diff --git a/crates/nu-cli/src/completions.rs b/crates/nu-cli/src/completions.rs index 89fcb100cf..470e42daa1 100644 --- a/crates/nu-cli/src/completions.rs +++ b/crates/nu-cli/src/completions.rs @@ -278,6 +278,8 @@ impl NuCompleter { &mut stack, &block, PipelineData::new(new_span), + true, + true, ); let v: Vec<_> = match result { diff --git a/crates/nu-command/src/core_commands/do_.rs b/crates/nu-command/src/core_commands/do_.rs index d5a5ffa9d7..4d63ab73ec 100644 --- a/crates/nu-command/src/core_commands/do_.rs +++ b/crates/nu-command/src/core_commands/do_.rs @@ -84,7 +84,14 @@ impl Command for Do { ) } } - let result = eval_block(engine_state, &mut stack, block, input); + let result = eval_block( + engine_state, + &mut stack, + block, + input, + call.redirect_stdout, + ignore_errors, + ); if ignore_errors { match result { diff --git a/crates/nu-command/src/core_commands/for_.rs b/crates/nu-command/src/core_commands/for_.rs index 685db8c7cc..96052b3143 100644 --- a/crates/nu-command/src/core_commands/for_.rs +++ b/crates/nu-command/src/core_commands/for_.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, eval_expression, CallExt}; +use nu_engine::{eval_block, eval_expression, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -71,6 +71,8 @@ impl Command for For { let mut stack = stack.captures_to_stack(&capture_block.captures); let orig_env_vars = stack.env_vars.clone(); let orig_env_hidden = stack.env_hidden.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; match values { Value::List { vals, .. } => Ok(vals @@ -99,11 +101,13 @@ impl Command for For { ); //let block = engine_state.get_block(block_id); - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, &block, PipelineData::new(head), + redirect_stdout, + redirect_stderr, ) { Ok(pipeline_data) => pipeline_data.into_value(head), Err(error) => Value::Error { error }, @@ -137,11 +141,13 @@ impl Command for For { ); //let block = engine_state.get_block(block_id); - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, &block, PipelineData::new(head), + redirect_stdout, + redirect_stderr, ) { Ok(pipeline_data) => pipeline_data.into_value(head), Err(error) => Value::Error { error }, @@ -152,7 +158,14 @@ impl Command for For { x => { stack.add_var(var_id, x); - eval_block_with_redirect(&engine_state, &mut stack, &block, PipelineData::new(head)) + eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(head), + redirect_stdout, + redirect_stderr, + ) } } } diff --git a/crates/nu-command/src/core_commands/if_.rs b/crates/nu-command/src/core_commands/if_.rs index 2f607eae66..5b0fe0b298 100644 --- a/crates/nu-command/src/core_commands/if_.rs +++ b/crates/nu-command/src/core_commands/if_.rs @@ -51,7 +51,14 @@ impl Command for If { if *val { let block = engine_state.get_block(then_block.block_id); let mut stack = stack.captures_to_stack(&then_block.captures); - eval_block(engine_state, &mut stack, block, input) + eval_block( + engine_state, + &mut stack, + block, + input, + call.redirect_stdout, + call.redirect_stderr, + ) } 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() { @@ -60,7 +67,14 @@ impl Command for If { let mut stack = stack.captures_to_stack(&else_block.captures); let block = engine_state.get_block(block_id); - eval_block(engine_state, &mut stack, block, input) + eval_block( + engine_state, + &mut stack, + block, + input, + call.redirect_stdout, + call.redirect_stderr, + ) } else { eval_expression(engine_state, stack, else_expr) .map(|x| x.into_pipeline_data()) diff --git a/crates/nu-command/src/core_commands/let_.rs b/crates/nu-command/src/core_commands/let_.rs index beb7716c41..f25cc8788c 100644 --- a/crates/nu-command/src/core_commands/let_.rs +++ b/crates/nu-command/src/core_commands/let_.rs @@ -41,7 +41,14 @@ impl Command for Let { .as_keyword() .expect("internal error: missing keyword"); - let rhs = eval_expression_with_input(engine_state, stack, keyword_expr, input, false)?; + let rhs = eval_expression_with_input( + engine_state, + stack, + keyword_expr, + input, + call.redirect_stdout, + call.redirect_stderr, + )?; //println!("Adding: {:?} to {}", rhs, var_id); diff --git a/crates/nu-command/src/core_commands/source.rs b/crates/nu-command/src/core_commands/source.rs index 17d1e427b0..80f12b66f5 100644 --- a/crates/nu-command/src/core_commands/source.rs +++ b/crates/nu-command/src/core_commands/source.rs @@ -38,7 +38,14 @@ impl Command for Source { let block_id: i64 = call.req(engine_state, stack, 1)?; let block = engine_state.get_block(block_id as usize).clone(); - eval_block(engine_state, stack, &block, input) + eval_block( + engine_state, + stack, + &block, + input, + call.redirect_stdout, + call.redirect_stderr, + ) } fn examples(&self) -> Vec { diff --git a/crates/nu-command/src/core_commands/use_.rs b/crates/nu-command/src/core_commands/use_.rs index db1ccb8c20..4a662dcb1d 100644 --- a/crates/nu-command/src/core_commands/use_.rs +++ b/crates/nu-command/src/core_commands/use_.rs @@ -96,8 +96,15 @@ impl Command for Use { // TODO: Add string conversions (e.g. int to string) // TODO: Later expand env to take all Values - let val = eval_block(engine_state, stack, block, PipelineData::new(call.head))? - .into_value(call.head); + let val = eval_block( + engine_state, + stack, + block, + PipelineData::new(call.head), + false, + true, + )? + .into_value(call.head); stack.add_env_var(name, val); } diff --git a/crates/nu-command/src/dataframe/test_dataframe.rs b/crates/nu-command/src/dataframe/test_dataframe.rs index 3b78750a28..7fe6066bb4 100644 --- a/crates/nu-command/src/dataframe/test_dataframe.rs +++ b/crates/nu-command/src/dataframe/test_dataframe.rs @@ -72,6 +72,8 @@ pub fn test_dataframe(cmds: Vec>) { &mut stack, &block, PipelineData::new(Span::test_data()), + true, + true, ) { Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err), Ok(result) => { diff --git a/crates/nu-command/src/env/let_env.rs b/crates/nu-command/src/env/let_env.rs index 1bab91b8c9..f9a9e45b44 100644 --- a/crates/nu-command/src/env/let_env.rs +++ b/crates/nu-command/src/env/let_env.rs @@ -39,8 +39,9 @@ impl Command for LetEnv { .as_keyword() .expect("internal error: missing keyword"); - let rhs = eval_expression_with_input(engine_state, stack, keyword_expr, input, false)? - .into_value(call.head); + let rhs = + eval_expression_with_input(engine_state, stack, keyword_expr, input, false, true)? + .into_value(call.head); if env_var == "PWD" { let cwd = current_dir(engine_state, stack)?; diff --git a/crates/nu-command/src/env/with_env.rs b/crates/nu-command/src/env/with_env.rs index 014a1e9f43..e79c541d3e 100644 --- a/crates/nu-command/src/env/with_env.rs +++ b/crates/nu-command/src/env/with_env.rs @@ -132,7 +132,14 @@ fn with_env( stack.add_env_var(k, v); } - eval_block(engine_state, &mut stack, block, input) + eval_block( + engine_state, + &mut stack, + block, + input, + call.redirect_stdout, + call.redirect_stderr, + ) } #[cfg(test)] diff --git a/crates/nu-command/src/example_test.rs b/crates/nu-command/src/example_test.rs index b936d55494..765928e179 100644 --- a/crates/nu-command/src/example_test.rs +++ b/crates/nu-command/src/example_test.rs @@ -121,6 +121,8 @@ pub fn test_examples(cmd: impl Command + 'static) { &mut stack, &block, PipelineData::new(Span::test_data()), + true, + true, ) { Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err), Ok(result) => { diff --git a/crates/nu-command/src/filters/all.rs b/crates/nu-command/src/filters/all.rs index cdc076262b..f3f50c6736 100644 --- a/crates/nu-command/src/filters/all.rs +++ b/crates/nu-command/src/filters/all.rs @@ -68,10 +68,17 @@ impl Command for All { stack.add_var(var_id, value); } - eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + eval_block( + &engine_state, + &mut stack, + block, + PipelineData::new(span), + call.redirect_stdout, + call.redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }), span, } diff --git a/crates/nu-command/src/filters/any.rs b/crates/nu-command/src/filters/any.rs index b66507f5c5..316fe069ec 100644 --- a/crates/nu-command/src/filters/any.rs +++ b/crates/nu-command/src/filters/any.rs @@ -67,10 +67,17 @@ impl Command for Any { stack.add_var(var_id, value); } - eval_block(&engine_state, &mut stack, block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + eval_block( + &engine_state, + &mut stack, + block, + PipelineData::new(span), + call.redirect_stdout, + call.redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }), span, } diff --git a/crates/nu-command/src/filters/collect.rs b/crates/nu-command/src/filters/collect.rs index c9cc64dcb6..c9de01ca40 100644 --- a/crates/nu-command/src/filters/collect.rs +++ b/crates/nu-command/src/filters/collect.rs @@ -50,6 +50,8 @@ impl Command for Collect { &mut stack, &block, PipelineData::new(call.head), + call.redirect_stdout, + call.redirect_stderr, ) } diff --git a/crates/nu-command/src/filters/each.rs b/crates/nu-command/src/filters/each.rs index 49b04ee092..3d3112325b 100644 --- a/crates/nu-command/src/filters/each.rs +++ b/crates/nu-command/src/filters/each.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -110,6 +110,8 @@ impl Command for Each { let orig_env_vars = stack.env_vars.clone(); let orig_env_hidden = stack.env_hidden.clone(); let span = call.head; + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; match input { PipelineData::Value(Value::Range { .. }, ..) @@ -143,11 +145,13 @@ impl Command for Each { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, &block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v.into_value(span), Err(error) => Value::Error { error }, @@ -188,87 +192,34 @@ impl Command for Each { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, &block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v.into_value(span), Err(error) => Value::Error { error }, } }) .into_pipeline_data(ctrlc)), - // JT: we'll turn this off for now until we get a better design - // leaving it here, but commented-out, for the time being - // 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); - - // stack.with_env(&orig_env_vars, &orig_env_hidden); - - // 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_with_redirect( - // &engine_state, - // &mut stack, - // &block, - // PipelineData::new(span), - // )? { - // 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(span)); - // } - // } - // } - - // 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_with_redirect(&engine_state, &mut stack, &block, PipelineData::new(span)) + eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) } } .and_then(|x| { diff --git a/crates/nu-command/src/filters/each_group.rs b/crates/nu-command/src/filters/each_group.rs index 2defc4f0b0..20ee65990e 100644 --- a/crates/nu-command/src/filters/each_group.rs +++ b/crates/nu-command/src/filters/each_group.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -69,6 +69,8 @@ impl Command for EachGroup { engine_state: engine_state.clone(), stack: stack.clone(), group_size: group_size.item, + redirect_stdout: call.redirect_stdout, + redirect_stderr: call.redirect_stderr, input: Box::new(input.into_iter()), span: call.head, }; @@ -82,6 +84,8 @@ struct EachGroupIterator { engine_state: EngineState, stack: Stack, group_size: usize, + redirect_stdout: bool, + redirect_stderr: bool, input: Box + Send>, span: Span, } @@ -118,6 +122,8 @@ impl Iterator for EachGroupIterator { self.block.clone(), self.engine_state.clone(), self.stack.clone(), + self.redirect_stdout, + self.redirect_stderr, self.span, )) } @@ -128,6 +134,8 @@ pub(crate) fn run_block_on_vec( capture_block: CaptureBlock, engine_state: EngineState, stack: Stack, + redirect_stdout: bool, + redirect_stderr: bool, span: Span, ) -> Value { let value = Value::List { vals: input, span }; @@ -142,7 +150,14 @@ pub(crate) fn run_block_on_vec( } } - match eval_block_with_redirect(&engine_state, &mut stack, block, PipelineData::new(span)) { + match eval_block( + &engine_state, + &mut stack, + block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) { Ok(pipeline) => pipeline.into_value(span), Err(error) => Value::Error { error }, } diff --git a/crates/nu-command/src/filters/each_window.rs b/crates/nu-command/src/filters/each_window.rs index 1f3dd4484c..fd6a5db68c 100644 --- a/crates/nu-command/src/filters/each_window.rs +++ b/crates/nu-command/src/filters/each_window.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -108,6 +108,8 @@ impl Command for EachWindow { stack: stack.clone(), group_size: group_size.item, input: Box::new(input.into_iter()), + redirect_stdout: call.redirect_stdout, + redirect_stderr: call.redirect_stderr, span: call.head, previous: vec![], stride, @@ -123,6 +125,8 @@ struct EachWindowIterator { stack: Stack, group_size: usize, input: Box + Send>, + redirect_stdout: bool, + redirect_stderr: bool, span: Span, previous: Vec, stride: usize, @@ -186,6 +190,8 @@ impl Iterator for EachWindowIterator { self.block.clone(), self.engine_state.clone(), self.stack.clone(), + self.redirect_stdout, + self.redirect_stderr, self.span, )) } @@ -196,6 +202,8 @@ pub(crate) fn run_block_on_vec( capture_block: CaptureBlock, engine_state: EngineState, stack: Stack, + redirect_stdout: bool, + redirect_stderr: bool, span: Span, ) -> Value { let value = Value::List { vals: input, span }; @@ -210,7 +218,14 @@ pub(crate) fn run_block_on_vec( } } - match eval_block_with_redirect(&engine_state, &mut stack, block, PipelineData::new(span)) { + match eval_block( + &engine_state, + &mut stack, + block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) { Ok(pipeline) => pipeline.into_value(span), Err(error) => Value::Error { error }, } diff --git a/crates/nu-command/src/filters/empty.rs b/crates/nu-command/src/filters/empty.rs index fb5bd4cf9a..27bbbf90f9 100644 --- a/crates/nu-command/src/filters/empty.rs +++ b/crates/nu-command/src/filters/empty.rs @@ -118,7 +118,14 @@ fn empty( .ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), head))?; let b = engine_state.get_block(block_id); - let evaluated_block = eval_block(engine_state, stack, b, PipelineData::new(head))?; + let evaluated_block = eval_block( + engine_state, + stack, + b, + PipelineData::new(head), + call.redirect_stdout, + call.redirect_stderr, + )?; Some(evaluated_block.into_value(head)) } else { None diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index b7b5676564..419c25b97b 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -93,6 +93,9 @@ impl Command for Find { let metadata = input.metadata(); let config = stack.get_config()?; + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + match call.get_flag::(&engine_state, stack, "predicate")? { Some(predicate) => { let capture_block = predicate; @@ -121,6 +124,8 @@ impl Command for Find { &mut stack, &block, PipelineData::new_with_metadata(metadata.clone(), span), + redirect_stdout, + redirect_stderr, ) .map_or(false, |pipeline_data| { pipeline_data.into_value(span).is_true() diff --git a/crates/nu-command/src/filters/group_by.rs b/crates/nu-command/src/filters/group_by.rs index 906590458c..7ae162dbd8 100644 --- a/crates/nu-command/src/filters/group_by.rs +++ b/crates/nu-command/src/filters/group_by.rs @@ -119,8 +119,14 @@ pub fn group_by( if let Some(capture_block) = &block { let mut stack = stack.captures_to_stack(&capture_block.captures); let block = engine_state.get_block(capture_block.block_id); - let pipeline = - eval_block(engine_state, &mut stack, block, value.into_pipeline_data()); + let pipeline = eval_block( + engine_state, + &mut stack, + block, + value.into_pipeline_data(), + call.redirect_stdout, + call.redirect_stderr, + ); match pipeline { Ok(s) => { diff --git a/crates/nu-command/src/filters/keep/keep_until.rs b/crates/nu-command/src/filters/keep/keep_until.rs index d6238c3df0..660acc4d75 100644 --- a/crates/nu-command/src/filters/keep/keep_until.rs +++ b/crates/nu-command/src/filters/keep/keep_until.rs @@ -58,6 +58,9 @@ impl Command for KeepUntil { let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + Ok(input .into_iter() .take_while(move |value| { @@ -65,10 +68,17 @@ impl Command for KeepUntil { stack.add_var(var_id, value.clone()); } - !eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + !eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }) .into_pipeline_data(ctrlc)) } diff --git a/crates/nu-command/src/filters/keep/keep_while.rs b/crates/nu-command/src/filters/keep/keep_while.rs index 5b5705e962..25a6c59392 100644 --- a/crates/nu-command/src/filters/keep/keep_while.rs +++ b/crates/nu-command/src/filters/keep/keep_while.rs @@ -58,6 +58,9 @@ impl Command for KeepWhile { let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + Ok(input .into_iter() .take_while(move |value| { @@ -65,10 +68,17 @@ impl Command for KeepWhile { stack.add_var(var_id, value.clone()); } - eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }) .into_pipeline_data(ctrlc)) } diff --git a/crates/nu-command/src/filters/merge.rs b/crates/nu-command/src/filters/merge.rs index 5caf5e862d..1518e760d7 100644 --- a/crates/nu-command/src/filters/merge.rs +++ b/crates/nu-command/src/filters/merge.rs @@ -82,6 +82,8 @@ impl Command for Merge { &mut stack, block, PipelineData::new(call.head), + call.redirect_stdout, + call.redirect_stderr, ); let table = match result { diff --git a/crates/nu-command/src/filters/par_each.rs b/crates/nu-command/src/filters/par_each.rs index e15267d391..602cd2907a 100644 --- a/crates/nu-command/src/filters/par_each.rs +++ b/crates/nu-command/src/filters/par_each.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -53,6 +53,8 @@ impl Command for ParEach { let block_id = capture_block.block_id; let mut stack = stack.captures_to_stack(&capture_block.captures); let span = call.head; + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; match input { PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val @@ -87,11 +89,13 @@ impl Command for ParEach { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), @@ -133,11 +137,13 @@ impl Command for ParEach { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), @@ -178,11 +184,13 @@ impl Command for ParEach { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), @@ -228,11 +236,13 @@ impl Command for ParEach { } } - match eval_block_with_redirect( + match eval_block( &engine_state, &mut stack, block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v, Err(error) => Value::Error { error }.into_pipeline_data(), @@ -242,64 +252,6 @@ impl Command for ParEach { .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_with_redirect( - &engine_state, - &mut stack, - block, - PipelineData::new(span), - )? { - 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(span)); - } - } - } - - 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); @@ -309,7 +261,14 @@ impl Command for ParEach { } } - eval_block_with_redirect(&engine_state, &mut stack, block, PipelineData::new(span)) + eval_block( + &engine_state, + &mut stack, + block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) } } } diff --git a/crates/nu-command/src/filters/par_each_group.rs b/crates/nu-command/src/filters/par_each_group.rs index 8bf559147f..4f4066723d 100644 --- a/crates/nu-command/src/filters/par_each_group.rs +++ b/crates/nu-command/src/filters/par_each_group.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -49,6 +49,8 @@ impl Command for ParEachGroup { let capture_block: CaptureBlock = call.req(engine_state, stack, 1)?; let ctrlc = engine_state.ctrlc.clone(); let span = call.head; + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; let stack = stack.captures_to_stack(&capture_block.captures); @@ -72,11 +74,13 @@ impl Command for ParEachGroup { } } - match eval_block_with_redirect( + match eval_block( engine_state, &mut stack, block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ) { Ok(v) => v.into_value(span), Err(error) => Value::Error { error }, diff --git a/crates/nu-command/src/filters/reduce.rs b/crates/nu-command/src/filters/reduce.rs index 1bb9b6956e..f57c787f33 100644 --- a/crates/nu-command/src/filters/reduce.rs +++ b/crates/nu-command/src/filters/reduce.rs @@ -109,6 +109,9 @@ impl Command for Reduce { let orig_env_vars = stack.env_vars.clone(); let orig_env_hidden = stack.env_hidden.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + let mut input_iter = input.into_iter(); let (off, start_val) = if let Some(val) = fold { @@ -170,7 +173,14 @@ impl Command for Reduce { } } - let v = match eval_block(engine_state, &mut stack, block, PipelineData::new(span)) { + let v = match eval_block( + engine_state, + &mut stack, + block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) { Ok(v) => v.into_value(span), Err(error) => Value::Error { error }, }; diff --git a/crates/nu-command/src/filters/skip/skip_until.rs b/crates/nu-command/src/filters/skip/skip_until.rs index 79bbacdded..f0cafdbadf 100644 --- a/crates/nu-command/src/filters/skip/skip_until.rs +++ b/crates/nu-command/src/filters/skip/skip_until.rs @@ -58,6 +58,9 @@ impl Command for SkipUntil { let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + Ok(input .into_iter() .skip_while(move |value| { @@ -65,10 +68,17 @@ impl Command for SkipUntil { stack.add_var(var_id, value.clone()); } - !eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + !eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }) .into_pipeline_data(ctrlc) .set_metadata(metadata)) diff --git a/crates/nu-command/src/filters/skip/skip_while.rs b/crates/nu-command/src/filters/skip/skip_while.rs index 4c0ba6c36a..19bc7853af 100644 --- a/crates/nu-command/src/filters/skip/skip_while.rs +++ b/crates/nu-command/src/filters/skip/skip_while.rs @@ -58,6 +58,9 @@ impl Command for SkipWhile { let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + Ok(input .into_iter() .skip_while(move |value| { @@ -65,10 +68,17 @@ impl Command for SkipWhile { stack.add_var(var_id, value.clone()); } - eval_block(&engine_state, &mut stack, &block, PipelineData::new(span)) - .map_or(false, |pipeline_data| { - pipeline_data.into_value(span).is_true() - }) + eval_block( + &engine_state, + &mut stack, + &block, + PipelineData::new(span), + redirect_stdout, + redirect_stderr, + ) + .map_or(false, |pipeline_data| { + pipeline_data.into_value(span).is_true() + }) }) .into_pipeline_data(ctrlc) .set_metadata(metadata)) diff --git a/crates/nu-command/src/filters/update.rs b/crates/nu-command/src/filters/update.rs index f0a1f8d0bc..a70a17e50b 100644 --- a/crates/nu-command/src/filters/update.rs +++ b/crates/nu-command/src/filters/update.rs @@ -70,6 +70,10 @@ fn update( let cell_path: CellPath = call.req(engine_state, stack, 0)?; let replacement: Value = call.req(engine_state, stack, 1)?; + + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + let engine_state = engine_state.clone(); let ctrlc = engine_state.ctrlc.clone(); @@ -97,6 +101,8 @@ fn update( &mut stack, &block, input.clone().into_pipeline_data(), + redirect_stdout, + redirect_stderr, ); match output { diff --git a/crates/nu-command/src/filters/update_cells.rs b/crates/nu-command/src/filters/update_cells.rs index 6dbe50c0c6..f578b132cd 100644 --- a/crates/nu-command/src/filters/update_cells.rs +++ b/crates/nu-command/src/filters/update_cells.rs @@ -132,6 +132,9 @@ impl Command for UpdateCells { let ctrlc = engine_state.ctrlc.clone(); let block: Block = engine_state.get_block(block.block_id).clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + let span = call.head; stack.with_env(&orig_env_vars, &orig_env_hidden); @@ -156,6 +159,8 @@ impl Command for UpdateCells { stack, block, columns, + redirect_stdout, + redirect_stderr, span, } .into_pipeline_data(ctrlc)) @@ -168,6 +173,8 @@ struct UpdateCellIterator { engine_state: EngineState, stack: Stack, block: Block, + redirect_stdout: bool, + redirect_stderr: bool, span: Span, } @@ -195,6 +202,8 @@ impl Iterator for UpdateCellIterator { &self.engine_state, &mut self.stack, &self.block, + self.redirect_stdout, + self.redirect_stderr, span, ), }) @@ -207,6 +216,8 @@ impl Iterator for UpdateCellIterator { &self.engine_state, &mut self.stack, &self.block, + self.redirect_stdout, + self.redirect_stderr, self.span, )), } @@ -221,6 +232,8 @@ fn process_cell( engine_state: &EngineState, stack: &mut Stack, block: &Block, + redirect_stdout: bool, + redirect_stderr: bool, span: Span, ) -> Value { if let Some(var) = block.signature.get_positional(0) { @@ -228,7 +241,14 @@ fn process_cell( stack.add_var(*var_id, val.clone()); } } - match eval_block(engine_state, stack, block, val.into_pipeline_data()) { + match eval_block( + engine_state, + stack, + block, + val.into_pipeline_data(), + redirect_stdout, + redirect_stderr, + ) { Ok(pd) => pd.into_value(span), Err(e) => Value::Error { error: e }, } diff --git a/crates/nu-command/src/filters/where_.rs b/crates/nu-command/src/filters/where_.rs index cbda0c7f3c..9eb10fb51e 100644 --- a/crates/nu-command/src/filters/where_.rs +++ b/crates/nu-command/src/filters/where_.rs @@ -1,4 +1,4 @@ -use nu_engine::{eval_block_with_redirect, CallExt}; +use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::{ @@ -41,6 +41,9 @@ impl Command for Where { let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + Ok(input .into_iter() .filter_map(move |value| { @@ -49,11 +52,13 @@ impl Command for Where { stack.add_var(*var_id, value.clone()); } } - let result = eval_block_with_redirect( + let result = eval_block( &engine_state, &mut stack, &block, PipelineData::new(span), + redirect_stdout, + redirect_stderr, ); match result { diff --git a/crates/nu-command/src/system/benchmark.rs b/crates/nu-command/src/system/benchmark.rs index ce1d537112..ac1ea49e23 100644 --- a/crates/nu-command/src/system/benchmark.rs +++ b/crates/nu-command/src/system/benchmark.rs @@ -39,6 +39,9 @@ impl Command for Benchmark { let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?; let block = engine_state.get_block(capture_block.block_id); + let redirect_stdout = call.redirect_stdout; + let redirect_stderr = call.redirect_stderr; + let mut stack = stack.captures_to_stack(&capture_block.captures); let start_time = Instant::now(); eval_block( @@ -46,6 +49,8 @@ impl Command for Benchmark { &mut stack, block, PipelineData::new(call.head), + redirect_stdout, + redirect_stderr, )? .into_value(call.head); diff --git a/crates/nu-command/src/system/exec.rs b/crates/nu-command/src/system/exec.rs index 56b0a71f55..26d6c16419 100644 --- a/crates/nu-command/src/system/exec.rs +++ b/crates/nu-command/src/system/exec.rs @@ -84,7 +84,8 @@ fn exec( name, args, env_vars, - last_expression: true, + redirect_stdout: true, + redirect_stderr: false, }; let mut command = external_command.spawn_simple_command(&cwd.to_string_lossy().to_string())?; diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 26c398cbf1..adcfc7ccf0 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -36,7 +36,8 @@ impl Command for External { fn signature(&self) -> nu_protocol::Signature { Signature::build("run-external") - .switch("last-expression", "last-expression", None) + .switch("redirect-stdout", "redirect-stdout", None) + .switch("redirect-stderr", "redirect-stderr", None) .rest("rest", SyntaxShape::Any, "external command to run") .category(Category::System) } @@ -50,7 +51,8 @@ impl Command for External { ) -> Result { let name: Spanned = call.req(engine_state, stack, 0)?; let args: Vec = call.rest(engine_state, stack, 1)?; - let last_expression = call.has_flag("last-expression"); + let redirect_stdout = call.has_flag("redirect-stdout"); + let redirect_stderr = call.has_flag("redirect-stderr"); // Translate environment variables from Values to Strings let config = stack.get_config().unwrap_or_default(); @@ -93,7 +95,8 @@ impl Command for External { let command = ExternalCommand { name, args: args_strs, - last_expression, + redirect_stdout, + redirect_stderr, env_vars: env_vars_str, }; command.run_with_input(engine_state, stack, input) @@ -103,7 +106,8 @@ impl Command for External { pub struct ExternalCommand { pub name: Spanned, pub args: Vec>, - pub last_expression: bool, + pub redirect_stdout: bool, + pub redirect_stderr: bool, pub env_vars: HashMap, } @@ -138,10 +142,14 @@ impl ExternalCommand { // If the external is not the last command, its output will get piped // either as a string or binary - if !self.last_expression { + if self.redirect_stdout { process.stdout(Stdio::piped()); } + if self.redirect_stderr { + process.stderr(Stdio::piped()); + } + // 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 !matches!(input, PipelineData::Value(Value::Nothing { .. }, ..)) { @@ -173,10 +181,14 @@ impl ExternalCommand { // If the external is not the last command, its output will get piped // either as a string or binary - if !self.last_expression { + if self.redirect_stdout { process.stdout(Stdio::piped()); } + if self.redirect_stderr { + process.stderr(Stdio::piped()); + } + // 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 !matches!(input, PipelineData::Value(Value::Nothing { .. }, ..)) { @@ -241,7 +253,8 @@ impl ExternalCommand { } } - let last_expression = self.last_expression; + let redirect_stdout = self.redirect_stdout; + let redirect_stderr = self.redirect_stderr; let span = self.name.span; let output_ctrlc = ctrlc.clone(); let (tx, rx) = mpsc::channel(); @@ -249,7 +262,12 @@ impl ExternalCommand { std::thread::spawn(move || { // If this external is not the last expression, then its output is piped to a channel // and we create a ValueStream that can be consumed - if !last_expression { + + if redirect_stderr { + let _ = child.stderr.take(); + } + + if redirect_stdout { let stdout = child.stdout.take().ok_or_else(|| { ShellError::ExternalCommand( "Error taking stdout from external".to_string(), diff --git a/crates/nu-command/tests/commands/str_/mod.rs b/crates/nu-command/tests/commands/str_/mod.rs index f56becb20c..37698c16a5 100644 --- a/crates/nu-command/tests/commands/str_/mod.rs +++ b/crates/nu-command/tests/commands/str_/mod.rs @@ -354,3 +354,15 @@ fn str_reverse() { assert!(actual.out.contains("llehsun")); } + +#[test] +fn test_redirection_trim() { + let actual = nu!( + cwd: ".", pipeline( + r#" + let x = (nu --testbin cococo niceone); $x | str trim | str length + "# + )); + + assert_eq!(actual.out, "7"); +} diff --git a/crates/nu-command/tests/commands/with_env.rs b/crates/nu-command/tests/commands/with_env.rs index ca94c2b33d..32d9d4f22d 100644 --- a/crates/nu-command/tests/commands/with_env.rs +++ b/crates/nu-command/tests/commands/with_env.rs @@ -55,6 +55,16 @@ fn with_env_and_shorthand_same_result() { assert_eq!(actual_shorthand.out, actual_normal.out); } +#[test] +fn test_redirection2() { + let actual = nu!( + cwd: "tests/fixtures/formats", + "let x = (FOO=BAR nu --testbin cococo niceenvvar); $x | str trim | str length" + ); + + assert_eq!(actual.out, "10"); +} + // FIXME: jt: needs more work #[ignore] #[test] diff --git a/crates/nu-engine/src/env.rs b/crates/nu-engine/src/env.rs index 07da45414e..602f7eccfc 100644 --- a/crates/nu-engine/src/env.rs +++ b/crates/nu-engine/src/env.rs @@ -161,8 +161,14 @@ fn get_converted_value( stack.add_var(*var_id, orig_val.clone()); } - let result = - eval_block(engine_state, &mut stack, block, PipelineData::new(val_span)); + let result = eval_block( + engine_state, + &mut stack, + block, + PipelineData::new(val_span), + true, + true, + ); match result { Ok(data) => ConversionResult::Ok(data.into_value(val_span)), diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 361ff6eef4..df7d044372 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -133,7 +133,7 @@ fn eval_call( } } - let result = eval_block(engine_state, &mut callee_stack, block, input); + let result = eval_block(engine_state, &mut callee_stack, block, input, false, true); if block.redirect_env { let caller_env_vars = caller_stack.get_env_var_names(engine_state); @@ -169,7 +169,8 @@ fn eval_external( head: &Expression, args: &[Expression], input: PipelineData, - last_expression: bool, + redirect_stdout: bool, + redirect_stderr: bool, ) -> Result { let decl_id = engine_state .find_decl("run-external".as_bytes()) @@ -185,10 +186,20 @@ fn eval_external( call.positional.push(arg.clone()) } - if last_expression { + if redirect_stdout { call.named.push(( Spanned { - item: "last-expression".into(), + item: "redirect-stdout".into(), + span: head.span, + }, + None, + )) + } + + if redirect_stderr { + call.named.push(( + Spanned { + item: "redirect-stderr".into(), span: head.span, }, None, @@ -277,6 +288,7 @@ pub fn eval_expression( args, PipelineData::new(span), false, + false, )? .into_value(span)) } @@ -431,20 +443,37 @@ pub fn eval_expression_with_input( stack: &mut Stack, expr: &Expression, mut input: PipelineData, - last_expression: bool, + redirect_stdout: bool, + redirect_stderr: bool, ) -> Result { match expr { Expression { expr: Expr::Call(call), .. } => { - input = eval_call(engine_state, stack, call, input)?; + if !redirect_stdout || redirect_stderr { + // we're doing something different than the defaults + let mut call = call.clone(); + call.redirect_stdout = redirect_stdout; + call.redirect_stderr = redirect_stderr; + input = eval_call(engine_state, stack, &call, input)?; + } else { + input = eval_call(engine_state, stack, call, input)?; + } } Expression { expr: Expr::ExternalCall(head, args), .. } => { - input = eval_external(engine_state, stack, head, args, input, last_expression)?; + input = eval_external( + engine_state, + stack, + head, + args, + input, + redirect_stdout, + redirect_stderr, + )?; } Expression { @@ -470,6 +499,8 @@ pub fn eval_block( stack: &mut Stack, block: &Block, mut input: PipelineData, + redirect_stdout: bool, + redirect_stderr: bool, ) -> Result { let num_pipelines = block.len(); for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() { @@ -479,7 +510,8 @@ pub fn eval_block( stack, elem, input, - i == pipeline.expressions.len() - 1, + redirect_stdout || (i != pipeline.expressions.len() - 1), + redirect_stderr, )? } @@ -543,78 +575,6 @@ pub fn eval_block( Ok(input) } -pub fn eval_block_with_redirect( - engine_state: &EngineState, - stack: &mut Stack, - block: &Block, - mut input: PipelineData, -) -> Result { - let num_pipelines = block.len(); - for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() { - for elem in pipeline.expressions.iter() { - input = eval_expression_with_input(engine_state, stack, elem, input, false)? - } - - if pipeline_idx < (num_pipelines) - 1 { - match input { - PipelineData::Value(Value::Nothing { .. }, ..) => {} - _ => { - // Drain the input to the screen via tabular output - let config = stack.get_config().unwrap_or_default(); - - match engine_state.find_decl("table".as_bytes()) { - Some(decl_id) => { - let table = engine_state.get_decl(decl_id).run( - engine_state, - stack, - &Call::new(Span::new(0, 0)), - input, - )?; - - for item in table { - let stdout = std::io::stdout(); - - if let Value::Error { error } = item { - return Err(error); - } - - let mut out = item.into_string("\n", &config); - out.push('\n'); - - match stdout.lock().write_all(out.as_bytes()) { - Ok(_) => (), - Err(err) => eprintln!("{}", err), - }; - } - } - None => { - for item in input { - let stdout = std::io::stdout(); - - if let Value::Error { error } = item { - return Err(error); - } - - let mut out = item.into_string("\n", &config); - out.push('\n'); - - match stdout.lock().write_all(out.as_bytes()) { - Ok(_) => (), - Err(err) => eprintln!("{}", err), - }; - } - } - }; - } - } - - input = PipelineData::new(Span { start: 0, end: 0 }) - } - } - - Ok(input) -} - pub fn eval_subexpression( engine_state: &EngineState, stack: &mut Stack, @@ -623,7 +583,7 @@ pub fn eval_subexpression( ) -> Result { for pipeline in block.pipelines.iter() { for expr in pipeline.expressions.iter() { - input = eval_expression_with_input(engine_state, stack, expr, input, false)? + input = eval_expression_with_input(engine_state, stack, expr, input, true, false)? } } diff --git a/crates/nu-engine/src/lib.rs b/crates/nu-engine/src/lib.rs index 9de7dae381..f43b780d01 100644 --- a/crates/nu-engine/src/lib.rs +++ b/crates/nu-engine/src/lib.rs @@ -10,7 +10,6 @@ pub use column::get_columns; pub use documentation::{generate_docs, get_brief_help, get_documentation, get_full_help}; pub use env::*; pub use eval::{ - eval_block, eval_block_with_redirect, eval_expression, eval_expression_with_input, - eval_operator, eval_subexpression, + eval_block, eval_expression, eval_expression_with_input, eval_operator, eval_subexpression, }; pub use glob_from::glob_from; diff --git a/crates/nu-parser/src/known_external.rs b/crates/nu-parser/src/known_external.rs index 6009cbc15e..391d311f3a 100644 --- a/crates/nu-parser/src/known_external.rs +++ b/crates/nu-parser/src/known_external.rs @@ -1,7 +1,7 @@ use nu_protocol::ast::Expr; use nu_protocol::engine::{EngineState, Stack, StateWorkingSet}; -use nu_protocol::PipelineData; use nu_protocol::{ast::Call, engine::Command, ShellError, Signature}; +use nu_protocol::{PipelineData, Spanned}; #[derive(Clone)] pub struct KnownExternal { @@ -61,15 +61,25 @@ impl Command for KnownExternal { call.positional.push(arg.clone()) } - // if last_expression { - // call.named.push(( - // Spanned { - // item: "last-expression".into(), - // span: head.span, - // }, - // None, - // )) - // } + if call.redirect_stdout { + call.named.push(( + Spanned { + item: "redirect-stdout".into(), + span: call_span, + }, + None, + )) + } + + if call.redirect_stderr { + call.named.push(( + Spanned { + item: "redirect-stderr".into(), + span: call_span, + }, + None, + )) + } command.run(engine_state, stack, &call, input) } diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 1bcb7df2e8..b277ecd495 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -579,6 +579,8 @@ pub fn parse_export( decl_id: export_decl_id, positional: vec![], named: vec![], + redirect_stdout: true, + redirect_stderr: false, }); let exportable = if let Some(kw_span) = spans.get(1) { @@ -986,6 +988,8 @@ pub fn parse_module( decl_id: module_decl_id, positional: vec![module_name_expr, block_expr], named: vec![], + redirect_stdout: true, + redirect_stderr: false, }); ( @@ -1200,6 +1204,8 @@ pub fn parse_use( decl_id: use_decl_id, positional: vec![import_pattern_expr], named: vec![], + redirect_stdout: true, + redirect_stderr: false, }); ( @@ -1399,6 +1405,8 @@ pub fn parse_hide( decl_id: hide_decl_id, positional: vec![import_pattern_expr], named: vec![], + redirect_stdout: true, + redirect_stderr: false, }); ( @@ -1480,6 +1488,8 @@ pub fn parse_let( head: spans[0], positional: vec![lvalue, rvalue], named: vec![], + redirect_stdout: true, + redirect_stderr: false, }); return ( diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index e6c1d87bf2..7948cf3f29 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -3420,7 +3420,7 @@ pub fn parse_expression( ( Expression { expr: Expr::String(String::new()), - span: spans[pos], + span: Span { start: 0, end: 0 }, ty: Type::Nothing, custom_completion: None, }, @@ -3556,6 +3556,8 @@ pub fn parse_expression( decl_id, named: vec![], positional, + redirect_stdout: true, + redirect_stderr: false, })); ( @@ -4108,6 +4110,8 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) named: vec![], positional: output, decl_id, + redirect_stdout: true, + redirect_stderr: false, })), span, ty: Type::String, diff --git a/crates/nu-protocol/src/ast/call.rs b/crates/nu-protocol/src/ast/call.rs index 7a85b40e2a..116478860d 100644 --- a/crates/nu-protocol/src/ast/call.rs +++ b/crates/nu-protocol/src/ast/call.rs @@ -8,6 +8,8 @@ pub struct Call { pub head: Span, pub positional: Vec, pub named: Vec<(Spanned, Option)>, + pub redirect_stdout: bool, + pub redirect_stderr: bool, } impl Call { @@ -17,6 +19,8 @@ impl Call { head, positional: vec![], named: vec![], + redirect_stdout: true, + redirect_stderr: false, } } diff --git a/src/commands.rs b/src/commands.rs index 9652f87432..ce97a38d51 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -95,7 +95,7 @@ pub(crate) fn evaluate( std::process::exit(1); } - match eval_block(engine_state, &mut stack, &block, input) { + match eval_block(engine_state, &mut stack, &block, input, false, false) { Ok(pipeline_data) => { crate::eval_file::print_table_or_error(engine_state, &mut stack, pipeline_data, &config) } diff --git a/src/tests/test_engine.rs b/src/tests/test_engine.rs index a562e50193..645091aa2c 100644 --- a/src/tests/test_engine.rs +++ b/src/tests/test_engine.rs @@ -251,3 +251,9 @@ fn with_env_shorthand_nested_quotes() -> TestResult { "-arg \"hello world\"", ) } + +#[test] +fn test_redirection_stderr() -> TestResult { + // try a nonsense binary + run_test(r#"do -i { asdjw4j5cnaabw44rd }; echo done"#, "done") +} diff --git a/src/utils.rs b/src/utils.rs index 8537aac346..95880dd732 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -226,7 +226,7 @@ pub(crate) fn eval_source( report_error(&working_set, &err); } - match eval_block(engine_state, stack, &block, input) { + match eval_block(engine_state, stack, &block, input, false, false) { Ok(pipeline_data) => { if let Err(err) = print_pipeline_data(pipeline_data, engine_state, stack) { let working_set = StateWorkingSet::new(engine_state);