Merge branch 'main' of https://github.com/nushell/engine-q into plugins

This commit is contained in:
Fernando Herrera
2021-10-28 07:12:40 +01:00
95 changed files with 2796 additions and 1607 deletions

View File

@ -27,6 +27,7 @@ terminal_size = "0.1.17"
lscolors = { version = "0.8.0", features = ["crossterm"] }
bytesize = "1.1.0"
dialoguer = "0.9.0"
rayon = "1.5.1"
[features]
trash-support = ["trash"]

View File

@ -1,9 +1,10 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, SyntaxShape, Value,
engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -25,11 +26,12 @@ impl Command for SubCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
into_binary(context, call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_binary(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
@ -84,28 +86,31 @@ impl Command for SubCommand {
}
fn into_binary(
_context: &EvaluationContext,
engine_state: &EngineState,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(head, move |v| {
action(v, head)
// FIXME: Add back in cell_path support
// if column_paths.is_empty() {
// action(v, head)
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret =
// ret.swap_data_by_cell_path(path, Box::new(move |old| action(old, old.tag())))?;
// }
input.map(
move |v| {
action(v, head)
// FIXME: Add back in cell_path support
// if column_paths.is_empty() {
// action(v, head)
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret =
// ret.swap_data_by_cell_path(path, Box::new(move |old| action(old, old.tag())))?;
// }
// Ok(ret)
// }
})
// Ok(ret)
// }
},
engine_state.ctrlc.clone(),
)
}
fn int_to_endian(n: i64) -> Vec<u8> {

View File

@ -1,10 +1,11 @@
use nu_engine::get_full_help;
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Signature, Value,
engine::{Command, EngineState, Stack},
IntoPipelineData, PipelineData, Signature, Value,
};
#[derive(Clone)]
pub struct Into;
impl Command for Into {
@ -22,14 +23,16 @@ impl Command for Into {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::String {
val: get_full_help(&Into.signature(), &[], context),
val: get_full_help(&Into.signature(), &[], engine_state),
span: call.head,
})
}
.into_pipeline_data())
}
}

View File

