forked from extern/nushell
Add pipeline redirection support (#4594)
* redirection * Remove commented-out * fix tests * more fixes
This commit is contained in:
parent
739e403cd5
commit
9888f8f298
@ -278,6 +278,8 @@ impl NuCompleter {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(new_span),
|
PipelineData::new(new_span),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let v: Vec<_> = match result {
|
let v: Vec<_> = match result {
|
||||||
|
@ -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 {
|
if ignore_errors {
|
||||||
match result {
|
match result {
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -71,6 +71,8 @@ impl Command for For {
|
|||||||
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
||||||
let orig_env_vars = stack.env_vars.clone();
|
let orig_env_vars = stack.env_vars.clone();
|
||||||
let orig_env_hidden = stack.env_hidden.clone();
|
let orig_env_hidden = stack.env_hidden.clone();
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
match values {
|
match values {
|
||||||
Value::List { vals, .. } => Ok(vals
|
Value::List { vals, .. } => Ok(vals
|
||||||
@ -99,11 +101,13 @@ impl Command for For {
|
|||||||
);
|
);
|
||||||
|
|
||||||
//let block = engine_state.get_block(block_id);
|
//let block = engine_state.get_block(block_id);
|
||||||
match eval_block_with_redirect(
|
match eval_block(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(head),
|
PipelineData::new(head),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(pipeline_data) => pipeline_data.into_value(head),
|
Ok(pipeline_data) => pipeline_data.into_value(head),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
@ -137,11 +141,13 @@ impl Command for For {
|
|||||||
);
|
);
|
||||||
|
|
||||||
//let block = engine_state.get_block(block_id);
|
//let block = engine_state.get_block(block_id);
|
||||||
match eval_block_with_redirect(
|
match eval_block(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(head),
|
PipelineData::new(head),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(pipeline_data) => pipeline_data.into_value(head),
|
Ok(pipeline_data) => pipeline_data.into_value(head),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
@ -152,7 +158,14 @@ impl Command for For {
|
|||||||
x => {
|
x => {
|
||||||
stack.add_var(var_id, 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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,14 @@ impl Command for If {
|
|||||||
if *val {
|
if *val {
|
||||||
let block = engine_state.get_block(then_block.block_id);
|
let block = engine_state.get_block(then_block.block_id);
|
||||||
let mut stack = stack.captures_to_stack(&then_block.captures);
|
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 {
|
} else if let Some(else_case) = else_case {
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
if let Some(else_expr) = else_case.as_keyword() {
|
||||||
if let Some(block_id) = else_expr.as_block() {
|
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 mut stack = stack.captures_to_stack(&else_block.captures);
|
||||||
let block = engine_state.get_block(block_id);
|
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 {
|
} else {
|
||||||
eval_expression(engine_state, stack, else_expr)
|
eval_expression(engine_state, stack, else_expr)
|
||||||
.map(|x| x.into_pipeline_data())
|
.map(|x| x.into_pipeline_data())
|
||||||
|
@ -41,7 +41,14 @@ impl Command for Let {
|
|||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing 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);
|
//println!("Adding: {:?} to {}", rhs, var_id);
|
||||||
|
|
||||||
|
@ -38,7 +38,14 @@ impl Command for Source {
|
|||||||
let block_id: i64 = call.req(engine_state, stack, 1)?;
|
let block_id: i64 = call.req(engine_state, stack, 1)?;
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id as usize).clone();
|
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<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -96,7 +96,14 @@ impl Command for Use {
|
|||||||
|
|
||||||
// TODO: Add string conversions (e.g. int to string)
|
// TODO: Add string conversions (e.g. int to string)
|
||||||
// TODO: Later expand env to take all Values
|
// TODO: Later expand env to take all Values
|
||||||
let val = eval_block(engine_state, stack, block, PipelineData::new(call.head))?
|
let val = eval_block(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(call.head),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?
|
||||||
.into_value(call.head);
|
.into_value(call.head);
|
||||||
|
|
||||||
stack.add_env_var(name, val);
|
stack.add_env_var(name, val);
|
||||||
|
@ -72,6 +72,8 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(Span::test_data()),
|
PipelineData::new(Span::test_data()),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
) {
|
) {
|
||||||
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
|
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
|
3
crates/nu-command/src/env/let_env.rs
vendored
3
crates/nu-command/src/env/let_env.rs
vendored
@ -39,7 +39,8 @@ impl Command for LetEnv {
|
|||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing 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, false, true)?
|
||||||
.into_value(call.head);
|
.into_value(call.head);
|
||||||
|
|
||||||
if env_var == "PWD" {
|
if env_var == "PWD" {
|
||||||
|
9
crates/nu-command/src/env/with_env.rs
vendored
9
crates/nu-command/src/env/with_env.rs
vendored
@ -132,7 +132,14 @@ fn with_env(
|
|||||||
stack.add_env_var(k, v);
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -121,6 +121,8 @@ pub fn test_examples(cmd: impl Command + 'static) {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(Span::test_data()),
|
PipelineData::new(Span::test_data()),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
) {
|
) {
|
||||||
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
|
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
|
@ -68,7 +68,14 @@ impl Command for All {
|
|||||||
stack.add_var(var_id, value);
|
stack.add_var(var_id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_block(&engine_state, &mut stack, block, PipelineData::new(span))
|
eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -67,7 +67,14 @@ impl Command for Any {
|
|||||||
stack.add_var(var_id, value);
|
stack.add_var(var_id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_block(&engine_state, &mut stack, block, PipelineData::new(span))
|
eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -50,6 +50,8 @@ impl Command for Collect {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(call.head),
|
PipelineData::new(call.head),
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -110,6 +110,8 @@ impl Command for Each {
|
|||||||
let orig_env_vars = stack.env_vars.clone();
|
let orig_env_vars = stack.env_vars.clone();
|
||||||
let orig_env_hidden = stack.env_hidden.clone();
|
let orig_env_hidden = stack.env_hidden.clone();
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(Value::Range { .. }, ..)
|
PipelineData::Value(Value::Range { .. }, ..)
|
||||||
@ -143,11 +145,13 @@ impl Command for Each {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match eval_block_with_redirect(
|
match eval_block(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v.into_value(span),
|
Ok(v) => v.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
@ -188,87 +192,34 @@ impl Command for Each {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match eval_block_with_redirect(
|
match eval_block(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v.into_value(span),
|
Ok(v) => v.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.into_pipeline_data(ctrlc)),
|
.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, ..) => {
|
PipelineData::Value(x, ..) => {
|
||||||
//let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
if let Some(var) = block.signature.get_positional(0) {
|
||||||
if let Some(var_id) = &var.var_id {
|
if let Some(var_id) = &var.var_id {
|
||||||
stack.add_var(*var_id, x);
|
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| {
|
.and_then(|x| {
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -69,6 +69,8 @@ impl Command for EachGroup {
|
|||||||
engine_state: engine_state.clone(),
|
engine_state: engine_state.clone(),
|
||||||
stack: stack.clone(),
|
stack: stack.clone(),
|
||||||
group_size: group_size.item,
|
group_size: group_size.item,
|
||||||
|
redirect_stdout: call.redirect_stdout,
|
||||||
|
redirect_stderr: call.redirect_stderr,
|
||||||
input: Box::new(input.into_iter()),
|
input: Box::new(input.into_iter()),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
};
|
};
|
||||||
@ -82,6 +84,8 @@ struct EachGroupIterator {
|
|||||||
engine_state: EngineState,
|
engine_state: EngineState,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
group_size: usize,
|
group_size: usize,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
input: Box<dyn Iterator<Item = Value> + Send>,
|
input: Box<dyn Iterator<Item = Value> + Send>,
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
@ -118,6 +122,8 @@ impl Iterator for EachGroupIterator {
|
|||||||
self.block.clone(),
|
self.block.clone(),
|
||||||
self.engine_state.clone(),
|
self.engine_state.clone(),
|
||||||
self.stack.clone(),
|
self.stack.clone(),
|
||||||
|
self.redirect_stdout,
|
||||||
|
self.redirect_stderr,
|
||||||
self.span,
|
self.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -128,6 +134,8 @@ pub(crate) fn run_block_on_vec(
|
|||||||
capture_block: CaptureBlock,
|
capture_block: CaptureBlock,
|
||||||
engine_state: EngineState,
|
engine_state: EngineState,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let value = Value::List { vals: input, span };
|
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),
|
Ok(pipeline) => pipeline.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
}
|
}
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -108,6 +108,8 @@ impl Command for EachWindow {
|
|||||||
stack: stack.clone(),
|
stack: stack.clone(),
|
||||||
group_size: group_size.item,
|
group_size: group_size.item,
|
||||||
input: Box::new(input.into_iter()),
|
input: Box::new(input.into_iter()),
|
||||||
|
redirect_stdout: call.redirect_stdout,
|
||||||
|
redirect_stderr: call.redirect_stderr,
|
||||||
span: call.head,
|
span: call.head,
|
||||||
previous: vec![],
|
previous: vec![],
|
||||||
stride,
|
stride,
|
||||||
@ -123,6 +125,8 @@ struct EachWindowIterator {
|
|||||||
stack: Stack,
|
stack: Stack,
|
||||||
group_size: usize,
|
group_size: usize,
|
||||||
input: Box<dyn Iterator<Item = Value> + Send>,
|
input: Box<dyn Iterator<Item = Value> + Send>,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
previous: Vec<Value>,
|
previous: Vec<Value>,
|
||||||
stride: usize,
|
stride: usize,
|
||||||
@ -186,6 +190,8 @@ impl Iterator for EachWindowIterator {
|
|||||||
self.block.clone(),
|
self.block.clone(),
|
||||||
self.engine_state.clone(),
|
self.engine_state.clone(),
|
||||||
self.stack.clone(),
|
self.stack.clone(),
|
||||||
|
self.redirect_stdout,
|
||||||
|
self.redirect_stderr,
|
||||||
self.span,
|
self.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -196,6 +202,8 @@ pub(crate) fn run_block_on_vec(
|
|||||||
capture_block: CaptureBlock,
|
capture_block: CaptureBlock,
|
||||||
engine_state: EngineState,
|
engine_state: EngineState,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let value = Value::List { vals: input, span };
|
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),
|
Ok(pipeline) => pipeline.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,14 @@ fn empty(
|
|||||||
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), head))?;
|
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), head))?;
|
||||||
|
|
||||||
let b = engine_state.get_block(block_id);
|
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))
|
Some(evaluated_block.into_value(head))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -93,6 +93,9 @@ impl Command for Find {
|
|||||||
let metadata = input.metadata();
|
let metadata = input.metadata();
|
||||||
let config = stack.get_config()?;
|
let config = stack.get_config()?;
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
match call.get_flag::<CaptureBlock>(&engine_state, stack, "predicate")? {
|
match call.get_flag::<CaptureBlock>(&engine_state, stack, "predicate")? {
|
||||||
Some(predicate) => {
|
Some(predicate) => {
|
||||||
let capture_block = predicate;
|
let capture_block = predicate;
|
||||||
@ -121,6 +124,8 @@ impl Command for Find {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new_with_metadata(metadata.clone(), span),
|
PipelineData::new_with_metadata(metadata.clone(), span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
)
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
|
@ -119,8 +119,14 @@ pub fn group_by(
|
|||||||
if let Some(capture_block) = &block {
|
if let Some(capture_block) = &block {
|
||||||
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
let block = engine_state.get_block(capture_block.block_id);
|
||||||
let pipeline =
|
let pipeline = eval_block(
|
||||||
eval_block(engine_state, &mut stack, block, value.into_pipeline_data());
|
engine_state,
|
||||||
|
&mut stack,
|
||||||
|
block,
|
||||||
|
value.into_pipeline_data(),
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
);
|
||||||
|
|
||||||
match pipeline {
|
match pipeline {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
|
@ -58,6 +58,9 @@ impl Command for KeepUntil {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(move |value| {
|
.take_while(move |value| {
|
||||||
@ -65,7 +68,14 @@ impl Command for KeepUntil {
|
|||||||
stack.add_var(var_id, value.clone());
|
stack.add_var(var_id, value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
!eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))
|
!eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
&block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -58,6 +58,9 @@ impl Command for KeepWhile {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(move |value| {
|
.take_while(move |value| {
|
||||||
@ -65,7 +68,14 @@ impl Command for KeepWhile {
|
|||||||
stack.add_var(var_id, value.clone());
|
stack.add_var(var_id, value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))
|
eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
&block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -82,6 +82,8 @@ impl Command for Merge {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(call.head),
|
PipelineData::new(call.head),
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let table = match result {
|
let table = match result {
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -53,6 +53,8 @@ impl Command for ParEach {
|
|||||||
let block_id = capture_block.block_id;
|
let block_id = capture_block.block_id;
|
||||||
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
let mut stack = stack.captures_to_stack(&capture_block.captures);
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
|
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,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(error) => Value::Error { error }.into_pipeline_data(),
|
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,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(error) => Value::Error { error }.into_pipeline_data(),
|
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,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(error) => Value::Error { error }.into_pipeline_data(),
|
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,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(error) => Value::Error { error }.into_pipeline_data(),
|
Err(error) => Value::Error { error }.into_pipeline_data(),
|
||||||
@ -242,64 +252,6 @@ impl Command for ParEach {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.into_pipeline_data(ctrlc)),
|
.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, ..) => {
|
PipelineData::Value(x, ..) => {
|
||||||
let block = engine_state.get_block(block_id);
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -49,6 +49,8 @@ impl Command for ParEachGroup {
|
|||||||
let capture_block: CaptureBlock = call.req(engine_state, stack, 1)?;
|
let capture_block: CaptureBlock = call.req(engine_state, stack, 1)?;
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let span = call.head;
|
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);
|
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,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
) {
|
) {
|
||||||
Ok(v) => v.into_value(span),
|
Ok(v) => v.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
|
@ -109,6 +109,9 @@ impl Command for Reduce {
|
|||||||
let orig_env_vars = stack.env_vars.clone();
|
let orig_env_vars = stack.env_vars.clone();
|
||||||
let orig_env_hidden = stack.env_hidden.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 mut input_iter = input.into_iter();
|
||||||
|
|
||||||
let (off, start_val) = if let Some(val) = fold {
|
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),
|
Ok(v) => v.into_value(span),
|
||||||
Err(error) => Value::Error { error },
|
Err(error) => Value::Error { error },
|
||||||
};
|
};
|
||||||
|
@ -58,6 +58,9 @@ impl Command for SkipUntil {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.skip_while(move |value| {
|
.skip_while(move |value| {
|
||||||
@ -65,7 +68,14 @@ impl Command for SkipUntil {
|
|||||||
stack.add_var(var_id, value.clone());
|
stack.add_var(var_id, value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
!eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))
|
!eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
&block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -58,6 +58,9 @@ impl Command for SkipWhile {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.skip_while(move |value| {
|
.skip_while(move |value| {
|
||||||
@ -65,7 +68,14 @@ impl Command for SkipWhile {
|
|||||||
stack.add_var(var_id, value.clone());
|
stack.add_var(var_id, value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))
|
eval_block(
|
||||||
|
&engine_state,
|
||||||
|
&mut stack,
|
||||||
|
&block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
)
|
||||||
.map_or(false, |pipeline_data| {
|
.map_or(false, |pipeline_data| {
|
||||||
pipeline_data.into_value(span).is_true()
|
pipeline_data.into_value(span).is_true()
|
||||||
})
|
})
|
||||||
|
@ -70,6 +70,10 @@ fn update(
|
|||||||
|
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let replacement: Value = call.req(engine_state, stack, 1)?;
|
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 engine_state = engine_state.clone();
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
|
||||||
@ -97,6 +101,8 @@ fn update(
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
input.clone().into_pipeline_data(),
|
input.clone().into_pipeline_data(),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
);
|
);
|
||||||
|
|
||||||
match output {
|
match output {
|
||||||
|
@ -132,6 +132,9 @@ impl Command for UpdateCells {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let block: Block = engine_state.get_block(block.block_id).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;
|
let span = call.head;
|
||||||
|
|
||||||
stack.with_env(&orig_env_vars, &orig_env_hidden);
|
stack.with_env(&orig_env_vars, &orig_env_hidden);
|
||||||
@ -156,6 +159,8 @@ impl Command for UpdateCells {
|
|||||||
stack,
|
stack,
|
||||||
block,
|
block,
|
||||||
columns,
|
columns,
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
span,
|
span,
|
||||||
}
|
}
|
||||||
.into_pipeline_data(ctrlc))
|
.into_pipeline_data(ctrlc))
|
||||||
@ -168,6 +173,8 @@ struct UpdateCellIterator {
|
|||||||
engine_state: EngineState,
|
engine_state: EngineState,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
block: Block,
|
block: Block,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +202,8 @@ impl Iterator for UpdateCellIterator {
|
|||||||
&self.engine_state,
|
&self.engine_state,
|
||||||
&mut self.stack,
|
&mut self.stack,
|
||||||
&self.block,
|
&self.block,
|
||||||
|
self.redirect_stdout,
|
||||||
|
self.redirect_stderr,
|
||||||
span,
|
span,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
@ -207,6 +216,8 @@ impl Iterator for UpdateCellIterator {
|
|||||||
&self.engine_state,
|
&self.engine_state,
|
||||||
&mut self.stack,
|
&mut self.stack,
|
||||||
&self.block,
|
&self.block,
|
||||||
|
self.redirect_stdout,
|
||||||
|
self.redirect_stderr,
|
||||||
self.span,
|
self.span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@ -221,6 +232,8 @@ fn process_cell(
|
|||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
if let Some(var) = block.signature.get_positional(0) {
|
||||||
@ -228,7 +241,14 @@ fn process_cell(
|
|||||||
stack.add_var(*var_id, val.clone());
|
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),
|
Ok(pd) => pd.into_value(span),
|
||||||
Err(e) => Value::Error { error: e },
|
Err(e) => Value::Error { error: e },
|
||||||
}
|
}
|
||||||
|
@ -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::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -41,6 +41,9 @@ impl Command for Where {
|
|||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
|
let redirect_stdout = call.redirect_stdout;
|
||||||
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(move |value| {
|
.filter_map(move |value| {
|
||||||
@ -49,11 +52,13 @@ impl Command for Where {
|
|||||||
stack.add_var(*var_id, value.clone());
|
stack.add_var(*var_id, value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = eval_block_with_redirect(
|
let result = eval_block(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
&block,
|
&block,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
);
|
);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
@ -39,6 +39,9 @@ impl Command for Benchmark {
|
|||||||
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
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 mut stack = stack.captures_to_stack(&capture_block.captures);
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
eval_block(
|
eval_block(
|
||||||
@ -46,6 +49,8 @@ impl Command for Benchmark {
|
|||||||
&mut stack,
|
&mut stack,
|
||||||
block,
|
block,
|
||||||
PipelineData::new(call.head),
|
PipelineData::new(call.head),
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
)?
|
)?
|
||||||
.into_value(call.head);
|
.into_value(call.head);
|
||||||
|
|
||||||
|
@ -84,7 +84,8 @@ fn exec(
|
|||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
env_vars,
|
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())?;
|
let mut command = external_command.spawn_simple_command(&cwd.to_string_lossy().to_string())?;
|
||||||
|
@ -36,7 +36,8 @@ impl Command for External {
|
|||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("run-external")
|
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")
|
.rest("rest", SyntaxShape::Any, "external command to run")
|
||||||
.category(Category::System)
|
.category(Category::System)
|
||||||
}
|
}
|
||||||
@ -50,7 +51,8 @@ impl Command for External {
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
let args: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
let args: Vec<Value> = 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
|
// Translate environment variables from Values to Strings
|
||||||
let config = stack.get_config().unwrap_or_default();
|
let config = stack.get_config().unwrap_or_default();
|
||||||
@ -93,7 +95,8 @@ impl Command for External {
|
|||||||
let command = ExternalCommand {
|
let command = ExternalCommand {
|
||||||
name,
|
name,
|
||||||
args: args_strs,
|
args: args_strs,
|
||||||
last_expression,
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
env_vars: env_vars_str,
|
env_vars: env_vars_str,
|
||||||
};
|
};
|
||||||
command.run_with_input(engine_state, stack, input)
|
command.run_with_input(engine_state, stack, input)
|
||||||
@ -103,7 +106,8 @@ impl Command for External {
|
|||||||
pub struct ExternalCommand {
|
pub struct ExternalCommand {
|
||||||
pub name: Spanned<String>,
|
pub name: Spanned<String>,
|
||||||
pub args: Vec<Spanned<String>>,
|
pub args: Vec<Spanned<String>>,
|
||||||
pub last_expression: bool,
|
pub redirect_stdout: bool,
|
||||||
|
pub redirect_stderr: bool,
|
||||||
pub env_vars: HashMap<String, String>,
|
pub env_vars: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +142,14 @@ impl ExternalCommand {
|
|||||||
|
|
||||||
// If the external is not the last command, its output will get piped
|
// If the external is not the last command, its output will get piped
|
||||||
// either as a string or binary
|
// either as a string or binary
|
||||||
if !self.last_expression {
|
if self.redirect_stdout {
|
||||||
process.stdout(Stdio::piped());
|
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
|
// 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
|
// is piped so it can be used to send the input information
|
||||||
if !matches!(input, PipelineData::Value(Value::Nothing { .. }, ..)) {
|
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
|
// If the external is not the last command, its output will get piped
|
||||||
// either as a string or binary
|
// either as a string or binary
|
||||||
if !self.last_expression {
|
if self.redirect_stdout {
|
||||||
process.stdout(Stdio::piped());
|
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
|
// 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
|
// is piped so it can be used to send the input information
|
||||||
if !matches!(input, PipelineData::Value(Value::Nothing { .. }, ..)) {
|
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 span = self.name.span;
|
||||||
let output_ctrlc = ctrlc.clone();
|
let output_ctrlc = ctrlc.clone();
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
@ -249,7 +262,12 @@ impl ExternalCommand {
|
|||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
// If this external is not the last expression, then its output is piped to a channel
|
// 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
|
// 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(|| {
|
let stdout = child.stdout.take().ok_or_else(|| {
|
||||||
ShellError::ExternalCommand(
|
ShellError::ExternalCommand(
|
||||||
"Error taking stdout from external".to_string(),
|
"Error taking stdout from external".to_string(),
|
||||||
|
@ -354,3 +354,15 @@ fn str_reverse() {
|
|||||||
|
|
||||||
assert!(actual.out.contains("llehsun"));
|
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");
|
||||||
|
}
|
||||||
|
@ -55,6 +55,16 @@ fn with_env_and_shorthand_same_result() {
|
|||||||
assert_eq!(actual_shorthand.out, actual_normal.out);
|
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
|
// FIXME: jt: needs more work
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -161,8 +161,14 @@ fn get_converted_value(
|
|||||||
stack.add_var(*var_id, orig_val.clone());
|
stack.add_var(*var_id, orig_val.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let result =
|
let result = eval_block(
|
||||||
eval_block(engine_state, &mut stack, block, PipelineData::new(val_span));
|
engine_state,
|
||||||
|
&mut stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(val_span),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(data) => ConversionResult::Ok(data.into_value(val_span)),
|
Ok(data) => ConversionResult::Ok(data.into_value(val_span)),
|
||||||
|
@ -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 {
|
if block.redirect_env {
|
||||||
let caller_env_vars = caller_stack.get_env_var_names(engine_state);
|
let caller_env_vars = caller_stack.get_env_var_names(engine_state);
|
||||||
@ -169,7 +169,8 @@ fn eval_external(
|
|||||||
head: &Expression,
|
head: &Expression,
|
||||||
args: &[Expression],
|
args: &[Expression],
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
last_expression: bool,
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let decl_id = engine_state
|
let decl_id = engine_state
|
||||||
.find_decl("run-external".as_bytes())
|
.find_decl("run-external".as_bytes())
|
||||||
@ -185,10 +186,20 @@ fn eval_external(
|
|||||||
call.positional.push(arg.clone())
|
call.positional.push(arg.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_expression {
|
if redirect_stdout {
|
||||||
call.named.push((
|
call.named.push((
|
||||||
Spanned {
|
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,
|
span: head.span,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@ -277,6 +288,7 @@ pub fn eval_expression(
|
|||||||
args,
|
args,
|
||||||
PipelineData::new(span),
|
PipelineData::new(span),
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
)?
|
)?
|
||||||
.into_value(span))
|
.into_value(span))
|
||||||
}
|
}
|
||||||
@ -431,20 +443,37 @@ pub fn eval_expression_with_input(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
expr: &Expression,
|
expr: &Expression,
|
||||||
mut input: PipelineData,
|
mut input: PipelineData,
|
||||||
last_expression: bool,
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Call(call),
|
expr: Expr::Call(call),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
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)?;
|
input = eval_call(engine_state, stack, call, input)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::ExternalCall(head, args),
|
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 {
|
Expression {
|
||||||
@ -470,6 +499,8 @@ pub fn eval_block(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
mut input: PipelineData,
|
mut input: PipelineData,
|
||||||
|
redirect_stdout: bool,
|
||||||
|
redirect_stderr: bool,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let num_pipelines = block.len();
|
let num_pipelines = block.len();
|
||||||
for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
|
for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
|
||||||
@ -479,7 +510,8 @@ pub fn eval_block(
|
|||||||
stack,
|
stack,
|
||||||
elem,
|
elem,
|
||||||
input,
|
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)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_block_with_redirect(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
block: &Block,
|
|
||||||
mut input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
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(
|
pub fn eval_subexpression(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
@ -623,7 +583,7 @@ pub fn eval_subexpression(
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
for pipeline in block.pipelines.iter() {
|
for pipeline in block.pipelines.iter() {
|
||||||
for expr in pipeline.expressions.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)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ pub use column::get_columns;
|
|||||||
pub use documentation::{generate_docs, get_brief_help, get_documentation, get_full_help};
|
pub use documentation::{generate_docs, get_brief_help, get_documentation, get_full_help};
|
||||||
pub use env::*;
|
pub use env::*;
|
||||||
pub use eval::{
|
pub use eval::{
|
||||||
eval_block, eval_block_with_redirect, eval_expression, eval_expression_with_input,
|
eval_block, eval_expression, eval_expression_with_input, eval_operator, eval_subexpression,
|
||||||
eval_operator, eval_subexpression,
|
|
||||||
};
|
};
|
||||||
pub use glob_from::glob_from;
|
pub use glob_from::glob_from;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use nu_protocol::ast::Expr;
|
use nu_protocol::ast::Expr;
|
||||||
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
|
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
|
||||||
use nu_protocol::PipelineData;
|
|
||||||
use nu_protocol::{ast::Call, engine::Command, ShellError, Signature};
|
use nu_protocol::{ast::Call, engine::Command, ShellError, Signature};
|
||||||
|
use nu_protocol::{PipelineData, Spanned};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct KnownExternal {
|
pub struct KnownExternal {
|
||||||
@ -61,15 +61,25 @@ impl Command for KnownExternal {
|
|||||||
call.positional.push(arg.clone())
|
call.positional.push(arg.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// if last_expression {
|
if call.redirect_stdout {
|
||||||
// call.named.push((
|
call.named.push((
|
||||||
// Spanned {
|
Spanned {
|
||||||
// item: "last-expression".into(),
|
item: "redirect-stdout".into(),
|
||||||
// span: head.span,
|
span: call_span,
|
||||||
// },
|
},
|
||||||
// None,
|
None,
|
||||||
// ))
|
))
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
if call.redirect_stderr {
|
||||||
|
call.named.push((
|
||||||
|
Spanned {
|
||||||
|
item: "redirect-stderr".into(),
|
||||||
|
span: call_span,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
command.run(engine_state, stack, &call, input)
|
command.run(engine_state, stack, &call, input)
|
||||||
}
|
}
|
||||||
|
@ -579,6 +579,8 @@ pub fn parse_export(
|
|||||||
decl_id: export_decl_id,
|
decl_id: export_decl_id,
|
||||||
positional: vec![],
|
positional: vec![],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let exportable = if let Some(kw_span) = spans.get(1) {
|
let exportable = if let Some(kw_span) = spans.get(1) {
|
||||||
@ -986,6 +988,8 @@ pub fn parse_module(
|
|||||||
decl_id: module_decl_id,
|
decl_id: module_decl_id,
|
||||||
positional: vec![module_name_expr, block_expr],
|
positional: vec![module_name_expr, block_expr],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -1200,6 +1204,8 @@ pub fn parse_use(
|
|||||||
decl_id: use_decl_id,
|
decl_id: use_decl_id,
|
||||||
positional: vec![import_pattern_expr],
|
positional: vec![import_pattern_expr],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -1399,6 +1405,8 @@ pub fn parse_hide(
|
|||||||
decl_id: hide_decl_id,
|
decl_id: hide_decl_id,
|
||||||
positional: vec![import_pattern_expr],
|
positional: vec![import_pattern_expr],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -1480,6 +1488,8 @@ pub fn parse_let(
|
|||||||
head: spans[0],
|
head: spans[0],
|
||||||
positional: vec![lvalue, rvalue],
|
positional: vec![lvalue, rvalue],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -3420,7 +3420,7 @@ pub fn parse_expression(
|
|||||||
(
|
(
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::String(String::new()),
|
expr: Expr::String(String::new()),
|
||||||
span: spans[pos],
|
span: Span { start: 0, end: 0 },
|
||||||
ty: Type::Nothing,
|
ty: Type::Nothing,
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
},
|
},
|
||||||
@ -3556,6 +3556,8 @@ pub fn parse_expression(
|
|||||||
decl_id,
|
decl_id,
|
||||||
named: vec![],
|
named: vec![],
|
||||||
positional,
|
positional,
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -4108,6 +4110,8 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
|||||||
named: vec![],
|
named: vec![],
|
||||||
positional: output,
|
positional: output,
|
||||||
decl_id,
|
decl_id,
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
})),
|
})),
|
||||||
span,
|
span,
|
||||||
ty: Type::String,
|
ty: Type::String,
|
||||||
|
@ -8,6 +8,8 @@ pub struct Call {
|
|||||||
pub head: Span,
|
pub head: Span,
|
||||||
pub positional: Vec<Expression>,
|
pub positional: Vec<Expression>,
|
||||||
pub named: Vec<(Spanned<String>, Option<Expression>)>,
|
pub named: Vec<(Spanned<String>, Option<Expression>)>,
|
||||||
|
pub redirect_stdout: bool,
|
||||||
|
pub redirect_stderr: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Call {
|
impl Call {
|
||||||
@ -17,6 +19,8 @@ impl Call {
|
|||||||
head,
|
head,
|
||||||
positional: vec![],
|
positional: vec![],
|
||||||
named: vec![],
|
named: vec![],
|
||||||
|
redirect_stdout: true,
|
||||||
|
redirect_stderr: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ pub(crate) fn evaluate(
|
|||||||
std::process::exit(1);
|
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) => {
|
Ok(pipeline_data) => {
|
||||||
crate::eval_file::print_table_or_error(engine_state, &mut stack, pipeline_data, &config)
|
crate::eval_file::print_table_or_error(engine_state, &mut stack, pipeline_data, &config)
|
||||||
}
|
}
|
||||||
|
@ -251,3 +251,9 @@ fn with_env_shorthand_nested_quotes() -> TestResult {
|
|||||||
"-arg \"hello world\"",
|
"-arg \"hello world\"",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_redirection_stderr() -> TestResult {
|
||||||
|
// try a nonsense binary
|
||||||
|
run_test(r#"do -i { asdjw4j5cnaabw44rd }; echo done"#, "done")
|
||||||
|
}
|
||||||
|
@ -226,7 +226,7 @@ pub(crate) fn eval_source(
|
|||||||
report_error(&working_set, &err);
|
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) => {
|
Ok(pipeline_data) => {
|
||||||
if let Err(err) = print_pipeline_data(pipeline_data, engine_state, stack) {
|
if let Err(err) = print_pipeline_data(pipeline_data, engine_state, stack) {
|
||||||
let working_set = StateWorkingSet::new(engine_state);
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
Loading…
Reference in New Issue
Block a user