mirror of
https://github.com/nushell/nushell.git
synced 2025-05-24 20:00:47 +02:00
Fix try
not working with let
, etc. (#13885)
# Description Partialy addresses #13868. `try` does not catch non-zero exit code errors from the last command in a pipeline if the result is assigned to a variable using `let` (or `mut`). This was fixed by adding a new `OutDest::Value` case. This is used when the pipeline is in a "value" position. I.e., it will be collected into a value. This ended up replacing most of the usages of `OutDest::Capture`. So, this PR also renames `OutDest::Capture` to `OutDest::PipeSeparate` to better fit the few remaining use cases for it. # User-Facing Changes Bug fix. # Tests + Formatting Added two tests.
This commit is contained in:
parent
2541a712e4
commit
03ee54a4df
@ -25,7 +25,7 @@ impl NuCompleter {
|
|||||||
pub fn new(engine_state: Arc<EngineState>, stack: Arc<Stack>) -> Self {
|
pub fn new(engine_state: Arc<EngineState>, stack: Arc<Stack>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine_state,
|
engine_state,
|
||||||
stack: Stack::with_parent(stack).reset_out_dest().capture(),
|
stack: Stack::with_parent(stack).reset_out_dest().collect_value(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ impl NuMenuCompleter {
|
|||||||
Self {
|
Self {
|
||||||
block_id,
|
block_id,
|
||||||
span,
|
span,
|
||||||
stack: stack.reset_out_dest().capture(),
|
stack: stack.reset_out_dest().collect_value(),
|
||||||
engine_state,
|
engine_state,
|
||||||
only_buffer_difference,
|
only_buffer_difference,
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ pub(crate) fn add_menus(
|
|||||||
|
|
||||||
engine_state.merge_delta(delta)?;
|
engine_state.merge_delta(delta)?;
|
||||||
|
|
||||||
let mut temp_stack = Stack::new().capture();
|
let mut temp_stack = Stack::new().collect_value();
|
||||||
let input = PipelineData::Empty;
|
let input = PipelineData::Empty;
|
||||||
menu_eval_results.push(eval_block::<WithoutDebug>(
|
menu_eval_results.push(eval_block::<WithoutDebug>(
|
||||||
&engine_state,
|
&engine_state,
|
||||||
|
@ -166,7 +166,10 @@ impl Command for Do {
|
|||||||
}
|
}
|
||||||
Ok(PipelineData::ByteStream(mut stream, metadata))
|
Ok(PipelineData::ByteStream(mut stream, metadata))
|
||||||
if ignore_program_errors
|
if ignore_program_errors
|
||||||
&& !matches!(caller_stack.stdout(), OutDest::Pipe | OutDest::Capture) =>
|
&& !matches!(
|
||||||
|
caller_stack.stdout(),
|
||||||
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value
|
||||||
|
) =>
|
||||||
{
|
{
|
||||||
if let ByteStreamSource::Child(child) = stream.source_mut() {
|
if let ByteStreamSource::Child(child) = stream.source_mut() {
|
||||||
child.ignore_error();
|
child.ignore_error();
|
||||||
|
@ -63,7 +63,7 @@ impl Command for Let {
|
|||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
let value = pipeline_data.into_value(call.head)?;
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ impl Command for Mut {
|
|||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
let block = engine_state.get_block(block_id);
|
||||||
let eval_block = get_eval_block(engine_state);
|
let eval_block = get_eval_block(engine_state);
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
let value = pipeline_data.into_value(call.head)?;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ pub fn eval_block(
|
|||||||
cwd: &std::path::Path,
|
cwd: &std::path::Path,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let mut stack = Stack::new().capture();
|
let mut stack = Stack::new().collect_value();
|
||||||
|
|
||||||
stack.add_env_var("PWD".to_string(), Value::test_string(cwd.to_string_lossy()));
|
stack.add_env_var("PWD".to_string(), Value::test_string(cwd.to_string_lossy()));
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ pub fn check_example_evaluates_to_expected_output(
|
|||||||
cwd: &std::path::Path,
|
cwd: &std::path::Path,
|
||||||
engine_state: &mut Box<EngineState>,
|
engine_state: &mut Box<EngineState>,
|
||||||
) {
|
) {
|
||||||
let mut stack = Stack::new().capture();
|
let mut stack = Stack::new().collect_value();
|
||||||
|
|
||||||
// Set up PWD
|
// Set up PWD
|
||||||
stack.add_env_var("PWD".to_string(), Value::test_string(cwd.to_string_lossy()));
|
stack.add_env_var("PWD".to_string(), Value::test_string(cwd.to_string_lossy()));
|
||||||
|
@ -270,7 +270,7 @@ impl Command for Save {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
(Some(OutDest::PipeSeparate), Some(OutDest::PipeSeparate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ use it in your pipeline."#
|
|||||||
let tee_thread = spawn_tee(info.clone(), eval_block)?;
|
let tee_thread = spawn_tee(info.clone(), eval_block)?;
|
||||||
let tee = IoTee::new(stderr, tee_thread);
|
let tee = IoTee::new(stderr, tee_thread);
|
||||||
match stack.stderr() {
|
match stack.stderr() {
|
||||||
OutDest::Pipe | OutDest::Capture => {
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => {
|
||||||
child.stderr = Some(ChildPipe::Tee(Box::new(tee)));
|
child.stderr = Some(ChildPipe::Tee(Box::new(tee)));
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -176,7 +176,7 @@ use it in your pipeline."#
|
|||||||
|
|
||||||
if let Some(stdout) = child.stdout.take() {
|
if let Some(stdout) = child.stdout.take() {
|
||||||
match stack.stdout() {
|
match stack.stdout() {
|
||||||
OutDest::Pipe | OutDest::Capture => {
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => {
|
||||||
child.stdout = Some(stdout);
|
child.stdout = Some(stdout);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ use it in your pipeline."#
|
|||||||
let stderr_thread = if let Some(stderr) = child.stderr.take() {
|
let stderr_thread = if let Some(stderr) = child.stderr.take() {
|
||||||
let info = info.clone();
|
let info = info.clone();
|
||||||
match stack.stderr() {
|
match stack.stderr() {
|
||||||
OutDest::Pipe | OutDest::Capture => {
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => {
|
||||||
child.stderr = Some(stderr);
|
child.stderr = Some(stderr);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ use it in your pipeline."#
|
|||||||
let tee_thread = spawn_tee(info.clone(), eval_block)?;
|
let tee_thread = spawn_tee(info.clone(), eval_block)?;
|
||||||
let tee = IoTee::new(stdout, tee_thread);
|
let tee = IoTee::new(stdout, tee_thread);
|
||||||
match stack.stdout() {
|
match stack.stdout() {
|
||||||
OutDest::Pipe | OutDest::Capture => {
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => {
|
||||||
child.stdout = Some(ChildPipe::Tee(Box::new(tee)));
|
child.stdout = Some(ChildPipe::Tee(Box::new(tee)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ use it in your pipeline."#
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
(Some(OutDest::PipeSeparate), Some(OutDest::PipeSeparate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,6 @@ impl Command for Complete {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
(Some(OutDest::PipeSeparate), Some(OutDest::PipeSeparate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ fn write_pipeline_data(
|
|||||||
} else if let PipelineData::Value(Value::Binary { val, .. }, ..) = data {
|
} else if let PipelineData::Value(Value::Binary { val, .. }, ..) = data {
|
||||||
writer.write_all(&val)?;
|
writer.write_all(&val)?;
|
||||||
} else {
|
} else {
|
||||||
stack.start_capture();
|
stack.start_collect_value();
|
||||||
|
|
||||||
// Turn off color as we pass data through
|
// Turn off color as we pass data through
|
||||||
Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false;
|
Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false;
|
||||||
@ -367,7 +367,7 @@ pub fn command_not_found(
|
|||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
// Run the `command_not_found` hook if there is one.
|
// Run the `command_not_found` hook if there is one.
|
||||||
if let Some(hook) = &stack.get_config(engine_state).hooks.command_not_found {
|
if let Some(hook) = &stack.get_config(engine_state).hooks.command_not_found {
|
||||||
let mut stack = stack.start_capture();
|
let mut stack = stack.start_collect_value();
|
||||||
// Set a special environment variable to avoid infinite loops when the
|
// Set a special environment variable to avoid infinite loops when the
|
||||||
// `command_not_found` hook triggers itself.
|
// `command_not_found` hook triggers itself.
|
||||||
let canary = "ENTERED_COMMAND_NOT_FOUND";
|
let canary = "ENTERED_COMMAND_NOT_FOUND";
|
||||||
|
@ -105,3 +105,15 @@ fn exit_code_available_in_catch() {
|
|||||||
let actual = nu!("try { nu -c 'exit 42' } catch { |e| $e.exit_code }");
|
let actual = nu!("try { nu -c 'exit 42' } catch { |e| $e.exit_code }");
|
||||||
assert_eq!(actual.out, "42");
|
assert_eq!(actual.out, "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_catches_exit_code_in_assignment() {
|
||||||
|
let actual = nu!("let x = try { nu -c 'exit 42' } catch { |e| $e.exit_code }; $x");
|
||||||
|
assert_eq!(actual.out, "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_catches_exit_code_in_expr() {
|
||||||
|
let actual = nu!("print (try { nu -c 'exit 42' } catch { |e| $e.exit_code })");
|
||||||
|
assert_eq!(actual.out, "42");
|
||||||
|
}
|
||||||
|
@ -108,7 +108,7 @@ pub(crate) fn compile_call(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
expr,
|
expr,
|
||||||
RedirectModes::capture_out(arg.span()),
|
RedirectModes::value(arg.span()),
|
||||||
None,
|
None,
|
||||||
arg_reg,
|
arg_reg,
|
||||||
)?;
|
)?;
|
||||||
|
@ -90,7 +90,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
part_expr,
|
part_expr,
|
||||||
RedirectModes::capture_out(part_expr.span),
|
RedirectModes::value(part_expr.span),
|
||||||
None,
|
None,
|
||||||
reg,
|
reg,
|
||||||
)?;
|
)?;
|
||||||
@ -148,7 +148,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
subexpr,
|
subexpr,
|
||||||
RedirectModes::capture_out(subexpr.span),
|
RedirectModes::value(subexpr.span),
|
||||||
None,
|
None,
|
||||||
out_reg,
|
out_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -217,7 +217,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
expr,
|
expr,
|
||||||
RedirectModes::capture_out(expr.span),
|
RedirectModes::value(expr.span),
|
||||||
None,
|
None,
|
||||||
reg,
|
reg,
|
||||||
)?;
|
)?;
|
||||||
@ -265,7 +265,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
column,
|
column,
|
||||||
RedirectModes::capture_out(column.span),
|
RedirectModes::value(column.span),
|
||||||
None,
|
None,
|
||||||
reg,
|
reg,
|
||||||
)?;
|
)?;
|
||||||
@ -290,7 +290,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
item,
|
item,
|
||||||
RedirectModes::capture_out(item.span),
|
RedirectModes::value(item.span),
|
||||||
None,
|
None,
|
||||||
item_reg,
|
item_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -337,7 +337,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
key,
|
key,
|
||||||
RedirectModes::capture_out(key.span),
|
RedirectModes::value(key.span),
|
||||||
None,
|
None,
|
||||||
key_reg,
|
key_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -345,7 +345,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
val,
|
val,
|
||||||
RedirectModes::capture_out(val.span),
|
RedirectModes::value(val.span),
|
||||||
None,
|
None,
|
||||||
val_reg,
|
val_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -365,7 +365,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
expr,
|
expr,
|
||||||
RedirectModes::capture_out(expr.span),
|
RedirectModes::value(expr.span),
|
||||||
None,
|
None,
|
||||||
reg,
|
reg,
|
||||||
)?;
|
)?;
|
||||||
@ -449,7 +449,7 @@ pub(crate) fn compile_expression(
|
|||||||
// general, which shouldn't be captured any differently than they otherwise
|
// general, which shouldn't be captured any differently than they otherwise
|
||||||
// would be.
|
// would be.
|
||||||
if !full_cell_path.tail.is_empty() {
|
if !full_cell_path.tail.is_empty() {
|
||||||
RedirectModes::capture_out(expr.span)
|
RedirectModes::value(expr.span)
|
||||||
} else {
|
} else {
|
||||||
redirect_modes
|
redirect_modes
|
||||||
},
|
},
|
||||||
@ -491,7 +491,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
exprs_iter.next().expect("peek() was Some"),
|
exprs_iter.next().expect("peek() was Some"),
|
||||||
RedirectModes::capture_out(expr.span),
|
RedirectModes::value(expr.span),
|
||||||
None,
|
None,
|
||||||
out_reg,
|
out_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -507,7 +507,7 @@ pub(crate) fn compile_expression(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
expr,
|
expr,
|
||||||
RedirectModes::capture_out(expr.span),
|
RedirectModes::value(expr.span),
|
||||||
None,
|
None,
|
||||||
scratch_reg,
|
scratch_reg,
|
||||||
)?;
|
)?;
|
||||||
|
@ -47,7 +47,7 @@ pub(crate) fn compile_if(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
condition,
|
condition,
|
||||||
RedirectModes::capture_out(condition.span),
|
RedirectModes::value(condition.span),
|
||||||
None,
|
None,
|
||||||
condition_reg,
|
condition_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -181,7 +181,7 @@ pub(crate) fn compile_match(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
match_expr,
|
match_expr,
|
||||||
RedirectModes::capture_out(match_expr.span),
|
RedirectModes::value(match_expr.span),
|
||||||
None,
|
None,
|
||||||
match_reg,
|
match_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -233,7 +233,7 @@ pub(crate) fn compile_match(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
guard,
|
guard,
|
||||||
RedirectModes::capture_out(guard.span),
|
RedirectModes::value(guard.span),
|
||||||
None,
|
None,
|
||||||
guard_reg,
|
guard_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -319,7 +319,7 @@ pub(crate) fn compile_let(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
block,
|
block,
|
||||||
RedirectModes::capture_out(call.head),
|
RedirectModes::value(call.head),
|
||||||
Some(io_reg),
|
Some(io_reg),
|
||||||
io_reg,
|
io_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -427,7 +427,7 @@ pub(crate) fn compile_try(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
catch_expr,
|
catch_expr,
|
||||||
RedirectModes::capture_out(catch_expr.span),
|
RedirectModes::value(catch_expr.span),
|
||||||
None,
|
None,
|
||||||
closure_reg,
|
closure_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -655,7 +655,7 @@ pub(crate) fn compile_while(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
cond_arg,
|
cond_arg,
|
||||||
RedirectModes::capture_out(call.head),
|
RedirectModes::value(call.head),
|
||||||
None,
|
None,
|
||||||
io_reg,
|
io_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -739,7 +739,7 @@ pub(crate) fn compile_for(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
in_expr,
|
in_expr,
|
||||||
RedirectModes::capture_out(in_expr.span),
|
RedirectModes::value(in_expr.span),
|
||||||
None,
|
None,
|
||||||
stream_reg,
|
stream_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -867,7 +867,7 @@ pub(crate) fn compile_return(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
arg_expr,
|
arg_expr,
|
||||||
RedirectModes::capture_out(arg_expr.span),
|
RedirectModes::value(arg_expr.span),
|
||||||
None,
|
None,
|
||||||
io_reg,
|
io_reg,
|
||||||
)?;
|
)?;
|
||||||
|
@ -35,7 +35,7 @@ pub(crate) fn compile_binary_op(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
rhs,
|
rhs,
|
||||||
RedirectModes::capture_out(rhs.span),
|
RedirectModes::value(rhs.span),
|
||||||
None,
|
None,
|
||||||
out_reg,
|
out_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -53,7 +53,7 @@ pub(crate) fn compile_binary_op(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
lhs,
|
lhs,
|
||||||
RedirectModes::capture_out(lhs.span),
|
RedirectModes::value(lhs.span),
|
||||||
None,
|
None,
|
||||||
lhs_reg,
|
lhs_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -73,7 +73,7 @@ pub(crate) fn compile_binary_op(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
rhs,
|
rhs,
|
||||||
RedirectModes::capture_out(rhs.span),
|
RedirectModes::value(rhs.span),
|
||||||
None,
|
None,
|
||||||
lhs_reg,
|
lhs_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -96,7 +96,7 @@ pub(crate) fn compile_binary_op(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
rhs,
|
rhs,
|
||||||
RedirectModes::capture_out(rhs.span),
|
RedirectModes::value(rhs.span),
|
||||||
None,
|
None,
|
||||||
lhs_reg,
|
lhs_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -118,7 +118,7 @@ pub(crate) fn compile_binary_op(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
rhs,
|
rhs,
|
||||||
RedirectModes::capture_out(rhs.span),
|
RedirectModes::value(rhs.span),
|
||||||
None,
|
None,
|
||||||
rhs_reg,
|
rhs_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -277,7 +277,7 @@ pub(crate) fn compile_assignment(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
&path.head,
|
&path.head,
|
||||||
RedirectModes::capture_out(path.head.span),
|
RedirectModes::value(path.head.span),
|
||||||
None,
|
None,
|
||||||
head_reg,
|
head_reg,
|
||||||
)?;
|
)?;
|
||||||
|
@ -14,9 +14,9 @@ pub(crate) struct RedirectModes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RedirectModes {
|
impl RedirectModes {
|
||||||
pub(crate) fn capture_out(span: Span) -> Self {
|
pub(crate) fn value(span: Span) -> Self {
|
||||||
RedirectModes {
|
RedirectModes {
|
||||||
out: Some(RedirectMode::Capture.into_spanned(span)),
|
out: Some(RedirectMode::Value.into_spanned(span)),
|
||||||
err: None,
|
err: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ pub(crate) fn redirection_target_to_mode(
|
|||||||
working_set,
|
working_set,
|
||||||
builder,
|
builder,
|
||||||
expr,
|
expr,
|
||||||
RedirectModes::capture_out(*redir_span),
|
RedirectModes::value(*redir_span),
|
||||||
None,
|
None,
|
||||||
path_reg,
|
path_reg,
|
||||||
)?;
|
)?;
|
||||||
@ -148,7 +148,8 @@ pub(crate) fn out_dest_to_redirect_mode(
|
|||||||
out_dest
|
out_dest
|
||||||
.map(|out_dest| match out_dest {
|
.map(|out_dest| match out_dest {
|
||||||
OutDest::Pipe => Ok(RedirectMode::Pipe),
|
OutDest::Pipe => Ok(RedirectMode::Pipe),
|
||||||
OutDest::Capture => Ok(RedirectMode::Capture),
|
OutDest::PipeSeparate => Ok(RedirectMode::PipeSeparate),
|
||||||
|
OutDest::Value => Ok(RedirectMode::Value),
|
||||||
OutDest::Null => Ok(RedirectMode::Null),
|
OutDest::Null => Ok(RedirectMode::Null),
|
||||||
OutDest::Inherit => Ok(RedirectMode::Inherit),
|
OutDest::Inherit => Ok(RedirectMode::Inherit),
|
||||||
OutDest::File(_) => Err(CompileError::InvalidRedirectMode { span }),
|
OutDest::File(_) => Err(CompileError::InvalidRedirectMode { span }),
|
||||||
|
@ -23,7 +23,7 @@ pub fn get_full_help(
|
|||||||
// internally call several commands (`table`, `ansi`, `nu-highlight`) and get their
|
// internally call several commands (`table`, `ansi`, `nu-highlight`) and get their
|
||||||
// `PipelineData` using this `Stack`, any other output should not be redirected like the main
|
// `PipelineData` using this `Stack`, any other output should not be redirected like the main
|
||||||
// execution.
|
// execution.
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
|
|
||||||
let signature = engine_state
|
let signature = engine_state
|
||||||
.get_signature(command)
|
.get_signature(command)
|
||||||
@ -202,7 +202,7 @@ fn get_documentation(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let caller_stack = &mut Stack::new().capture();
|
let caller_stack = &mut Stack::new().collect_value();
|
||||||
if let Ok(result) = eval_call::<WithoutDebug>(
|
if let Ok(result) = eval_call::<WithoutDebug>(
|
||||||
engine_state,
|
engine_state,
|
||||||
caller_stack,
|
caller_stack,
|
||||||
@ -329,7 +329,7 @@ fn update_ansi_from_config(
|
|||||||
theme_component: &str,
|
theme_component: &str,
|
||||||
) {
|
) {
|
||||||
if let Some(color) = &nu_config.color_config.get(theme_component) {
|
if let Some(color) = &nu_config.color_config.get(theme_component) {
|
||||||
let caller_stack = &mut Stack::new().capture();
|
let caller_stack = &mut Stack::new().collect_value();
|
||||||
let span = Span::unknown();
|
let span = Span::unknown();
|
||||||
let span_id = UNKNOWN_SPAN_ID;
|
let span_id = UNKNOWN_SPAN_ID;
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ pub fn eval_expression<D: DebugContext>(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
expr: &Expression,
|
expr: &Expression,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
<EvalRuntime as Eval>::eval::<D>(engine_state, stack, expr)
|
<EvalRuntime as Eval>::eval::<D>(engine_state, stack, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ pub fn eval_expression_with_input<D: DebugContext>(
|
|||||||
let block = engine_state.get_block(*block_id);
|
let block = engine_state.get_block(*block_id);
|
||||||
|
|
||||||
if !full_cell_path.tail.is_empty() {
|
if !full_cell_path.tail.is_empty() {
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
// FIXME: protect this collect with ctrl-c
|
// FIXME: protect this collect with ctrl-c
|
||||||
input = eval_subexpression::<D>(engine_state, stack, block, input)?
|
input = eval_subexpression::<D>(engine_state, stack, block, input)?
|
||||||
.into_value(*span)?
|
.into_value(*span)?
|
||||||
@ -325,7 +325,7 @@ fn eval_redirection<D: DebugContext>(
|
|||||||
}
|
}
|
||||||
RedirectionTarget::Pipe { .. } => {
|
RedirectionTarget::Pipe { .. } => {
|
||||||
let dest = match next_out {
|
let dest = match next_out {
|
||||||
None | Some(OutDest::Capture) => OutDest::Pipe,
|
None | Some(OutDest::PipeSeparate) => OutDest::Pipe,
|
||||||
Some(next) => next,
|
Some(next) => next,
|
||||||
};
|
};
|
||||||
Ok(Redirection::Pipe(dest))
|
Ok(Redirection::Pipe(dest))
|
||||||
@ -357,7 +357,7 @@ fn eval_element_redirection<D: DebugContext>(
|
|||||||
let stderr = eval_redirection::<D>(engine_state, stack, target, None)?;
|
let stderr = eval_redirection::<D>(engine_state, stack, target, None)?;
|
||||||
if matches!(stderr, Redirection::Pipe(OutDest::Pipe)) {
|
if matches!(stderr, Redirection::Pipe(OutDest::Pipe)) {
|
||||||
let dest = match next_out {
|
let dest = match next_out {
|
||||||
None | Some(OutDest::Capture) => OutDest::Pipe,
|
None | Some(OutDest::PipeSeparate) => OutDest::Pipe,
|
||||||
Some(next) => next,
|
Some(next) => next,
|
||||||
};
|
};
|
||||||
// e>| redirection, don't override current stack `stdout`
|
// e>| redirection, don't override current stack `stdout`
|
||||||
|
@ -1414,7 +1414,8 @@ fn eval_redirection(
|
|||||||
) -> Result<Option<Redirection>, ShellError> {
|
) -> Result<Option<Redirection>, ShellError> {
|
||||||
match mode {
|
match mode {
|
||||||
RedirectMode::Pipe => Ok(Some(Redirection::Pipe(OutDest::Pipe))),
|
RedirectMode::Pipe => Ok(Some(Redirection::Pipe(OutDest::Pipe))),
|
||||||
RedirectMode::Capture => Ok(Some(Redirection::Pipe(OutDest::Capture))),
|
RedirectMode::PipeSeparate => Ok(Some(Redirection::Pipe(OutDest::PipeSeparate))),
|
||||||
|
RedirectMode::Value => Ok(Some(Redirection::Pipe(OutDest::Value))),
|
||||||
RedirectMode::Null => Ok(Some(Redirection::Pipe(OutDest::Null))),
|
RedirectMode::Null => Ok(Some(Redirection::Pipe(OutDest::Null))),
|
||||||
RedirectMode::Inherit => Ok(Some(Redirection::Pipe(OutDest::Inherit))),
|
RedirectMode::Inherit => Ok(Some(Redirection::Pipe(OutDest::Inherit))),
|
||||||
RedirectMode::File { file_num } => {
|
RedirectMode::File { file_num } => {
|
||||||
|
@ -96,8 +96,8 @@ fn eval_source2(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(
|
let stack = &mut stack.push_redirection(
|
||||||
Some(Redirection::Pipe(OutDest::Capture)),
|
Some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
Some(Redirection::Pipe(OutDest::Capture)),
|
Some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
);
|
);
|
||||||
eval_block::<WithoutDebug>(engine_state, stack, &block, input)
|
eval_block::<WithoutDebug>(engine_state, stack, &block, input)
|
||||||
}
|
}
|
||||||
|
@ -190,8 +190,8 @@ impl<'a> PluginExecutionContext for PluginExecutionCommandContext<'a> {
|
|||||||
.reset_pipes();
|
.reset_pipes();
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(
|
let stack = &mut stack.push_redirection(
|
||||||
redirect_stdout.then_some(Redirection::Pipe(OutDest::Capture)),
|
redirect_stdout.then_some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
redirect_stderr.then_some(Redirection::Pipe(OutDest::Capture)),
|
redirect_stderr.then_some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set up the positional arguments
|
// Set up the positional arguments
|
||||||
@ -239,8 +239,8 @@ impl<'a> PluginExecutionContext for PluginExecutionCommandContext<'a> {
|
|||||||
let decl = self.engine_state.get_decl(decl_id);
|
let decl = self.engine_state.get_decl(decl_id);
|
||||||
|
|
||||||
let stack = &mut self.stack.push_redirection(
|
let stack = &mut self.stack.push_redirection(
|
||||||
redirect_stdout.then_some(Redirection::Pipe(OutDest::Capture)),
|
redirect_stdout.then_some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
redirect_stderr.then_some(Redirection::Pipe(OutDest::Capture)),
|
redirect_stderr.then_some(Redirection::Pipe(OutDest::PipeSeparate)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut call_builder = ir::Call::build(decl_id, call.head);
|
let mut call_builder = ir::Call::build(decl_id, call.head);
|
||||||
|
@ -353,7 +353,7 @@ impl GetPlugin for PersistentPlugin {
|
|||||||
// We need the current environment variables for `python` based plugins. Or
|
// We need the current environment variables for `python` based plugins. Or
|
||||||
// we'll likely have a problem when a plugin is implemented in a virtual Python
|
// we'll likely have a problem when a plugin is implemented in a virtual Python
|
||||||
// environment.
|
// environment.
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
nu_engine::env::env_to_strings(engine_state, stack)
|
nu_engine::env::env_to_strings(engine_state, stack)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
@ -156,7 +156,7 @@ impl PluginTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Eval the block with the input
|
// Eval the block with the input
|
||||||
let mut stack = Stack::new().capture();
|
let mut stack = Stack::new().collect_value();
|
||||||
let data = eval_block::<WithoutDebug>(&self.engine_state, &mut stack, &block, input)?;
|
let data = eval_block::<WithoutDebug>(&self.engine_state, &mut stack, &block, input)?;
|
||||||
if matches!(data, PipelineData::ByteStream(..)) {
|
if matches!(data, PipelineData::ByteStream(..)) {
|
||||||
Ok(data)
|
Ok(data)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
engine::{
|
engine::{
|
||||||
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
|
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
|
||||||
StackCaptureGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME,
|
StackCollectValueGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME,
|
||||||
},
|
},
|
||||||
Config, OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID,
|
Config, OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
@ -68,7 +68,7 @@ impl Stack {
|
|||||||
/// stdout and stderr will be set to [`OutDest::Inherit`]. So, if the last command is an external command,
|
/// stdout and stderr will be set to [`OutDest::Inherit`]. So, if the last command is an external command,
|
||||||
/// then its output will be forwarded to the terminal/stdio streams.
|
/// then its output will be forwarded to the terminal/stdio streams.
|
||||||
///
|
///
|
||||||
/// Use [`Stack::capture`] afterwards if you need to evaluate an expression to a [`Value`]
|
/// Use [`Stack::collect_value`] afterwards if you need to evaluate an expression to a [`Value`]
|
||||||
/// (as opposed to a [`PipelineData`](crate::PipelineData)).
|
/// (as opposed to a [`PipelineData`](crate::PipelineData)).
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -299,7 +299,8 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn captures_to_stack(&self, captures: Vec<(VarId, Value)>) -> Stack {
|
pub fn captures_to_stack(&self, captures: Vec<(VarId, Value)>) -> Stack {
|
||||||
self.captures_to_stack_preserve_out_dest(captures).capture()
|
self.captures_to_stack_preserve_out_dest(captures)
|
||||||
|
.collect_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn captures_to_stack_preserve_out_dest(&self, captures: Vec<(VarId, Value)>) -> Stack {
|
pub fn captures_to_stack_preserve_out_dest(&self, captures: Vec<(VarId, Value)>) -> Stack {
|
||||||
@ -589,11 +590,11 @@ impl Stack {
|
|||||||
self.out_dest.pipe_stderr.as_ref()
|
self.out_dest.pipe_stderr.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily set the pipe stdout redirection to [`OutDest::Capture`].
|
/// Temporarily set the pipe stdout redirection to [`OutDest::Value`].
|
||||||
///
|
///
|
||||||
/// This is used before evaluating an expression into a `Value`.
|
/// This is used before evaluating an expression into a `Value`.
|
||||||
pub fn start_capture(&mut self) -> StackCaptureGuard {
|
pub fn start_collect_value(&mut self) -> StackCollectValueGuard {
|
||||||
StackCaptureGuard::new(self)
|
StackCollectValueGuard::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily use the output redirections in the parent scope.
|
/// Temporarily use the output redirections in the parent scope.
|
||||||
@ -612,14 +613,14 @@ impl Stack {
|
|||||||
StackIoGuard::new(self, stdout, stderr)
|
StackIoGuard::new(self, stdout, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark stdout for the last command as [`OutDest::Capture`].
|
/// Mark stdout for the last command as [`OutDest::Value`].
|
||||||
///
|
///
|
||||||
/// This will irreversibly alter the output redirections, and so it only makes sense to use this on an owned `Stack`
|
/// This will irreversibly alter the output redirections, and so it only makes sense to use this on an owned `Stack`
|
||||||
/// (which is why this function does not take `&mut self`).
|
/// (which is why this function does not take `&mut self`).
|
||||||
///
|
///
|
||||||
/// See [`Stack::start_capture`] which can temporarily set stdout as [`OutDest::Capture`] for a mutable `Stack` reference.
|
/// See [`Stack::start_collect_value`] which can temporarily set stdout as [`OutDest::Value`] for a mutable `Stack` reference.
|
||||||
pub fn capture(mut self) -> Self {
|
pub fn collect_value(mut self) -> Self {
|
||||||
self.out_dest.pipe_stdout = Some(OutDest::Capture);
|
self.out_dest.pipe_stdout = Some(OutDest::Value);
|
||||||
self.out_dest.pipe_stderr = None;
|
self.out_dest.pipe_stderr = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -184,15 +184,15 @@ impl Drop for StackIoGuard<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StackCaptureGuard<'a> {
|
pub struct StackCollectValueGuard<'a> {
|
||||||
stack: &'a mut Stack,
|
stack: &'a mut Stack,
|
||||||
old_pipe_stdout: Option<OutDest>,
|
old_pipe_stdout: Option<OutDest>,
|
||||||
old_pipe_stderr: Option<OutDest>,
|
old_pipe_stderr: Option<OutDest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StackCaptureGuard<'a> {
|
impl<'a> StackCollectValueGuard<'a> {
|
||||||
pub(crate) fn new(stack: &'a mut Stack) -> Self {
|
pub(crate) fn new(stack: &'a mut Stack) -> Self {
|
||||||
let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Capture));
|
let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Value));
|
||||||
let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
|
let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
|
||||||
Self {
|
Self {
|
||||||
stack,
|
stack,
|
||||||
@ -202,7 +202,7 @@ impl<'a> StackCaptureGuard<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for StackCaptureGuard<'a> {
|
impl<'a> Deref for StackCollectValueGuard<'a> {
|
||||||
type Target = Stack;
|
type Target = Stack;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -210,13 +210,13 @@ impl<'a> Deref for StackCaptureGuard<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DerefMut for StackCaptureGuard<'a> {
|
impl<'a> DerefMut for StackCollectValueGuard<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.stack
|
self.stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for StackCaptureGuard<'_> {
|
impl Drop for StackCollectValueGuard<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.out_dest.pipe_stdout = self.old_pipe_stdout.take();
|
self.out_dest.pipe_stdout = self.old_pipe_stdout.take();
|
||||||
self.out_dest.pipe_stderr = self.old_pipe_stderr.take();
|
self.out_dest.pipe_stderr = self.old_pipe_stderr.take();
|
||||||
@ -233,7 +233,7 @@ pub struct StackCallArgGuard<'a> {
|
|||||||
|
|
||||||
impl<'a> StackCallArgGuard<'a> {
|
impl<'a> StackCallArgGuard<'a> {
|
||||||
pub(crate) fn new(stack: &'a mut Stack) -> Self {
|
pub(crate) fn new(stack: &'a mut Stack) -> Self {
|
||||||
let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Capture));
|
let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Value));
|
||||||
let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
|
let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
|
||||||
|
|
||||||
let old_stdout = stack
|
let old_stdout = stack
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::fmt;
|
|
||||||
|
|
||||||
use crate::{ast::Pattern, engine::EngineState, DeclId, VarId};
|
|
||||||
|
|
||||||
use super::{DataSlice, Instruction, IrBlock, Literal, RedirectMode};
|
use super::{DataSlice, Instruction, IrBlock, Literal, RedirectMode};
|
||||||
|
use crate::{ast::Pattern, engine::EngineState, DeclId, VarId};
|
||||||
|
use std::fmt::{self};
|
||||||
|
|
||||||
pub struct FmtIrBlock<'a> {
|
pub struct FmtIrBlock<'a> {
|
||||||
pub(super) engine_state: &'a EngineState,
|
pub(super) engine_state: &'a EngineState,
|
||||||
@ -310,7 +308,8 @@ impl fmt::Display for RedirectMode {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RedirectMode::Pipe => write!(f, "pipe"),
|
RedirectMode::Pipe => write!(f, "pipe"),
|
||||||
RedirectMode::Capture => write!(f, "capture"),
|
RedirectMode::PipeSeparate => write!(f, "pipe separate"),
|
||||||
|
RedirectMode::Value => write!(f, "value"),
|
||||||
RedirectMode::Null => write!(f, "null"),
|
RedirectMode::Null => write!(f, "null"),
|
||||||
RedirectMode::Inherit => write!(f, "inherit"),
|
RedirectMode::Inherit => write!(f, "inherit"),
|
||||||
RedirectMode::File { file_num } => write!(f, "file({file_num})"),
|
RedirectMode::File { file_num } => write!(f, "file({file_num})"),
|
||||||
|
@ -446,7 +446,8 @@ pub enum Literal {
|
|||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub enum RedirectMode {
|
pub enum RedirectMode {
|
||||||
Pipe,
|
Pipe,
|
||||||
Capture,
|
PipeSeparate,
|
||||||
|
Value,
|
||||||
Null,
|
Null,
|
||||||
Inherit,
|
Inherit,
|
||||||
/// Use the given numbered file.
|
/// Use the given numbered file.
|
||||||
|
@ -580,8 +580,8 @@ impl ByteStream {
|
|||||||
copy_with_signals(file, dest, span, signals)?;
|
copy_with_signals(file, dest, span, signals)?;
|
||||||
}
|
}
|
||||||
ByteStreamSource::Child(mut child) => {
|
ByteStreamSource::Child(mut child) => {
|
||||||
// All `OutDest`s except `OutDest::Capture` will cause `stderr` to be `None`.
|
// All `OutDest`s except `OutDest::PipeSeparate` will cause `stderr` to be `None`.
|
||||||
// Only `save`, `tee`, and `complete` set the stderr `OutDest` to `OutDest::Capture`,
|
// Only `save`, `tee`, and `complete` set the stderr `OutDest` to `OutDest::PipeSeparate`,
|
||||||
// and those commands have proper simultaneous handling of stdout and stderr.
|
// and those commands have proper simultaneous handling of stdout and stderr.
|
||||||
debug_assert!(child.stderr.is_none(), "stderr should not exist");
|
debug_assert!(child.stderr.is_none(), "stderr should not exist");
|
||||||
|
|
||||||
@ -614,7 +614,7 @@ impl ByteStream {
|
|||||||
write_to_out_dest(read, stdout, true, span, signals)?;
|
write_to_out_dest(read, stdout, true, span, signals)?;
|
||||||
}
|
}
|
||||||
ByteStreamSource::File(file) => match stdout {
|
ByteStreamSource::File(file) => match stdout {
|
||||||
OutDest::Pipe | OutDest::Capture | OutDest::Null => {}
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value | OutDest::Null => {}
|
||||||
OutDest::Inherit => {
|
OutDest::Inherit => {
|
||||||
copy_with_signals(file, io::stdout(), span, signals)?;
|
copy_with_signals(file, io::stdout(), span, signals)?;
|
||||||
}
|
}
|
||||||
@ -970,7 +970,7 @@ fn write_to_out_dest(
|
|||||||
signals: &Signals,
|
signals: &Signals,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
match stream {
|
match stream {
|
||||||
OutDest::Pipe | OutDest::Capture => return Ok(()),
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => return Ok(()),
|
||||||
OutDest::Null => copy_with_signals(read, io::sink(), span, signals),
|
OutDest::Null => copy_with_signals(read, io::sink(), span, signals),
|
||||||
OutDest::Inherit if stdout => copy_with_signals(read, io::stdout(), span, signals),
|
OutDest::Inherit if stdout => copy_with_signals(read, io::stdout(), span, signals),
|
||||||
OutDest::Inherit => copy_with_signals(read, io::stderr(), span, signals),
|
OutDest::Inherit => copy_with_signals(read, io::stderr(), span, signals),
|
||||||
|
@ -10,13 +10,17 @@ pub enum OutDest {
|
|||||||
/// If stdout and stderr are both set to `Pipe`,
|
/// If stdout and stderr are both set to `Pipe`,
|
||||||
/// then they will combined into the `stdout` of [`ChildProcess`](crate::process::ChildProcess).
|
/// then they will combined into the `stdout` of [`ChildProcess`](crate::process::ChildProcess).
|
||||||
Pipe,
|
Pipe,
|
||||||
/// Capture output to later be collected into a [`Value`](crate::Value), `Vec`, or used in some other way.
|
/// Redirect the stdout and/or stderr of one command as the input for the next command in the pipeline.
|
||||||
///
|
///
|
||||||
/// The output stream(s) will be available in the `stdout` or `stderr` of [`ChildProcess`](crate::process::ChildProcess).
|
/// The output stream(s) will be available in the `stdout` or `stderr` of [`ChildProcess`](crate::process::ChildProcess).
|
||||||
///
|
///
|
||||||
/// This is similar to `Pipe` but will never combine stdout and stderr
|
/// This is similar to `Pipe` but will never combine stdout and stderr
|
||||||
/// or place an external command's stderr into `stdout` of [`ChildProcess`](crate::process::ChildProcess).
|
/// or place an external command's stderr into `stdout` of [`ChildProcess`](crate::process::ChildProcess).
|
||||||
Capture,
|
PipeSeparate,
|
||||||
|
/// Signifies the result of the pipeline will be immediately collected into a value after this command.
|
||||||
|
///
|
||||||
|
/// So, it is fine to collect the stream ahead of time in the current command.
|
||||||
|
Value,
|
||||||
/// Ignore output.
|
/// Ignore output.
|
||||||
///
|
///
|
||||||
/// This will forward output to the null device for the platform.
|
/// This will forward output to the null device for the platform.
|
||||||
@ -46,7 +50,7 @@ impl TryFrom<&OutDest> for Stdio {
|
|||||||
|
|
||||||
fn try_from(out_dest: &OutDest) -> Result<Self, Self::Error> {
|
fn try_from(out_dest: &OutDest) -> Result<Self, Self::Error> {
|
||||||
match out_dest {
|
match out_dest {
|
||||||
OutDest::Pipe | OutDest::Capture => Ok(Self::piped()),
|
OutDest::Pipe | OutDest::PipeSeparate | OutDest::Value => Ok(Self::piped()),
|
||||||
OutDest::Null => Ok(Self::null()),
|
OutDest::Null => Ok(Self::null()),
|
||||||
OutDest::Inherit => Ok(Self::inherit()),
|
OutDest::Inherit => Ok(Self::inherit()),
|
||||||
OutDest::File(file) => Ok(file.try_clone()?.into()),
|
OutDest::File(file) => Ok(file.try_clone()?.into()),
|
||||||
|
@ -167,8 +167,8 @@ impl PipelineData {
|
|||||||
|
|
||||||
/// Writes all values or redirects all output to the current [`OutDest`]s in `stack`.
|
/// Writes all values or redirects all output to the current [`OutDest`]s in `stack`.
|
||||||
///
|
///
|
||||||
/// For [`OutDest::Pipe`] and [`OutDest::Capture`], this will return the `PipelineData` as is
|
/// For [`OutDest::Pipe`] and [`OutDest::PipeSeparate`], this will return the `PipelineData` as
|
||||||
/// without consuming input and without writing anything.
|
/// is without consuming input and without writing anything.
|
||||||
///
|
///
|
||||||
/// For the other [`OutDest`]s, the given `PipelineData` will be completely consumed
|
/// For the other [`OutDest`]s, the given `PipelineData` will be completely consumed
|
||||||
/// and `PipelineData::Empty` will be returned (assuming no errors).
|
/// and `PipelineData::Empty` will be returned (assuming no errors).
|
||||||
@ -178,11 +178,18 @@ impl PipelineData {
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
match (self, stack.stdout()) {
|
match (self, stack.stdout()) {
|
||||||
(data, OutDest::Pipe | OutDest::Capture) => return Ok(data),
|
(PipelineData::Empty, ..) => {}
|
||||||
|
(data, OutDest::Pipe | OutDest::PipeSeparate) => return Ok(data),
|
||||||
|
(data, OutDest::Value) => {
|
||||||
|
let metadata = data.metadata();
|
||||||
|
let span = data.span().unwrap_or(Span::unknown());
|
||||||
|
return data
|
||||||
|
.into_value(span)
|
||||||
|
.map(|val| PipelineData::Value(val, metadata));
|
||||||
|
}
|
||||||
(PipelineData::ByteStream(stream, ..), stdout) => {
|
(PipelineData::ByteStream(stream, ..), stdout) => {
|
||||||
stream.write_to_out_dests(stdout, stack.stderr())?;
|
stream.write_to_out_dests(stdout, stack.stderr())?;
|
||||||
}
|
}
|
||||||
(PipelineData::Empty, ..) => {}
|
|
||||||
(PipelineData::Value(..), OutDest::Null) => {}
|
(PipelineData::Value(..), OutDest::Null) => {}
|
||||||
(PipelineData::ListStream(stream, ..), OutDest::Null) => {
|
(PipelineData::ListStream(stream, ..), OutDest::Null) => {
|
||||||
// we need to drain the stream in case there are external commands in the pipeline
|
// we need to drain the stream in case there are external commands in the pipeline
|
||||||
|
@ -337,7 +337,7 @@ pub fn nu_repl() {
|
|||||||
let config = engine_state.get_config();
|
let config = engine_state.get_config();
|
||||||
|
|
||||||
{
|
{
|
||||||
let stack = &mut stack.start_capture();
|
let stack = &mut stack.start_collect_value();
|
||||||
match eval_block::<WithoutDebug>(&engine_state, stack, &block, input) {
|
match eval_block::<WithoutDebug>(&engine_state, stack, &block, input) {
|
||||||
Ok(pipeline_data) => match pipeline_data.collect_string("", config) {
|
Ok(pipeline_data) => match pipeline_data.collect_string("", config) {
|
||||||
Ok(s) => last_output = s,
|
Ok(s) => last_output = s,
|
||||||
|
Loading…
Reference in New Issue
Block a user