@ -1,9 +1,10 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, SyntaxShape, Value,
engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -25,11 +26,12 @@ impl Command for SubCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
into_filesize(context, call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_filesize(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
@ -112,31 +114,34 @@ impl Command for SubCommand {
}
fn into_filesize(
_context: &EvaluationContext,
engine_state: &EngineState,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
// let call_paths: Vec<ColumnPath> = args.rest(0)?;
input.map(head, move |v| {
action(v, head)
input.map(
move |v| {
action(v, head)
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret.swap_data_by_column_path(
// path,
// Box::new(move |old| action(old, old.tag())),
// )?;
// }
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret.swap_data_by_column_path(
// path,
// Box::new(move |old| action(old, old.tag())),
// )?;
// }
// Ok(ret)
// }
})
// Ok(ret)
// }
},
engine_state.ctrlc.clone(),
)
}
pub fn action(input: Value, span: Span) -> Value {

View File

@ -1,9 +1,10 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value,
engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -25,11 +26,12 @@ impl Command for SubCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
into_int(context, call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_int(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
@ -78,10 +80,8 @@ impl Command for SubCommand {
Example {
description: "Convert bool to integer",
example: "[$false, $true] | into int",
result: Some(Value::Stream {
stream: vec![Value::test_int(0), Value::test_int(1)]
.into_iter()
.into_value_stream(),
result: Some(Value::List {
vals: vec![Value::test_int(0), Value::test_int(1)],
span: Span::unknown(),
}),
},
@ -90,28 +90,31 @@ impl Command for SubCommand {
}
fn into_int(
_context: &EvaluationContext,
engine_state: &EngineState,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(head, move |v| {
action(v, head)
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret
// .swap_data_by_column_path(path, Box::new(move |old| action(old, old.tag())))?;
// }
input.map(
move |v| {
action(v, head)
// FIXME: Add back cell_path support
// if column_paths.is_empty() {
// action(&v, v.tag())
// } else {
// let mut ret = v;
// for path in &column_paths {
// ret = ret
// .swap_data_by_column_path(path, Box::new(move |old| action(old, old.tag())))?;
// }
// Ok(ret)
// }
})
// Ok(ret)
// }
},
engine_state.ctrlc.clone(),
)
}
pub fn action(input: Value, span: Span) -> Value {

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Alias;
impl Command for Alias {
@ -25,10 +26,11 @@ impl Command for Alias {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Def;
impl Command for Def {
@ -26,10 +27,11 @@ impl Command for Def {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Do;
impl Command for Do {
@ -27,19 +28,19 @@ impl Command for Do {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let rest: Vec<Value> = call.rest(context, 1)?;
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
let mut stack = stack.collect_captures(&block.captures);
let params: Vec<_> = block
.signature
@ -50,7 +51,7 @@ impl Command for Do {
for param in params.iter().zip(&rest) {
if let Some(var_id) = param.0.var_id {
state.add_var(var_id, param.1.clone())
stack.add_var(var_id, param.1.clone())
}
}
@ -68,7 +69,7 @@ impl Command for Do {
call.head
};
state.add_var(
stack.add_var(
param
.var_id
.expect("Internal error: rest positional parameter lacks var_id"),
@ -79,6 +80,6 @@ impl Command for Do {
)
}
}
eval_block(&state, block, input)
eval_block(engine_state, &mut stack, block, input)
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct ExportDef;
impl Command for ExportDef {
@ -26,10 +27,11 @@ impl Command for ExportDef {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,8 +1,11 @@
use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, Signature, Span, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct For;
impl Command for For {
@ -36,10 +39,11 @@ impl Command for For {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let var_id = call.positional[0]
.as_var()
.expect("internal error: missing variable");
@ -47,27 +51,48 @@ impl Command for For {
let keyword_expr = call.positional[1]
.as_keyword()
.expect("internal error: missing keyword");
let values = eval_expression(context, keyword_expr)?;
let values = eval_expression(engine_state, stack, keyword_expr)?;
let block = call.positional[2]
let block_id = call.positional[2]
.as_block()
.expect("internal error: expected block");
let context = context.clone();
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
values.map(call.head, move |x| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block);
match values {
Value::List { vals, .. } => Ok(vals
.into_iter()
.map(move |x| {
stack.add_var(var_id, x);
let state = context.enter_scope();
//let block = engine_state.get_block(block_id);
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Ok(pipeline_data) => pipeline_data.into_value(),
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(ctrlc)),
Value::Range { val, .. } => Ok(val
.into_range_iter()?
.map(move |x| {
stack.add_var(var_id, x);
state.add_var(var_id, x);
//let block = engine_state.get_block(block_id);
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Ok(pipeline_data) => pipeline_data.into_value(),
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(ctrlc)),
x => {
stack.add_var(var_id, x);
match eval_block(&state, block, Value::nothing()) {
Ok(value) => value,
Err(error) => Value::Error { error },
eval_block(&engine_state, &mut stack, &block, PipelineData::new())
}
})
}
}
fn examples(&self) -> Vec<Example> {

View File

@ -1,11 +1,13 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
span, Example, ShellError, Signature, Spanned, SyntaxShape, Value,
engine::{Command, EngineState, Stack},
span, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Spanned, SyntaxShape, Value,
};
use nu_engine::{get_full_help, CallExt};
#[derive(Clone)]
pub struct Help;
impl Command for Help {
@ -34,11 +36,12 @@ impl Command for Help {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<Value, ShellError> {
help(context, call)
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
help(engine_state, stack, call)
}
fn examples(&self) -> Vec<Example> {
@ -72,12 +75,16 @@ impl Command for Help {
}
}
fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
fn help(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let find: Option<Spanned<String>> = call.get_flag(context, "find")?;
let rest: Vec<Spanned<String>> = call.rest(context, 0)?;
let find: Option<Spanned<String>> = call.get_flag(engine_state, stack, "find")?;
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
let full_commands = context.get_signatures_with_examples();
let full_commands = engine_state.get_signatures_with_examples();
if let Some(f) = find {
let search_string = f.item;
@ -114,10 +121,9 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
}
}
return Ok(Value::List {
vals: found_cmds_vec,
span: head,
});
return Ok(found_cmds_vec
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()));
}
if !rest.is_empty() {
@ -151,10 +157,9 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
});
}
Ok(Value::List {
vals: found_cmds_vec,
span: head,
})
Ok(found_cmds_vec
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} else {
let mut name = String::new();
let mut output = String::new();
@ -168,7 +173,7 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
for cmd in full_commands {
if cmd.0.name == name {
let help = get_full_help(&cmd.0, &cmd.1, context);
let help = get_full_help(&cmd.0, &cmd.1, engine_state);
output.push_str(&help);
}
}
@ -177,7 +182,8 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
Ok(Value::String {
val: output,
span: call.head,
})
}
.into_pipeline_data())
} else {
Err(ShellError::CommandNotFound(span(&[
rest[0].span,
@ -355,7 +361,8 @@ You can also learn more at https://www.nushell.sh/book/"#;
Ok(Value::String {
val: msg.into(),
span: head,
})
}
.into_pipeline_data())
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Hide;
impl Command for Hide {
@ -19,10 +20,11 @@ impl Command for Hide {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct If;
impl Command for If {
@ -27,38 +28,40 @@ impl Command for If {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = &call.positional[0];
let then_block = call.positional[1]
.as_block()
.expect("internal error: expected block");
let else_case = call.positional.get(2);
let result = eval_expression(context, cond)?;
let result = eval_expression(engine_state, stack, cond)?;
match result {
Value::Bool { val, span } => {
let engine_state = context.engine_state.borrow();
Value::Bool { val, .. } => {
if val {
let block = engine_state.get_block(then_block);
let state = context.enter_scope();
eval_block(&state, block, input)
let mut stack = stack.collect_captures(&block.captures);
eval_block(engine_state, &mut stack, block, input)
} else if let Some(else_case) = else_case {
if let Some(else_expr) = else_case.as_keyword() {
if let Some(block_id) = else_expr.as_block() {
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
eval_block(&state, block, input)
let mut stack = stack.collect_captures(&block.captures);
eval_block(engine_state, &mut stack, block, input)
} else {
eval_expression(context, else_expr)
eval_expression(engine_state, stack, else_expr)
.map(|x| x.into_pipeline_data())
}
} else {
eval_expression(context, else_case)
eval_expression(engine_state, stack, else_case)
.map(|x| x.into_pipeline_data())
}
} else {
Ok(Value::Nothing { span })
Ok(PipelineData::new())
}
}
_ => Err(ShellError::CantConvert("bool".into(), result.span()?)),

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Let;
impl Command for Let {
@ -26,10 +27,11 @@ impl Command for Let {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let var_id = call.positional[0]
.as_var()
.expect("internal error: missing variable");
@ -38,13 +40,11 @@ impl Command for Let {
.as_keyword()
.expect("internal error: missing keyword");
let rhs = eval_expression(context, keyword_expr)?;
let rhs = eval_expression(engine_state, stack, keyword_expr)?;
//println!("Adding: {:?} to {}", rhs, var_id);
context.add_var(var_id, rhs);
Ok(Value::Nothing {
span: call.positional[0].span,
})
stack.add_var(var_id, rhs);
Ok(PipelineData::new())
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Module;
impl Command for Module {
@ -25,10 +26,11 @@ impl Command for Module {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,9 +1,10 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape};
/// Source a file for environment variables.
#[derive(Clone)]
pub struct Source;
impl Command for Source {
@ -25,19 +26,16 @@ impl Command for Source {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<Value, ShellError> {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
// Note: this hidden positional is the block_id that corresponded to the 0th position
// it is put here by the parser
let block_id: i64 = call.req(context, 1)?;
let block_id: i64 = call.req(engine_state, stack, 1)?;
let block = context
.engine_state
.borrow()
.get_block(block_id as usize)
.clone();
eval_block(context, &block, input)
let block = engine_state.get_block(block_id as usize).clone();
eval_block(engine_state, stack, &block, input)
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Use;
impl Command for Use {
@ -19,10 +20,11 @@ impl Command for Use {
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,5 +1,3 @@
use std::{cell::RefCell, rc::Rc};
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
Signature,
@ -7,11 +5,11 @@ use nu_protocol::{
use crate::*;
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
let engine_state = Rc::new(RefCell::new(EngineState::new()));
pub fn create_default_context() -> EngineState {
let mut engine_state = EngineState::new();
let delta = {
let engine_state = engine_state.borrow();
let mut working_set = StateWorkingSet::new(&*engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
macro_rules! bind_command {
( $command:expr ) => {
@ -46,14 +44,19 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
IntoBinary,
IntoFilesize,
IntoInt,
Last,
Length,
Let,
LetEnv,
Lines,
Ls,
Math,
MathAbs,
MathAvg,
Mkdir,
Module,
Mv,
ParEach,
Ps,
Rm,
RunPlugin,
@ -91,7 +94,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
};
{
EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta);
EngineState::merge_delta(&mut engine_state, delta);
}
engine_state

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct LetEnv;
impl Command for LetEnv {
@ -26,10 +27,11 @@ impl Command for LetEnv {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let env_var = call.positional[0]
.as_string()
.expect("internal error: missing variable");
@ -38,14 +40,12 @@ impl Command for LetEnv {
.as_keyword()
.expect("internal error: missing keyword");
let rhs = eval_expression(context, keyword_expr)?;
let rhs = eval_expression(engine_state, stack, keyword_expr)?;
let rhs = rhs.as_string()?;
//println!("Adding: {:?} to {}", rhs, var_id);
context.add_env_var(env_var, rhs);
Ok(Value::Nothing {
span: call.positional[0].span,
})
stack.add_env_var(env_var, rhs);
Ok(PipelineData::new())
}
}

View File

@ -1,26 +1,24 @@
use std::{cell::RefCell, rc::Rc};
use nu_engine::eval_block;
use nu_parser::parse;
use nu_protocol::{
engine::{Command, EngineState, EvaluationContext, StateWorkingSet},
Value,
engine::{Command, EngineState, Stack, StateWorkingSet},
PipelineData,
};
use super::{From, Into, Split};
use super::{From, Into, Math, Split};
pub fn test_examples(cmd: impl Command + 'static) {
let examples = cmd.examples();
let engine_state = Rc::new(RefCell::new(EngineState::new()));
let mut engine_state = Box::new(EngineState::new());
let delta = {
// Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible
let engine_state = engine_state.borrow();
let mut working_set = StateWorkingSet::new(&*engine_state);
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(Into));
working_set.add_decl(Box::new(Split));
working_set.add_decl(Box::new(Math));
// Adding the command that is being tested to the working set
working_set.add_decl(Box::new(cmd));
@ -28,7 +26,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
working_set.render()
};
EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta);
EngineState::merge_delta(&mut *engine_state, delta);
for example in examples {
// Skip tests that don't have results to compare to
@ -38,7 +36,6 @@ pub fn test_examples(cmd: impl Command + 'static) {
let start = std::time::Instant::now();
let (block, delta) = {
let engine_state = engine_state.borrow();
let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) = parse(&mut working_set, None, example.example.as_bytes(), false);
@ -49,16 +46,14 @@ pub fn test_examples(cmd: impl Command + 'static) {
(output, working_set.render())
};
EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta);
EngineState::merge_delta(&mut engine_state, delta);
let state = EvaluationContext {
engine_state: engine_state.clone(),
stack: nu_protocol::engine::Stack::new(),
};
let mut stack = Stack::new();
match eval_block(&state, &block, Value::nothing()) {
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
Ok(result) => {
let result = result.into_value();
println!("input: {}", example.example);
println!("result: {:?}", result);
println!("done: {:?}", start.elapsed());

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value};
#[derive(Clone)]
pub struct Git;
impl Command for Git {
@ -19,10 +20,11 @@ impl Command for Git {
fn run(
&self,
_context: &EvaluationContext,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
use std::process::Command as ProcessCommand;
use std::process::Stdio;
@ -37,17 +39,18 @@ impl Command for Git {
Ok(Value::String {
val: String::from_utf8_lossy(&result).to_string(),
span: call.head,
})
}
.into_pipeline_data())
}
Err(_err) => {
// FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing())
Ok(PipelineData::new())
}
}
}
Err(_err) => {
// FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing())
Ok(PipelineData::new())
}
}
}

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct GitCheckout;
impl Command for GitCheckout {
@ -24,16 +25,17 @@ impl Command for GitCheckout {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
use std::process::Command as ProcessCommand;
use std::process::Stdio;
let block = &call.positional[0];
let out = eval_expression(context, block)?;
let out = eval_expression(engine_state, stack, block)?;
let out = out.as_string()?;
@ -52,17 +54,18 @@ impl Command for GitCheckout {
Ok(Value::String {
val: String::from_utf8_lossy(&result).to_string(),
span: call.head,
})
}
.into_pipeline_data())
}
Err(_err) => {
// FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing())
Ok(PipelineData::new())
}
}
}
Err(_err) => {
// FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing())
Ok(PipelineData::new())
}
}
}

View File

@ -4,9 +4,14 @@ use std::process::Command as ProcessCommand;
use std::process::Stdio;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::engine::Command;
use nu_protocol::engine::EngineState;
use nu_protocol::engine::Stack;
use nu_protocol::IntoInterruptiblePipelineData;
use nu_protocol::PipelineData;
use nu_protocol::{Signature, Value};
#[derive(Clone)]
pub struct ListGitBranches;
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
@ -25,10 +30,11 @@ impl Command for ListGitBranches {
fn run(
&self,
_context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let list_branches = ProcessCommand::new("git")
.arg("branch")
.stdout(Stdio::piped())
@ -40,6 +46,7 @@ impl Command for ListGitBranches {
let s = String::from_utf8_lossy(&val).to_string();
#[allow(clippy::needless_collect)]
let lines: Vec<_> = s
.lines()
.filter_map(|x| {
@ -55,15 +62,14 @@ impl Command for ListGitBranches {
})
.collect();
Ok(Value::List {
vals: lines,
span: call.head,
})
Ok(lines
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
}

View File

@ -1,8 +1,9 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Cd;
impl Command for Cd {
@ -20,11 +21,12 @@ impl Command for Cd {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let path: Option<String> = call.opt(context, 0)?;
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let path: Option<String> = call.opt(engine_state, stack, 0)?;
let path = match path {
Some(path) => {
@ -40,7 +42,7 @@ impl Command for Cd {
//FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay
context.add_env_var("PWD".into(), path);
Ok(Value::Nothing { span: call.head })
stack.add_env_var("PWD".into(), path);
Ok(PipelineData::new())
}
}

View File

@ -1,15 +1,16 @@
use std::env::current_dir;
use std::path::PathBuf;
use super::interactive_helper::get_confirmation;
use super::util::get_interactive_confirmation;
use nu_engine::CallExt;
use nu_path::canonicalize_with;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape};
use crate::filesystem::util::FileStructure;
#[derive(Clone)]
pub struct Cp;
#[allow(unused_must_use)]
@ -37,12 +38,13 @@ impl Command for Cp {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<Value, ShellError> {
let source: String = call.req(context, 0)?;
let destination: String = call.req(context, 1)?;
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let source: String = call.req(engine_state, stack, 0)?;
let destination: String = call.req(engine_state, stack, 1)?;
let interactive = call.has_flag("interactive");
let force = call.has_flag("force");
@ -88,7 +90,7 @@ impl Command for Cp {
destination.file_name().unwrap().to_str().unwrap()
);
let input = get_confirmation(prompt)?;
let input = get_interactive_confirmation(prompt)?;
if !input {
remove.push(index);
@ -202,6 +204,6 @@ impl Command for Cp {
}
}
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}

View File

@ -1,26 +0,0 @@
use dialoguer::Input;
use std::error::Error;
pub fn get_confirmation(prompt: String) -> Result<bool, Box<dyn Error>> {
let input = Input::new()
.with_prompt(prompt)
.validate_with(|c_input: &String| -> Result<(), String> {
if c_input.len() == 1
&& (c_input == "y" || c_input == "Y" || c_input == "n" || c_input == "N")
{
Ok(())
} else if c_input.len() > 1 {
Err("Enter only one letter (Y/N)".to_string())
} else {
Err("Input not valid".to_string())
}
})
.default("Y/N".into())
.interact_text()?;
if input == "y" || input == "Y" {
Ok(true)
} else {
Ok(false)
}
}

View File

@ -1,9 +1,10 @@
use chrono::{DateTime, Utc};
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Ls;
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
@ -26,12 +27,13 @@ impl Command for Ls {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let pattern = if let Some(expr) = call.positional.get(0) {
let result = eval_expression(context, expr)?;
let result = eval_expression(engine_state, stack, expr)?;
let mut result = result.as_string()?;
let path = std::path::Path::new(&result);
@ -50,69 +52,66 @@ impl Command for Ls {
let call_span = call.head;
let glob = glob::glob(&pattern).unwrap();
Ok(Value::Stream {
stream: glob
.into_iter()
.map(move |x| match x {
Ok(path) => match std::fs::symlink_metadata(&path) {
Ok(metadata) => {
let is_file = metadata.is_file();
let is_dir = metadata.is_dir();
let filesize = metadata.len();
Ok(glob
.into_iter()
.map(move |x| match x {
Ok(path) => match std::fs::symlink_metadata(&path) {
Ok(metadata) => {
let is_file = metadata.is_file();
let is_dir = metadata.is_dir();
let filesize = metadata.len();
let mut cols = vec!["name".into(), "type".into(), "size".into()];
let mut cols = vec!["name".into(), "type".into(), "size".into()];
let mut vals = vec![
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
},
if is_file {
Value::string("File", call_span)
} else if is_dir {
Value::string("Dir", call_span)
} else {
Value::Nothing { span: call_span }
},
Value::Filesize {
val: filesize as i64,
span: call_span,
},
];
if let Ok(date) = metadata.modified() {
let utc: DateTime<Utc> = date.into();
cols.push("modified".into());
vals.push(Value::Date {
val: utc.into(),
span: call_span,
});
}
Value::Record {
cols,
vals,
let mut vals = vec![
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
}
},
if is_file {
Value::string("file", call_span)
} else if is_dir {
Value::string("dir", call_span)
} else {
Value::Nothing { span: call_span }
},
Value::Filesize {
val: filesize as i64,
span: call_span,
},
];
if let Ok(date) = metadata.modified() {
let utc: DateTime<Utc> = date.into();
cols.push("modified".into());
vals.push(Value::Date {
val: utc.into(),
span: call_span,
});
}
Err(_) => Value::Record {
cols: vec!["name".into(), "type".into(), "size".into()],
vals: vec![
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
},
Value::Nothing { span: call_span },
Value::Nothing { span: call_span },
],
Value::Record {
cols,
vals,
span: call_span,
},
}
}
Err(_) => Value::Record {
cols: vec!["name".into(), "type".into(), "size".into()],
vals: vec![
Value::String {
val: path.to_string_lossy().to_string(),
span: call_span,
},
Value::Nothing { span: call_span },
Value::Nothing { span: call_span },
],
span: call_span,
},
_ => Value::Nothing { span: call_span },
})
.into_value_stream(),
span: call_span,
})
},
_ => Value::Nothing { span: call_span },
})
.into_pipeline_data(engine_state.ctrlc.clone()))
}
}

View File

@ -3,9 +3,12 @@ use std::env::current_dir;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value, ValueStream};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Mkdir;
impl Command for Mkdir {
@ -29,13 +32,14 @@ impl Command for Mkdir {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<Value, ShellError> {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let path = current_dir()?;
let mut directories = call
.rest::<String>(context, 0)?
.rest::<String>(engine_state, stack, 0)?
.into_iter()
.map(|dir| path.join(dir))
.peekable();
@ -67,8 +71,8 @@ impl Command for Mkdir {
}
}
let stream = ValueStream::from_stream(stream.into_iter());
let span = call.head;
Ok(Value::Stream { stream, span })
Ok(stream
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
}
}

View File

@ -1,6 +1,5 @@
mod cd;
mod cp;
mod interactive_helper;
mod ls;
mod mkdir;
mod mv;

View File

@ -1,12 +1,13 @@
use std::env::current_dir;
use std::path::{Path, PathBuf};
use super::interactive_helper::get_confirmation;
use super::util::get_interactive_confirmation;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Mv;
#[allow(unused_must_use)]
@ -37,13 +38,14 @@ impl Command for Mv {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
// TODO: handle invalid directory or insufficient permissions when moving
let source: String = call.req(context, 0)?;
let destination: String = call.req(context, 1)?;
let source: String = call.req(engine_state, stack, 0)?;
let destination: String = call.req(engine_state, stack, 1)?;
let interactive = call.has_flag("interactive");
let force = call.has_flag("force");
@ -74,7 +76,7 @@ impl Command for Mv {
destination.file_name().unwrap().to_str().unwrap()
);
let input = get_confirmation(prompt)?;
let input = get_interactive_confirmation(prompt)?;
if !input {
remove.push(index);
@ -128,7 +130,7 @@ impl Command for Mv {
move_file(call, &entry, &destination)?
}
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}

View File

@ -3,13 +3,16 @@ use std::env::current_dir;
use std::os::unix::prelude::FileTypeExt;
use std::path::PathBuf;
use super::interactive_helper::get_confirmation;
use super::util::get_interactive_confirmation;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value, ValueStream};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Rm;
// Where self.0 is the unexpanded target's positional index (i.e. call.positional[self.0].span)
@ -56,15 +59,20 @@ impl Command for Rm {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<Value, ShellError> {
rm(context, call)
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
rm(engine_state, stack, call)
}
}
fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
fn rm(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<PipelineData, ShellError> {
let trash = call.has_flag("trash");
let permanent = call.has_flag("permanent");
let interactive = call.has_flag("interactive");
@ -95,7 +103,7 @@ fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
let current_path = current_dir()?;
let mut paths = call
.rest::<String>(context, 0)?
.rest::<String>(engine_state, stack, 0)?
.into_iter()
.map(|path| current_path.join(path))
.peekable();
@ -134,7 +142,7 @@ fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
file.1.file_name().unwrap().to_str().unwrap()
);
let input = get_confirmation(prompt)?;
let input = get_interactive_confirmation(prompt)?;
if !input {
remove.push(index);
@ -164,11 +172,9 @@ fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
// let temp = rm_helper(call, args).flatten();
// let temp = input.flatten(call.head, move |_| rm_helper(call, args));
Ok(Value::Stream {
stream: ValueStream::from_stream(response.into_iter()),
span: call.head,
})
Ok(response
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
// Ok(Value::Nothing { span })
}

View File

@ -2,9 +2,10 @@ use std::fs::OpenOptions;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Touch;
impl Command for Touch {
@ -28,12 +29,13 @@ impl Command for Touch {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<Value, ShellError> {
let target: String = call.req(context, 0)?;
let rest: Vec<String> = call.rest(context, 1)?;
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let target: String = call.req(engine_state, stack, 0)?;
let rest: Vec<String> = call.rest(engine_state, stack, 1)?;
for (index, item) in vec![target].into_iter().chain(rest).enumerate() {
match OpenOptions::new().write(true).create(true).open(&item) {
@ -47,6 +49,6 @@ impl Command for Touch {
}
}
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}

View File

@ -3,6 +3,9 @@ use std::path::{Path, PathBuf};
use nu_path::canonicalize_with;
use nu_protocol::ShellError;
use dialoguer::Input;
use std::error::Error;
#[derive(Default)]
pub struct FileStructure {
pub resources: Vec<Resource>,
@ -79,3 +82,27 @@ pub struct Resource {
}
impl Resource {}
pub fn get_interactive_confirmation(prompt: String) -> Result<bool, Box<dyn Error>> {
let input = Input::new()
.with_prompt(prompt)
.validate_with(|c_input: &String| -> Result<(), String> {
if c_input.len() == 1
&& (c_input == "y" || c_input == "Y" || c_input == "n" || c_input == "N")
{
Ok(())
} else if c_input.len() > 1 {
Err("Enter only one letter (Y/N)".to_string())
} else {
Err("Input not valid".to_string())
}
})
.default("Y/N".into())
.interact_text()?;
if input == "y" || input == "Y" {
Ok(true)
} else {
Ok(false)
}
}

View File

@ -1,8 +1,12 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, IntoValueStream, Signature, Span, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Span,
SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Each;
impl Command for Each {
@ -43,8 +47,8 @@ impl Command for Each {
vec![Example {
example: "[1 2 3] | each { 2 * $it }",
description: "Multiplies elements in list",
result: Some(Value::Stream {
stream: stream_test_1.into_iter().into_value_stream(),
result: Some(Value::List {
vals: stream_test_1,
span: Span::unknown(),
}),
}]
@ -52,151 +56,133 @@ impl Command for Each {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let numbered = call.has_flag("numbered");
let context = context.clone();
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let span = call.head;
match input {
Value::Range { val, .. } => Ok(Value::Stream {
stream: val
.into_range_iter()?
.enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
PipelineData::Value(Value::Range { val, .. }) => Ok(val
.into_range_iter()?
.enumerate()
.map(move |(idx, x)| {
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&state, block, Value::nothing()) {
Ok(v) => v,
Err(error) => Value::Error { error },
}
})
.into_value_stream(),
span: call.head,
}),
Value::List { vals: val, .. } => Ok(Value::Stream {
stream: val
.into_iter()
.enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Ok(v) => v.into_value(),
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
.into_iter()
.enumerate()
.map(move |(idx, x)| {
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&state, block, Value::nothing()) {
Ok(v) => v,
Err(error) => Value::Error { error },
}
})
.into_value_stream(),
span: call.head,
}),
Value::Stream { stream, .. } => Ok(Value::Stream {
stream: stream
.enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Ok(v) => v.into_value(),
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream
.enumerate()
.map(move |(idx, x)| {
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&state, block, Value::nothing()) {
Ok(v) => v,
Err(error) => Value::Error { error },
}
})
.into_value_stream(),
span: call.head,
}),
Value::Record { cols, vals, .. } => {
match eval_block(&engine_state, &mut stack, &block, PipelineData::new()) {
Ok(v) => v.into_value(),
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output_cols = vec![];
let mut output_vals = vec![];
for (col, val) in cols.into_iter().zip(vals.into_iter()) {
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
state.add_var(
stack.add_var(
*var_id,
Value::Record {
cols: vec!["column".into(), "value".into()],
@ -213,17 +199,17 @@ impl Command for Each {
}
}
match eval_block(&state, block, Value::nothing())? {
Value::Record {
match eval_block(&engine_state, &mut stack, block, PipelineData::new())? {
PipelineData::Value(Value::Record {
mut cols, mut vals, ..
} => {
}) => {
// TODO check that the lengths match when traversing record
output_cols.append(&mut cols);
output_vals.append(&mut vals);
}
x => {
output_cols.push(col);
output_vals.push(x);
output_vals.push(x.into_value());
}
}
}
@ -232,20 +218,19 @@ impl Command for Each {
cols: output_cols,
vals: output_vals,
span: call.head,
})
}
.into_pipeline_data())
}
x => {
let engine_state = context.engine_state.borrow();
PipelineData::Value(x) => {
let block = engine_state.get_block(block_id);
let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x);
stack.add_var(*var_id, x);
}
}
eval_block(&state, block, Value::nothing())
eval_block(&engine_state, &mut stack, block, PipelineData::new())
}
}
}

View File

@ -1,8 +1,9 @@
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Get;
impl Command for Get {
@ -24,12 +25,15 @@ impl Command for Get {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let cell_path: CellPath = call.req(context, 0)?;
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
input.follow_cell_path(&cell_path.members)
input
.follow_cell_path(&cell_path.members)
.map(|x| x.into_pipeline_data())
}
}

View File

@ -0,0 +1,86 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use std::convert::TryInto;
#[derive(Clone)]
pub struct Last;
impl Command for Last {
fn name(&self) -> &str {
"last"
}
fn signature(&self) -> Signature {
Signature::build("last").optional(
"rows",
SyntaxShape::Int,
"starting from the back, the number of rows to return",
)
}
fn usage(&self) -> &str {
"Show only the last number of rows."
}
fn examples(&self) -> Vec<Example> {
vec![Example {
example: "[1,2,3] | last 2",
description: "Get the last 2 items",
result: Some(Value::List {
vals: vec![Value::test_int(2), Value::test_int(3)],
span: Span::unknown(),
}),
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let rows: Option<i64> = call.opt(engine_state, stack, 0)?;
let v: Vec<_> = input.into_iter().collect();
let vlen: i64 = v.len() as i64;
let beginning_rows_to_skip = rows_to_skip(vlen, rows);
let iter = v
.into_iter()
.skip(beginning_rows_to_skip.try_into().unwrap());
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
}
fn rows_to_skip(count: i64, rows: Option<i64>) -> i64 {
let end_rows_desired = if let Some(quantity) = rows {
quantity
} else {
1
};
if end_rows_desired < count {
count - end_rows_desired
} else {
0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Last {})
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value};
#[derive(Clone)]
pub struct Length;
impl Command for Length {
@ -19,35 +20,22 @@ impl Command for Length {
fn run(
&self,
_context: &EvaluationContext,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
match input {
Value::List { vals: val, .. } => {
let length = val.len();
Ok(Value::Int {
val: length as i64,
span: call.head,
})
}
Value::Stream { stream, .. } => {
let length = stream.count();
Ok(Value::Int {
val: length as i64,
span: call.head,
})
}
Value::Nothing { .. } => Ok(Value::Int {
PipelineData::Value(Value::Nothing { .. }) => Ok(Value::Int {
val: 0,
span: call.head,
}),
}
.into_pipeline_data()),
_ => Ok(Value::Int {
val: 1,
val: input.into_iter().count() as i64,
span: call.head,
}),
}
.into_pipeline_data()),
}
}
}

View File

@ -1,10 +1,8 @@
use std::cell::RefCell;
use std::rc::Rc;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, Value, ValueStream};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value};
#[derive(Clone)]
pub struct Lines;
const SPLIT_CHAR: char = '\n';
@ -24,17 +22,17 @@ impl Command for Lines {
fn run(
&self,
_context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let span = call.head;
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
match input {
#[allow(clippy::needless_collect)]
// Collect is needed because the string may not live long enough for
// the Rc structure to continue using it. If split could take ownership
// of the split values, then this wouldn't be needed
Value::String { val, span } => {
PipelineData::Value(Value::String { val, span }) => {
let lines = val
.split(SPLIT_CHAR)
.map(|s| s.to_string())
@ -48,12 +46,9 @@ impl Command for Lines {
}
});
Ok(Value::Stream {
stream: ValueStream(Rc::new(RefCell::new(iter))),
span,
})
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
Value::Stream { stream, span: _ } => {
PipelineData::Stream(stream) => {
let iter = stream
.into_iter()
.filter_map(|value| {
@ -79,12 +74,9 @@ impl Command for Lines {
})
.flatten();
Ok(Value::Stream {
stream: ValueStream(Rc::new(RefCell::new(iter))),
span,
})
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
val => Err(ShellError::UnsupportedInput(
PipelineData::Value(val) => Err(ShellError::UnsupportedInput(
format!("Not supported input: {}", val.as_string()?),
call.head,
)),

View File

@ -1,15 +1,19 @@
mod each;
mod get;
mod last;
mod length;
mod lines;
mod par_each;
mod select;
mod where_;
mod wrap;
pub use each::Each;
pub use get::Get;
pub use last::Last;
pub use length::Length;
pub use lines::Lines;
pub use par_each::ParEach;
pub use select::Select;
pub use where_::Where;
pub use wrap::Wrap;

View File

@ -0,0 +1,256 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, SyntaxShape,
Value,
};
use rayon::prelude::*;
#[derive(Clone)]
pub struct ParEach;
impl Command for ParEach {
fn name(&self) -> &str {
"par-each"
}
fn usage(&self) -> &str {
"Run a block on each element of input in parallel"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("par-each")
.required(
"block",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])),
"the block to run",
)
.switch("numbered", "iterate with an index", Some('n'))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
example: "[1 2 3] | par-each { 2 * $it }",
description: "Multiplies elements in list",
result: None,
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let numbered = call.has_flag("numbered");
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures);
let span = call.head;
match input {
PipelineData::Value(Value::Range { val, .. }) => Ok(val
.into_range_iter()?
.enumerate()
.par_bridge()
.map(move |(idx, x)| {
let block = engine_state.get_block(block_id);
let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new()) {
Ok(v) => v,
Err(error) => Value::Error { error }.into_pipeline_data(),
}
})
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals: val, .. }) => Ok(val
.into_iter()
.enumerate()
.par_bridge()
.map(move |(idx, x)| {
let block = engine_state.get_block(block_id);
let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new()) {
Ok(v) => v,
Err(error) => Value::Error { error }.into_pipeline_data(),
}
})
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Stream(stream) => Ok(stream
.enumerate()
.par_bridge()
.map(move |(idx, x)| {
let block = engine_state.get_block(block_id);
let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
if numbered {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
stack.add_var(*var_id, x);
}
}
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new()) {
Ok(v) => v,
Err(error) => Value::Error { error }.into_pipeline_data(),
}
})
.collect::<Vec<_>>()
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output_cols = vec![];
let mut output_vals = vec![];
for (col, val) in cols.into_iter().zip(vals.into_iter()) {
let block = engine_state.get_block(block_id);
let mut stack = stack.clone();
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(
*var_id,
Value::Record {
cols: vec!["column".into(), "value".into()],
vals: vec![
Value::String {
val: col.clone(),
span: call.head,
},
val,
],
span: call.head,
},
);
}
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new())? {
PipelineData::Value(Value::Record {
mut cols, mut vals, ..
}) => {
// TODO check that the lengths match when traversing record
output_cols.append(&mut cols);
output_vals.append(&mut vals);
}
x => {
output_cols.push(col);
output_vals.push(x.into_value());
}
}
}
Ok(Value::Record {
cols: output_cols,
vals: output_vals,
span: call.head,
}
.into_pipeline_data())
}
PipelineData::Value(x) => {
let block = engine_state.get_block(block_id);
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, x);
}
}
eval_block(&engine_state, &mut stack, block, PipelineData::new())
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(ParEach {})
}
}

View File

@ -1,8 +1,12 @@
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Select;
impl Command for Select {
@ -24,14 +28,15 @@ impl Command for Select {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let columns: Vec<CellPath> = call.rest(context, 0)?;
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let columns: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let span = call.head;
select(span, columns, input)
select(engine_state, span, columns, input)
}
fn examples(&self) -> Vec<Example> {
@ -50,16 +55,21 @@ impl Command for Select {
}
}
fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, ShellError> {
fn select(
engine_state: &EngineState,
span: Span,
columns: Vec<CellPath>,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
if columns.is_empty() {
return Err(ShellError::CantFindColumn(span, input.span()?));
return Err(ShellError::CantFindColumn(span, span)); //FIXME?
}
match input {
Value::List {
PipelineData::Value(Value::List {
vals: input_vals,
span,
} => {
}) => {
let mut output = vec![];
for input_val in input_vals {
@ -76,33 +86,32 @@ fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, She
output.push(Value::Record { cols, vals, span })
}
Ok(Value::List { vals: output, span })
Ok(output
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
}
Value::Stream { stream, span } => Ok(Value::Stream {
stream: stream
.map(move |x| {
let mut cols = vec![];
let mut vals = vec![];
for path in &columns {
//FIXME: improve implementation to not clone
match x.clone().follow_cell_path(&path.members) {
Ok(value) => {
cols.push(path.into_string());
vals.push(value);
}
Err(error) => {
cols.push(path.into_string());
vals.push(Value::Error { error });
}
PipelineData::Stream(stream) => Ok(stream
.map(move |x| {
let mut cols = vec![];
let mut vals = vec![];
for path in &columns {
//FIXME: improve implementation to not clone
match x.clone().follow_cell_path(&path.members) {
Ok(value) => {
cols.push(path.into_string());
vals.push(value);
}
Err(error) => {
cols.push(path.into_string());
vals.push(Value::Error { error });
}
}
}
Value::Record { cols, vals, span }
})
.into_value_stream(),
span,
}),
v => {
Value::Record { cols, vals, span }
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(v) => {
let mut cols = vec![];
let mut vals = vec![];
@ -114,7 +123,7 @@ fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, She
vals.push(result);
}
Ok(Value::Record { cols, vals, span })
Ok(Value::Record { cols, vals, span }.into_pipeline_data())
}
}
}

View File

@ -1,8 +1,12 @@
use nu_engine::eval_expression;
use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, ShellError, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Where;
impl Command for Where {
@ -20,13 +24,18 @@ impl Command for Where {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = call.positional[0].clone();
let context = context.enter_scope();
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
// FIXME: very expensive
let mut stack = stack.clone();
let (var_id, cond) = match cond {
Expression {
@ -37,54 +46,40 @@ impl Command for Where {
};
match input {
Value::Stream { stream, span } => {
let output_stream = stream
.filter(move |value| {
context.add_var(var_id, value.clone());
PipelineData::Stream(stream) => Ok(stream
.filter(move |value| {
stack.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond);
let result = eval_expression(&engine_state, &mut stack, &cond);
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
}
Value::List { vals, span } => {
let output_stream = vals
.into_iter()
.filter(move |value| {
context.add_var(var_id, value.clone());
.into_pipeline_data(ctrlc)),
PipelineData::Value(Value::List { vals, .. }) => Ok(vals
.into_iter()
.filter(move |value| {
stack.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond);
let result = eval_expression(&engine_state, &mut stack, &cond);
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
match result {
Ok(result) => result.is_true(),
_ => false,
}
})
}
x => {
context.add_var(var_id, x.clone());
.into_pipeline_data(ctrlc)),
PipelineData::Value(x) => {
stack.add_var(var_id, x.clone());
let result = eval_expression(&context, &cond)?;
let result = eval_expression(&engine_state, &mut stack, &cond)?;
if result.is_true() {
Ok(x)
Ok(x.into_pipeline_data())
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
}

View File

@ -1,8 +1,11 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct Wrap;
impl Command for Wrap {
@ -20,40 +23,36 @@ impl Command for Wrap {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head;
let name: String = call.req(context, 0)?;
let name: String = call.req(engine_state, stack, 0)?;
match input {
Value::List { vals, .. } => Ok(Value::List {
vals: vals
.into_iter()
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.collect(),
span,
}),
Value::Stream { stream, .. } => Ok(Value::Stream {
stream: stream
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_value_stream(),
span,
}),
_ => Ok(Value::Record {
PipelineData::Value(Value::List { vals, .. }) => Ok(vals
.into_iter()
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Stream(stream) => Ok(stream
.map(move |x| Value::Record {
cols: vec![name.clone()],
vals: vec![x],
span,
})
.into_pipeline_data(engine_state.ctrlc.clone())),
PipelineData::Value(input) => Ok(Value::Record {
cols: vec![name],
vals: vec![input],
span,
}),
}
.into_pipeline_data()),
}
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Signature};
#[derive(Clone)]
pub struct From;
impl Command for From {
@ -19,10 +20,11 @@ impl Command for From {
fn run(
&self,
_context: &EvaluationContext,
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, ShellError> {
Ok(Value::nothing())
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
Ok(PipelineData::new())
}
}

View File

@ -1,7 +1,11 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, IntoValueStream, ShellError, Signature, Span, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature,
Span, Value,
};
#[derive(Clone)]
pub struct FromJson;
impl Command for FromJson {
@ -67,11 +71,12 @@ impl Command for FromJson {
fn run(
&self,
_context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, ShellError> {
let span = input.span()?;
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
let span = call.head;
let mut string_input = input.collect_string();
string_input.push('\n');
@ -79,21 +84,18 @@ impl Command for FromJson {
if call.has_flag("objects") {
#[allow(clippy::needless_collect)]
let lines: Vec<String> = string_input.lines().map(|x| x.to_string()).collect();
Ok(Value::Stream {
stream: lines
.into_iter()
.map(move |mut x| {
x.push('\n');
match convert_string_to_value(x, span) {
Ok(v) => v,
Err(error) => Value::Error { error },
}
})
.into_value_stream(),
span,
})
Ok(lines
.into_iter()
.map(move |mut x| {
x.push('\n');
match convert_string_to_value(x, span) {
Ok(v) => v,
Err(error) => Value::Error { error },
}
})
.into_pipeline_data(engine_state.ctrlc.clone()))
} else {
convert_string_to_value(string_input, span)
Ok(convert_string_to_value(string_input, span)?.into_pipeline_data())
}
}
}

View File

@ -7,6 +7,7 @@ mod experimental;
mod filesystem;
mod filters;
mod formats;
mod math;
mod strings;
mod system;
mod viewers;
@ -20,6 +21,7 @@ pub use experimental::*;
pub use filesystem::*;
pub use filters::*;
pub use formats::*;
pub use math::*;
pub use strings::*;
pub use system::*;
pub use viewers::*;

View File

@ -0,0 +1,84 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"math abs"
}
fn signature(&self) -> Signature {
Signature::build("math abs")
}
fn usage(&self) -> &str {
"Returns absolute values of a list of numbers"
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
input.map(
move |value| abs_helper(value, head),
engine_state.ctrlc.clone(),
)
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Get absolute of each value in a list of numbers",
example: "[-50 -100.0 25] | math abs",
result: Some(Value::List {
vals: vec![
Value::test_int(50),
Value::Float {
val: 100.0,
span: Span::unknown(),
},
Value::test_int(25),
],
span: Span::unknown(),
}),
}]
}
}
fn abs_helper(val: Value, head: Span) -> Value {
match val {
Value::Int { val, span } => Value::int(val.abs(), span),
Value::Float { val, span } => Value::Float {
val: val.abs(),
span,
},
Value::Duration { val, span } => Value::Duration {
val: val.abs(),
span,
},
_ => Value::Error {
error: ShellError::UnsupportedInput(
String::from("Only numerical values are supported"),
head,
),
},
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(SubCommand {})
}
}

View File

@ -0,0 +1,83 @@
use crate::math::reducers::{reducer_for, Reduce};
use crate::math::utils::run_with_function;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Value};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"math avg"
}
fn signature(&self) -> Signature {
Signature::build("math avg")
}
fn usage(&self) -> &str {
"Finds the average of a list of numbers or tables"
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_with_function(call, input, average)
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Get the average of a list of numbers",
example: "[-50 100.0 25] | math avg",
result: Some(Value::Float {
val: 25.0,
span: Span::unknown(),
}),
}]
}
}
pub fn average(values: &[Value], head: &Span) -> Result<Value, ShellError> {
let sum = reducer_for(Reduce::Summation);
let total = &sum(
Value::Int {
val: 0,
span: Span::unknown(),
},
values.to_vec(),
)?;
match total {
Value::Filesize { val, span } => Ok(Value::Filesize {
val: val / values.len() as i64,
span: *span,
}),
Value::Duration { val, span } => Ok(Value::Duration {
val: val / values.len() as i64,
span: *span,
}),
_ => total.div(
*head,
&Value::Int {
val: values.len() as i64,
span: *head,
},
),
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(SubCommand {})
}
}

View File

@ -0,0 +1,41 @@
use nu_engine::get_full_help;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
IntoPipelineData, PipelineData, Signature, Value,
};
#[derive(Clone)]
pub struct MathCommand;
impl Command for MathCommand {
fn name(&self) -> &str {
"math"
}
fn signature(&self) -> Signature {
Signature::build("math")
}
fn usage(&self) -> &str {
"Use mathematical functions as aggregate functions on a list of numbers or tables."
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::String {
val: get_full_help(
&MathCommand.signature(),
&MathCommand.examples(),
engine_state,
),
span: call.head,
}
.into_pipeline_data())
}
}

View File

@ -0,0 +1,9 @@
mod abs;
mod avg;
pub mod command;
mod reducers;
mod utils;
pub use abs::SubCommand as MathAbs;
pub use avg::SubCommand as MathAvg;
pub use command::MathCommand as Math;

View File

@ -0,0 +1,60 @@
use nu_protocol::{ShellError, Span, Value};
#[allow(dead_code)]
pub enum Reduce {
Summation,
}
pub fn reducer_for(
command: Reduce,
) -> Box<dyn Fn(Value, Vec<Value>) -> Result<Value, ShellError> + Send + Sync + 'static> {
match command {
Reduce::Summation => Box::new(|_, values| sum(values)),
}
}
pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
let initial_value = data.get(0);
let mut acc = match initial_value {
Some(Value::Filesize { span, .. }) => Ok(Value::Filesize {
val: 0,
span: *span,
}),
Some(Value::Duration { span, .. }) => Ok(Value::Duration {
val: 0,
span: *span,
}),
Some(Value::Int { span, .. }) | Some(Value::Float { span, .. }) => Ok(Value::Int {
val: 0,
span: *span,
}),
None => Err(ShellError::UnsupportedInput(
"Empty input".to_string(),
Span::unknown(),
)),
_ => Ok(Value::nothing()),
}?;
for value in &data {
match value {
Value::Int { .. }
| Value::Float { .. }
| Value::Filesize { .. }
| Value::Duration { .. } => {
let new_value = acc.add(acc.span().unwrap_or_else(|_| Span::unknown()), value);
if new_value.is_err() {
return new_value;
}
acc = new_value.expect("This should never trigger")
}
other => {
return Err(ShellError::UnsupportedInput(
"Attempted to compute the sum of a value that cannot be summed".to_string(),
other.span().unwrap_or_else(|_| Span::unknown()),
));
}
}
}
Ok(acc)
}

View File

@ -0,0 +1,87 @@
use nu_protocol::ast::Call;
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Span, Value};
use std::collections::HashMap;
pub type MathFunction = fn(values: &[Value], span: &Span) -> Result<Value, ShellError>;
pub fn run_with_function(
call: &Call,
input: PipelineData,
mf: MathFunction,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let name = call.head;
let res = calculate(input, name, mf);
match res {
Ok(v) => Ok(v.into_pipeline_data()),
Err(e) => Err(e),
}
}
fn helper_for_tables(
values: PipelineData,
name: Span,
mf: MathFunction,
) -> Result<Value, ShellError> {
// If we are not dealing with Primitives, then perhaps we are dealing with a table
// Create a key for each column name
let mut column_values = HashMap::new();
for val in values {
if let Value::Record { cols, vals, .. } = val {
for (key, value) in cols.iter().zip(vals.iter()) {
column_values
.entry(key.clone())
.and_modify(|v: &mut Vec<Value>| v.push(value.clone()))
.or_insert_with(|| vec![value.clone()]);
}
}
}
// The mathematical function operates over the columns of the table
let mut column_totals = HashMap::new();
for (col_name, col_vals) in column_values {
if let Ok(out) = mf(&col_vals, &name) {
column_totals.insert(col_name, out);
}
}
if column_totals.keys().len() == 0 {
return Err(ShellError::UnsupportedInput(
"Unable to give a result with this input".to_string(),
name,
));
}
let (cols, vals) = column_totals
.into_iter()
.fold((vec![], vec![]), |mut acc, (k, v)| {
acc.0.push(k);
acc.1.push(v);
acc
});
Ok(Value::Record {
cols,
vals,
span: name,
})
}
pub fn calculate(values: PipelineData, name: Span, mf: MathFunction) -> Result<Value, ShellError> {
match values {
PipelineData::Stream(_) => helper_for_tables(values, name, mf),
PipelineData::Value(Value::List { ref vals, .. }) => match &vals[..] {
[Value::Record { .. }, _end @ ..] => helper_for_tables(values, name, mf),
_ => mf(vals, &name),
},
PipelineData::Value(Value::Record { vals, cols, span }) => {
let new_vals: Result<Vec<Value>, ShellError> =
vals.into_iter().map(|val| mf(&[val], &name)).collect();
match new_vals {
Ok(vec) => Ok(Value::Record {
cols,
vals: vec,
span,
}),
Err(err) => Err(err),
}
}
PipelineData::Value(val) => mf(&[val], &name),
}
}

View File

@ -1,8 +1,11 @@
use nu_engine::eval_expression;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
#[derive(Clone)]
pub struct BuildString;
impl Command for BuildString {
@ -41,20 +44,22 @@ impl Command for BuildString {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let output = call
.positional
.iter()
.map(|expr| eval_expression(context, expr).map(|val| val.into_string()))
.map(|expr| eval_expression(engine_state, stack, expr).map(|val| val.into_string()))
.collect::<Result<Vec<String>, ShellError>>()?;
Ok(Value::String {
val: output.join(""),
span: call.head,
})
}
.into_pipeline_data())
}
}

View File

@ -3,9 +3,10 @@ extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Example, ShellError, Signature, Span, Type, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, Type, Value};
#[derive(Clone)]
pub struct Size;
impl Command for Size {
@ -23,11 +24,12 @@ impl Command for Size {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<Value, ShellError> {
size(context, call, input)
input: PipelineData,
) -> Result<PipelineData, ShellError> {
size(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
@ -98,18 +100,25 @@ impl Command for Size {
}
}
fn size(_context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> {
fn size(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
input.map(span, move |v| match v.as_string() {
Ok(s) => count(&s, span),
Err(_) => Value::Error {
error: ShellError::PipelineMismatch {
expected: Type::String,
expected_span: span,
origin: span,
input.map(
move |v| match v.as_string() {
Ok(s) => count(&s, span),
Err(_) => Value::Error {
error: ShellError::PipelineMismatch {
expected: Type::String,
expected_span: span,
origin: span,
},
},
},
})
engine_state.ctrlc.clone(),
)
}
fn count(contents: &str, span: Span) -> Value {

View File

@ -1,9 +1,10 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, Type, Value,
engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -38,18 +39,26 @@ impl Command for SubCommand {
fn run(
&self,
_context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
split_chars(call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_chars(engine_state, call, input)
}
}
fn split_chars(call: &Call, input: Value) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
fn split_chars(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head;
Ok(input.flat_map(span, move |x| split_chars_helper(&x, span)))
input.flat_map(
move |x| split_chars_helper(&x, span),
engine_state.ctrlc.clone(),
)
}
fn split_chars_helper(v: &Value, name: Span) -> Vec<Value> {

View File

@ -1,10 +1,11 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
engine::{Command, EngineState, Stack},
PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -33,27 +34,30 @@ impl Command for SubCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
split_column(context, call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_column(engine_state, stack, call, input)
}
}
fn split_column(
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let name_span = call.head;
let separator: Spanned<String> = call.req(context, 0)?;
let rest: Vec<Spanned<String>> = call.rest(context, 1)?;
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?;
let collapse_empty = call.has_flag("collapse-empty");
input.map(name_span, move |x| {
split_column_helper(&x, &separator, &rest, collapse_empty, name_span)
})
input.flat_map(
move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span),
engine_state.ctrlc.clone(),
)
}
fn split_column_helper(
@ -62,7 +66,7 @@ fn split_column_helper(
rest: &[Spanned<String>],
collapse_empty: bool,
head: Span,
) -> Value {
) -> Vec<Value> {
if let Ok(s) = v.as_string() {
let splitter = separator.item.replace("\\n", "\n");
@ -94,24 +98,21 @@ fn split_column_helper(
vals.push(Value::string(k, head));
}
}
Value::List {
vals: vec![Value::Record {
cols,
vals,
span: head,
}],
vec![Value::Record {
cols,
vals,
span: head,
}
}]
} else {
match v.span() {
Ok(span) => Value::Error {
Ok(span) => vec![Value::Error {
error: ShellError::PipelineMismatch {
expected: Type::String,
expected_span: head,
origin: span,
},
},
Err(error) => Value::Error { error },
}],
Err(error) => vec![Value::Error { error }],
}
}
}

View File

@ -1,8 +1,8 @@
use nu_engine::get_full_help;
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Signature, Value,
engine::{Command, EngineState, Stack},
IntoPipelineData, PipelineData, Signature, Value,
};
#[derive(Clone)]
@ -23,14 +23,20 @@ impl Command for SplitCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::String {
val: get_full_help(&SplitCommand.signature(), &SplitCommand.examples(), context),
val: get_full_help(
&SplitCommand.signature(),
&SplitCommand.examples(),
engine_state,
),
span: call.head,
})
}
.into_pipeline_data())
}
}

View File

@ -1,10 +1,11 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
engine::{Command, EngineState, Stack},
PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
@ -26,25 +27,28 @@ impl Command for SubCommand {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
split_row(context, call, input)
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_row(engine_state, stack, call, input)
}
}
fn split_row(
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let name_span = call.head;
let separator: Spanned<String> = call.req(context, 0)?;
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
Ok(input.flat_map(name_span, move |x| {
split_row_helper(&x, &separator, name_span)
}))
input.flat_map(
move |x| split_row_helper(&x, &separator, name_span),
engine_state.ctrlc.clone(),
)
}
fn split_row_helper(v: &Value, separator: &Spanned<String>, name: Span) -> Vec<Value> {

View File

@ -2,9 +2,10 @@ use std::time::Instant;
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Benchmark;
impl Command for Benchmark {
@ -26,23 +27,22 @@ impl Command for Benchmark {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block = call.positional[0]
.as_block()
.expect("internal error: expected block");
let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block);
let state = context.enter_scope();
let mut stack = stack.collect_captures(&block.captures);
let start_time = Instant::now();
eval_block(&state, block, Value::nothing())?;
eval_block(engine_state, &mut stack, block, PipelineData::new())?.into_value();
let end_time = Instant::now();
println!("{} ms", (end_time - start_time).as_millis());
Ok(Value::Nothing {
span: call.positional[0].span,
})
Ok(PipelineData::new())
}
}

View File

@ -1,10 +1,11 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, ShellError, Signature, Value,
engine::{Command, EngineState, Stack},
Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value,
};
use sysinfo::{ProcessExt, System, SystemExt};
#[derive(Clone)]
pub struct Ps;
impl Command for Ps {
@ -29,11 +30,12 @@ impl Command for Ps {
fn run(
&self,
_context: &EvaluationContext,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
run_ps(call)
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_ps(engine_state, call)
}
fn examples(&self) -> Vec<Example> {
@ -45,7 +47,7 @@ impl Command for Ps {
}
}
fn run_ps(call: &Call) -> Result<Value, ShellError> {
fn run_ps(engine_state: &EngineState, call: &Call) -> Result<PipelineData, ShellError> {
let span = call.head;
let long = call.has_flag("long");
let mut sys = System::new_all();
@ -124,5 +126,7 @@ fn run_ps(call: &Call) -> Result<Value, ShellError> {
}
}
Ok(Value::List { vals: output, span })
Ok(output
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
}

View File

@ -1,22 +1,19 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::io::{BufRead, BufReader, Write};
use std::process::{ChildStdin, Command as CommandSys, Stdio};
use std::rc::Rc;
use std::process::{Command as CommandSys, Stdio};
use std::sync::mpsc;
use nu_protocol::{
ast::{Call, Expression},
engine::{Command, EvaluationContext},
ShellError, Signature, SyntaxShape, Value,
};
use nu_protocol::{Span, ValueStream};
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{ast::Call, engine::Command, ShellError, Signature, SyntaxShape, Value};
use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, Span, Spanned};
use nu_engine::eval_expression;
use nu_engine::CallExt;
const OUTPUT_BUFFER_SIZE: usize = 8192;
#[derive(Clone)]
pub struct External;
impl Command for External {
@ -36,62 +33,49 @@ impl Command for External {
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<Value, ShellError> {
let command = ExternalCommand::try_new(call, context)?;
command.run_with_input(input)
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
let args: Vec<String> = call.rest(engine_state, stack, 1)?;
let last_expression = call.has_flag("last_expression");
let env_vars = stack.get_env_vars();
let command = ExternalCommand {
name,
args,
last_expression,
env_vars,
};
command.run_with_input(engine_state, input)
}
}
pub struct ExternalCommand<'call, 'contex> {
pub name: &'call Expression,
pub args: &'call [Expression],
pub context: &'contex EvaluationContext,
pub struct ExternalCommand {
pub name: Spanned<String>,
pub args: Vec<String>,
pub last_expression: bool,
pub env_vars: HashMap<String, String>,
}
impl<'call, 'contex> ExternalCommand<'call, 'contex> {
pub fn try_new(
call: &'call Call,
context: &'contex EvaluationContext,
) -> Result<Self, ShellError> {
if call.positional.is_empty() {
return Err(ShellError::ExternalNotSupported(call.head));
}
Ok(Self {
name: &call.positional[0],
args: &call.positional[1..],
context,
last_expression: call.has_flag("last_expression"),
})
}
pub fn get_name(&self) -> Result<String, ShellError> {
let value = eval_expression(self.context, self.name)?;
value.as_string()
}
pub fn get_args(&self) -> Vec<String> {
self.args
.iter()
.filter_map(|expr| eval_expression(self.context, expr).ok())
.filter_map(|value| value.as_string().ok())
.collect()
}
pub fn run_with_input(&self, input: Value) -> Result<Value, ShellError> {
impl ExternalCommand {
pub fn run_with_input(
&self,
engine_state: &EngineState,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut process = self.create_command();
let ctrlc = engine_state.ctrlc.clone();
// TODO. We don't have a way to know the current directory
// This should be information from the EvaluationContex or EngineState
let path = env::current_dir().unwrap();
process.current_dir(path);
let envs = self.context.stack.get_env_vars();
process.envs(envs);
process.envs(&self.env_vars);
// If the external is not the last command, its output will get piped
// either as a string or binary
@ -101,11 +85,7 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
// If there is an input from the pipeline. The stdin from the process
// is piped so it can be used to send the input information
if let Value::String { .. } = input {
process.stdin(Stdio::piped());
}
if let Value::Stream { .. } = input {
if !matches!(input, PipelineData::Value(Value::Nothing { .. })) {
process.stdin(Stdio::piped());
}
@ -116,33 +96,29 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
)),
Ok(mut child) => {
// if there is a string or a stream, that is sent to the pipe std
match input {
Value::String { val, span: _ } => {
if let Some(mut stdin_write) = child.stdin.take() {
self.write_to_stdin(&mut stdin_write, val.as_bytes())?
}
}
Value::Binary { val, span: _ } => {
if let Some(mut stdin_write) = child.stdin.take() {
self.write_to_stdin(&mut stdin_write, &val)?
}
}
Value::Stream { stream, span: _ } => {
if let Some(mut stdin_write) = child.stdin.take() {
for value in stream {
match value {
Value::String { val, span: _ } => {
self.write_to_stdin(&mut stdin_write, val.as_bytes())?
if let Some(mut stdin_write) = child.stdin.take() {
std::thread::spawn(move || {
for value in input.into_iter() {
match value {
Value::String { val, span: _ } => {
if stdin_write.write(val.as_bytes()).is_err() {
return Ok(());
}
Value::Binary { val, span: _ } => {
self.write_to_stdin(&mut stdin_write, &val)?
}
Value::Binary { val, span: _ } => {
if stdin_write.write(&val).is_err() {
return Ok(());
}
}
x => {
if stdin_write.write(x.into_string().as_bytes()).is_err() {
return Err(());
}
_ => continue,
}
}
}
}
_ => (),
Ok(())
});
}
// If this external is not the last expression, then its output is piped to a channel
@ -185,12 +161,9 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
});
// The ValueStream is consumed by the next expression in the pipeline
Value::Stream {
stream: ValueStream(Rc::new(RefCell::new(ChannelReceiver::new(rx)))),
span: Span::unknown(),
}
ChannelReceiver::new(rx).into_pipeline_data(ctrlc)
} else {
Value::nothing()
PipelineData::new()
};
match child.wait() {
@ -212,8 +185,8 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
// for minimal builds cwd is unused
let mut process = CommandSys::new("cmd");
process.arg("/c");
process.arg(&self.get_name().unwrap());
for arg in self.get_args() {
process.arg(&self.name.item);
for arg in &self.args {
// Clean the args before we use them:
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
// cmd.exe needs to have a caret to escape a pipe
@ -222,23 +195,12 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
}
process
} else {
let cmd_with_args = vec![self.get_name().unwrap(), self.get_args().join(" ")].join(" ");
let cmd_with_args = vec![self.name.item.clone(), self.args.join(" ")].join(" ");
let mut process = CommandSys::new("sh");
process.arg("-c").arg(cmd_with_args);
process
}
}
fn write_to_stdin(&self, stdin_write: &mut ChildStdin, val: &[u8]) -> Result<(), ShellError> {
if stdin_write.write(val).is_err() {
Err(ShellError::ExternalCommand(
"Error writing input to stdin".to_string(),
self.name.span,
))
} else {
Ok(())
}
}
}
// The piped data from stdout from the external command can be either String

View File

@ -1,10 +1,11 @@
use nu_protocol::{
ast::Call,
engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, Value,
engine::{Command, EngineState, Stack},
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
};
use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt};
#[derive(Clone)]
pub struct Sys;
impl Command for Sys {
@ -24,10 +25,11 @@ impl Command for Sys {
fn run(
&self,
_context: &EvaluationContext,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_sys(call)
}
@ -40,7 +42,7 @@ impl Command for Sys {
}
}
fn run_sys(call: &Call) -> Result<Value, ShellError> {
fn run_sys(call: &Call) -> Result<PipelineData, ShellError> {
let span = call.head;
let mut sys = System::new();
@ -76,7 +78,8 @@ fn run_sys(call: &Call) -> Result<Value, ShellError> {
cols: headers,
vals: values,
span,
})
}
.into_pipeline_data())
}
pub fn trim_cstyle_null(s: String) -> String {

View File

@ -2,12 +2,13 @@ use lscolors::{LsColors, Style};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, PathMember},
engine::{Command, EvaluationContext},
Signature, Span, SyntaxShape, Value,
engine::{Command, EngineState, Stack},
IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value,
};
use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
use terminal_size::{Height, Width};
#[derive(Clone)]
pub struct Griddle;
impl Command for Griddle {
@ -47,16 +48,17 @@ prints out the list properly."#
fn run(
&self,
context: &EvaluationContext,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let width_param: Option<String> = call.get_flag(context, "width")?;
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let width_param: Option<String> = call.get_flag(engine_state, stack, "width")?;
let color_param: bool = call.has_flag("color");
let separator_param: Option<String> = call.get_flag(context, "separator")?;
let separator_param: Option<String> = call.get_flag(engine_state, stack, "separator")?;
match input {
Value::List { vals, .. } => {
PipelineData::Value(Value::List { vals, .. }) => {
// dbg!("value::list");
let data = convert_to_list2(vals);
if let Some(items) = data {
@ -68,10 +70,10 @@ prints out the list properly."#
separator_param,
))
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
Value::Stream { stream, .. } => {
PipelineData::Stream(stream) => {
// dbg!("value::stream");
let data = convert_to_list2(stream);
if let Some(items) = data {
@ -84,10 +86,10 @@ prints out the list properly."#
))
} else {
// dbg!(data);
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
Value::Record { cols, vals, .. } => {
PipelineData::Value(Value::Record { cols, vals, .. }) => {
// dbg!("value::record");
let mut items = vec![];
@ -118,7 +120,7 @@ fn create_grid_output2(
width_param: Option<String>,
color_param: bool,
separator_param: Option<String>,
) -> Value {
) -> PipelineData {
let ls_colors = LsColors::from_env().unwrap_or_default();
let cols = if let Some(col) = width_param {
col.parse::<u16>().unwrap_or(80)
@ -166,6 +168,7 @@ fn create_grid_output2(
span: call.head,
}
}
.into_pipeline_data()
}
fn convert_to_list2(iter: impl IntoIterator<Item = Value>) -> Option<Vec<(usize, String, String)>> {

View File

@ -1,10 +1,11 @@
use nu_protocol::ast::{Call, PathMember};
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, Span, Value};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, Span, Value};
use nu_table::StyledString;
use std::collections::HashMap;
use terminal_size::{Height, Width};
#[derive(Clone)]
pub struct Table;
//NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.
@ -23,10 +24,11 @@ impl Command for Table {
fn run(
&self,
_context: &EvaluationContext,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let term_width = if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() {
w as usize
} else {
@ -34,7 +36,7 @@ impl Command for Table {
};
match input {
Value::List { vals, .. } => {
PipelineData::Value(Value::List { vals, .. }) => {
let table = convert_to_table(vals)?;
if let Some(table) = table {
@ -43,12 +45,13 @@ impl Command for Table {
Ok(Value::String {
val: result,
span: call.head,
})
}
.into_pipeline_data())
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
Value::Stream { stream, .. } => {
PipelineData::Stream(stream) => {
let table = convert_to_table(stream)?;
if let Some(table) = table {
@ -57,12 +60,13 @@ impl Command for Table {
Ok(Value::String {
val: result,
span: call.head,
})
}
.into_pipeline_data())
} else {
Ok(Value::Nothing { span: call.head })
Ok(PipelineData::new())
}
}
Value::Record { cols, vals, .. } => {
PipelineData::Value(Value::Record { cols, vals, .. }) => {
let mut output = vec![];
for (c, v) in cols.into_iter().zip(vals.into_iter()) {
@ -89,9 +93,10 @@ impl Command for Table {
Ok(Value::String {
val: result,
span: call.head,
})
}
.into_pipeline_data())
}
Value::Error { error } => Err(error),
PipelineData::Value(Value::Error { error }) => Err(error),
x => Ok(x),
}
}