diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index 15abe6f611..ce7b88509d 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -25,7 +25,7 @@ impl NuCompleter { pub fn new(engine_state: Arc, stack: Stack) -> Self { Self { engine_state, - stack: stack.reset_stdio().capture(), + stack: stack.reset_out_dest().capture(), } } diff --git a/crates/nu-cli/src/completions/custom_completions.rs b/crates/nu-cli/src/completions/custom_completions.rs index 67728f706b..12a7762e94 100644 --- a/crates/nu-cli/src/completions/custom_completions.rs +++ b/crates/nu-cli/src/completions/custom_completions.rs @@ -24,7 +24,7 @@ impl CustomCompletion { pub fn new(engine_state: Arc, stack: Stack, decl_id: usize, line: String) -> Self { Self { engine_state, - stack: stack.reset_stdio().capture(), + stack: stack.reset_out_dest().capture(), decl_id, line, sort_by: SortBy::None, diff --git a/crates/nu-cli/src/menus/menu_completions.rs b/crates/nu-cli/src/menus/menu_completions.rs index c853d7f77b..fbfc598225 100644 --- a/crates/nu-cli/src/menus/menu_completions.rs +++ b/crates/nu-cli/src/menus/menu_completions.rs @@ -28,7 +28,7 @@ impl NuMenuCompleter { Self { block_id, span, - stack: stack.reset_stdio().capture(), + stack: stack.reset_out_dest().capture(), engine_state, only_buffer_difference, } diff --git a/crates/nu-cmd-lang/src/core_commands/collect.rs b/crates/nu-cmd-lang/src/core_commands/collect.rs index 05726392d7..da94c4a890 100644 --- a/crates/nu-cmd-lang/src/core_commands/collect.rs +++ b/crates/nu-cmd-lang/src/core_commands/collect.rs @@ -40,7 +40,7 @@ impl Command for Collect { let block = engine_state.get_block(capture_block.block_id).clone(); let mut stack_captures = - stack.captures_to_stack_preserve_stdio(capture_block.captures.clone()); + stack.captures_to_stack_preserve_out_dest(capture_block.captures.clone()); let metadata = input.metadata(); let input: Value = input.into_value(call.head); diff --git a/crates/nu-cmd-lang/src/core_commands/do_.rs b/crates/nu-cmd-lang/src/core_commands/do_.rs index 129460d5c4..6043a8681a 100644 --- a/crates/nu-cmd-lang/src/core_commands/do_.rs +++ b/crates/nu-cmd-lang/src/core_commands/do_.rs @@ -1,5 +1,5 @@ use nu_engine::{command_prelude::*, get_eval_block_with_early_return, redirect_env}; -use nu_protocol::{engine::Closure, IoStream, ListStream, RawStream}; +use nu_protocol::{engine::Closure, ListStream, OutDest, RawStream}; use std::thread; #[derive(Clone)] @@ -72,7 +72,7 @@ impl Command for Do { let capture_errors = call.has_flag(engine_state, caller_stack, "capture-errors")?; let has_env = call.has_flag(engine_state, caller_stack, "env")?; - let mut callee_stack = caller_stack.captures_to_stack_preserve_stdio(block.captures); + let mut callee_stack = caller_stack.captures_to_stack_preserve_out_dest(block.captures); let block = engine_state.get_block(block.block_id); bind_args_to(&mut callee_stack, &block.signature, rest, call.head)?; @@ -191,7 +191,7 @@ impl Command for Do { metadata, trim_end_newline, }) if ignore_program_errors - && !matches!(caller_stack.stdout(), IoStream::Pipe | IoStream::Capture) => + && !matches!(caller_stack.stdout(), OutDest::Pipe | OutDest::Capture) => { Ok(PipelineData::ExternalStream { stdout, diff --git a/crates/nu-cmd-lang/src/core_commands/ignore.rs b/crates/nu-cmd-lang/src/core_commands/ignore.rs index 9935286ee1..bca7f84a1a 100644 --- a/crates/nu-cmd-lang/src/core_commands/ignore.rs +++ b/crates/nu-cmd-lang/src/core_commands/ignore.rs @@ -1,5 +1,5 @@ use nu_engine::command_prelude::*; -use nu_protocol::{engine::StateWorkingSet, IoStream}; +use nu_protocol::{engine::StateWorkingSet, OutDest}; #[derive(Clone)] pub struct Ignore; @@ -56,8 +56,8 @@ impl Command for Ignore { }] } - fn stdio_redirect(&self) -> (Option, Option) { - (Some(IoStream::Null), None) + fn pipe_redirection(&self) -> (Option, Option) { + (Some(OutDest::Null), None) } } diff --git a/crates/nu-cmd-lang/src/core_commands/lazy_make.rs b/crates/nu-cmd-lang/src/core_commands/lazy_make.rs index 2f907658d2..a9c4355678 100644 --- a/crates/nu-cmd-lang/src/core_commands/lazy_make.rs +++ b/crates/nu-cmd-lang/src/core_commands/lazy_make.rs @@ -80,7 +80,7 @@ impl Command for LazyMake { } } - let stack = stack.clone().reset_stdio().capture(); + let stack = stack.clone().reset_out_dest().capture(); Ok(Value::lazy_record( Box::new(NuLazyRecord { diff --git a/crates/nu-command/src/env/config/utils.rs b/crates/nu-command/src/env/config/utils.rs index 48a648a1fa..63a323af7b 100644 --- a/crates/nu-command/src/env/config/utils.rs +++ b/crates/nu-command/src/env/config/utils.rs @@ -1,5 +1,5 @@ use crate::ExternalCommand; -use nu_protocol::{IoStream, Span, Spanned}; +use nu_protocol::{OutDest, Span, Spanned}; use std::{collections::HashMap, path::PathBuf}; pub(crate) fn gen_command( @@ -29,8 +29,8 @@ pub(crate) fn gen_command( name, args, arg_keep_raw: vec![false; number_of_args], - out: IoStream::Inherit, - err: IoStream::Inherit, + out: OutDest::Inherit, + err: OutDest::Inherit, env_vars: env_vars_str, } } diff --git a/crates/nu-command/src/env/with_env.rs b/crates/nu-command/src/env/with_env.rs index 5bd675e84a..91ccc78e4b 100644 --- a/crates/nu-command/src/env/with_env.rs +++ b/crates/nu-command/src/env/with_env.rs @@ -79,7 +79,7 @@ fn with_env( let capture_block: Closure = call.req(engine_state, stack, 1)?; let block = engine_state.get_block(capture_block.block_id); - let mut stack = stack.captures_to_stack_preserve_stdio(capture_block.captures); + let mut stack = stack.captures_to_stack_preserve_out_dest(capture_block.captures); let mut env: HashMap = HashMap::new(); diff --git a/crates/nu-command/src/filesystem/save.rs b/crates/nu-command/src/filesystem/save.rs index 6e6630be80..0dec55a4ef 100644 --- a/crates/nu-command/src/filesystem/save.rs +++ b/crates/nu-command/src/filesystem/save.rs @@ -3,7 +3,7 @@ use nu_engine::{command_prelude::*, current_dir}; use nu_path::expand_path_with; use nu_protocol::{ ast::{Expr, Expression}, - DataSource, IoStream, PipelineMetadata, RawStream, + DataSource, OutDest, PipelineMetadata, RawStream, }; use std::{ fs::File, @@ -261,8 +261,8 @@ impl Command for Save { ] } - fn stdio_redirect(&self) -> (Option, Option) { - (Some(IoStream::Capture), Some(IoStream::Capture)) + fn pipe_redirection(&self) -> (Option, Option) { + (Some(OutDest::Capture), Some(OutDest::Capture)) } } diff --git a/crates/nu-command/src/filters/tee.rs b/crates/nu-command/src/filters/tee.rs index 3a710c5a18..490e66a7c9 100644 --- a/crates/nu-command/src/filters/tee.rs +++ b/crates/nu-command/src/filters/tee.rs @@ -1,5 +1,5 @@ use nu_engine::{command_prelude::*, get_eval_block_with_early_return}; -use nu_protocol::{engine::Closure, IoStream, RawStream}; +use nu_protocol::{engine::Closure, OutDest, RawStream}; use std::{sync::mpsc, thread}; #[derive(Clone)] @@ -73,7 +73,7 @@ use it in your pipeline."# let closure_engine_state = engine_state.clone(); let mut closure_stack = stack - .captures_to_stack_preserve_stdio(captures) + .captures_to_stack_preserve_out_dest(captures) .reset_pipes(); let metadata = input.metadata(); @@ -198,8 +198,8 @@ use it in your pipeline."# } } - fn stdio_redirect(&self) -> (Option, Option) { - (Some(IoStream::Capture), Some(IoStream::Capture)) + fn pipe_redirection(&self) -> (Option, Option) { + (Some(OutDest::Capture), Some(OutDest::Capture)) } } diff --git a/crates/nu-command/src/system/complete.rs b/crates/nu-command/src/system/complete.rs index 2428dd0994..48f04b4ff3 100644 --- a/crates/nu-command/src/system/complete.rs +++ b/crates/nu-command/src/system/complete.rs @@ -1,5 +1,5 @@ use nu_engine::command_prelude::*; -use nu_protocol::IoStream; +use nu_protocol::OutDest; use std::thread; #[derive(Clone)] @@ -118,7 +118,7 @@ impl Command for Complete { }] } - fn stdio_redirect(&self) -> (Option, Option) { - (Some(IoStream::Capture), Some(IoStream::Capture)) + fn pipe_redirection(&self) -> (Option, Option) { + (Some(OutDest::Capture), Some(OutDest::Capture)) } } diff --git a/crates/nu-command/src/system/exec.rs b/crates/nu-command/src/system/exec.rs index 79c343babc..4ae44e44fd 100644 --- a/crates/nu-command/src/system/exec.rs +++ b/crates/nu-command/src/system/exec.rs @@ -1,6 +1,6 @@ use super::run_external::create_external_command; use nu_engine::{command_prelude::*, current_dir}; -use nu_protocol::IoStream; +use nu_protocol::OutDest; #[derive(Clone)] pub struct Exec; @@ -59,8 +59,8 @@ fn exec( call: &Call, ) -> Result { let mut external_command = create_external_command(engine_state, stack, call)?; - external_command.out = IoStream::Inherit; - external_command.err = IoStream::Inherit; + external_command.out = OutDest::Inherit; + external_command.err = OutDest::Inherit; let cwd = current_dir(engine_state, stack)?; let mut command = external_command.spawn_simple_command(&cwd.to_string_lossy())?; diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 02996f8423..1363481311 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -1,6 +1,6 @@ use nu_cmd_base::hook::eval_hook; use nu_engine::{command_prelude::*, env_to_strings, get_eval_expression}; -use nu_protocol::{ast::Expr, did_you_mean, IoStream, ListStream, NuGlob, RawStream}; +use nu_protocol::{ast::Expr, did_you_mean, ListStream, NuGlob, OutDest, RawStream}; use nu_system::ForegroundChild; use nu_utils::IgnoreCaseExt; use os_pipe::PipeReader; @@ -225,8 +225,8 @@ pub struct ExternalCommand { pub name: Spanned, pub args: Vec>, pub arg_keep_raw: Vec, - pub out: IoStream, - pub err: IoStream, + pub out: OutDest, + pub err: OutDest, pub env_vars: HashMap, } @@ -523,7 +523,7 @@ impl ExternalCommand { RawStream::new(Box::new(ByteLines::new(err)), ctrlc.clone(), head, None) }); - if matches!(self.err, IoStream::Pipe) { + if matches!(self.err, OutDest::Pipe) { (stderr, stdout) } else { (stdout, stderr) @@ -634,7 +634,7 @@ impl ExternalCommand { // If the external is not the last command, its output will get piped // either as a string or binary - let reader = if matches!(self.out, IoStream::Pipe) && matches!(self.err, IoStream::Pipe) { + let reader = if matches!(self.out, OutDest::Pipe) && matches!(self.err, OutDest::Pipe) { let (reader, writer) = os_pipe::pipe()?; let writer_clone = writer.try_clone()?; process.stdout(writer); diff --git a/crates/nu-engine/src/call_ext.rs b/crates/nu-engine/src/call_ext.rs index 517b9fbf12..daedb24a1f 100644 --- a/crates/nu-engine/src/call_ext.rs +++ b/crates/nu-engine/src/call_ext.rs @@ -69,7 +69,7 @@ impl CallExt for Call { if flag_name == name.0.item { return if let Some(expr) = &name.2 { // Check --flag=false - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let result = eval_expression::(engine_state, stack, expr)?; match result { Value::Bool { val, .. } => Ok(val), @@ -96,7 +96,7 @@ impl CallExt for Call { name: &str, ) -> Result, ShellError> { if let Some(expr) = self.get_flag_expr(name) { - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let result = eval_expression::(engine_state, stack, expr)?; FromValue::from_value(result).map(Some) } else { @@ -110,7 +110,7 @@ impl CallExt for Call { stack: &mut Stack, starting_pos: usize, ) -> Result, ShellError> { - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let mut output = vec![]; for result in self.rest_iter_flattened(starting_pos, |expr| { @@ -129,7 +129,7 @@ impl CallExt for Call { pos: usize, ) -> Result, ShellError> { if let Some(expr) = self.positional_nth(pos) { - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let result = eval_expression::(engine_state, stack, expr)?; FromValue::from_value(result).map(Some) } else { @@ -157,7 +157,7 @@ impl CallExt for Call { pos: usize, ) -> Result { if let Some(expr) = self.positional_nth(pos) { - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let result = eval_expression::(engine_state, stack, expr)?; FromValue::from_value(result) } else if self.positional_len() == 0 { @@ -177,7 +177,7 @@ impl CallExt for Call { name: &str, ) -> Result { if let Some(expr) = self.get_parser_info(name) { - let stack = &mut stack.use_call_arg_stdio(); + let stack = &mut stack.use_call_arg_out_dest(); let result = eval_expression::(engine_state, stack, expr)?; FromValue::from_value(result) } else if self.parser_info.is_empty() { diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index c56cc8d223..3674e0e2d4 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -8,7 +8,7 @@ use nu_protocol::{ debugger::DebugContext, engine::{Closure, EngineState, Redirection, Stack}, eval_base::Eval, - Config, FromValue, IntoPipelineData, IoStream, PipelineData, ShellError, Span, Spanned, Type, + Config, FromValue, IntoPipelineData, OutDest, PipelineData, ShellError, Span, Spanned, Type, Value, VarId, ENV_VARIABLE_ID, }; use std::{borrow::Cow, fs::OpenOptions, path::PathBuf}; @@ -302,8 +302,8 @@ pub fn eval_expression_with_input( // If input is PipelineData::ExternalStream, // then `might_consume_external_result` will consume `stderr` if `stdout` is `None`. // This should not happen if the user wants to capture stderr. - if !matches!(stack.stdout(), IoStream::Pipe | IoStream::Capture) - && matches!(stack.stderr(), IoStream::Capture) + if !matches!(stack.stdout(), OutDest::Pipe | OutDest::Capture) + && matches!(stack.stderr(), OutDest::Capture) { Ok((input, false)) } else { @@ -320,7 +320,7 @@ fn eval_redirection( engine_state: &EngineState, stack: &mut Stack, target: &RedirectionTarget, - next_out: Option, + next_out: Option, ) -> Result { match target { RedirectionTarget::File { expr, append, .. } => { @@ -337,7 +337,7 @@ fn eval_redirection( } Ok(Redirection::file(options.create(true).open(path)?)) } - RedirectionTarget::Pipe { .. } => Ok(Redirection::Pipe(next_out.unwrap_or(IoStream::Pipe))), + RedirectionTarget::Pipe { .. } => Ok(Redirection::Pipe(next_out.unwrap_or(OutDest::Pipe))), } } @@ -345,7 +345,7 @@ fn eval_element_redirection( engine_state: &EngineState, stack: &mut Stack, element_redirection: Option<&PipelineRedirection>, - pipe_redirection: (Option, Option), + pipe_redirection: (Option, Option), ) -> Result<(Option, Option), ShellError> { let (next_out, next_err) = pipe_redirection; @@ -363,7 +363,7 @@ fn eval_element_redirection( target, } => { let stderr = eval_redirection::(engine_state, stack, target, None)?; - if matches!(stderr, Redirection::Pipe(IoStream::Pipe)) { + if matches!(stderr, Redirection::Pipe(OutDest::Pipe)) { // e>| redirection, don't override current stack `stdout` Ok(( None, @@ -438,10 +438,10 @@ fn eval_element_with_input_inner( } } - let data = if matches!(stack.pipe_stdout(), Some(IoStream::File(_))) - && !matches!(stack.pipe_stderr(), Some(IoStream::Pipe)) + let data = if matches!(stack.pipe_stdout(), Some(OutDest::File(_))) + && !matches!(stack.pipe_stderr(), Some(OutDest::Pipe)) { - data.write_to_io_streams(engine_state, stack)? + data.write_to_out_dests(engine_state, stack)? } else { data }; @@ -496,12 +496,12 @@ pub fn eval_block( for (i, element) in elements.iter().enumerate() { let next = elements.get(i + 1).unwrap_or(last); - let (next_out, next_err) = next.stdio_redirect(engine_state); + let (next_out, next_err) = next.pipe_redirection(engine_state); let (stdout, stderr) = eval_element_redirection::( engine_state, stack, element.redirection.as_ref(), - (next_out.or(Some(IoStream::Pipe)), next_err), + (next_out.or(Some(OutDest::Pipe)), next_err), )?; let stack = &mut stack.push_redirection(stdout, stderr); let (output, failed) = diff --git a/crates/nu-explore/src/nu_common/command.rs b/crates/nu-explore/src/nu_common/command.rs index add3940e75..269382d1f0 100644 --- a/crates/nu-explore/src/nu_common/command.rs +++ b/crates/nu-explore/src/nu_common/command.rs @@ -3,7 +3,7 @@ use nu_parser::parse; use nu_protocol::{ debugger::WithoutDebug, engine::{EngineState, Redirection, Stack, StateWorkingSet}, - IoStream, PipelineData, ShellError, Value, + OutDest, PipelineData, ShellError, Value, }; use std::sync::Arc; @@ -96,8 +96,8 @@ fn eval_source2( } let stack = &mut stack.push_redirection( - Some(Redirection::Pipe(IoStream::Capture)), - Some(Redirection::Pipe(IoStream::Capture)), + Some(Redirection::Pipe(OutDest::Capture)), + Some(Redirection::Pipe(OutDest::Capture)), ); eval_block::(engine_state, stack, &block, input) } diff --git a/crates/nu-plugin/src/plugin/context.rs b/crates/nu-plugin/src/plugin/context.rs index f590392f8b..61fdfe662a 100644 --- a/crates/nu-plugin/src/plugin/context.rs +++ b/crates/nu-plugin/src/plugin/context.rs @@ -3,7 +3,7 @@ use nu_engine::{get_eval_block_with_early_return, get_full_help}; use nu_protocol::{ ast::Call, engine::{Closure, EngineState, Redirection, Stack}, - Config, IntoSpanned, IoStream, PipelineData, PluginIdentity, ShellError, Span, Spanned, Value, + Config, IntoSpanned, OutDest, PipelineData, PluginIdentity, ShellError, Span, Spanned, Value, }; use std::{ borrow::Cow, @@ -188,13 +188,13 @@ impl<'a> PluginExecutionContext for PluginExecutionCommandContext<'a> { .reset_pipes(); let stdout = if redirect_stdout { - Some(Redirection::Pipe(IoStream::Capture)) + Some(Redirection::Pipe(OutDest::Capture)) } else { None }; let stderr = if redirect_stderr { - Some(Redirection::Pipe(IoStream::Capture)) + Some(Redirection::Pipe(OutDest::Capture)) } else { None }; diff --git a/crates/nu-protocol/src/ast/block.rs b/crates/nu-protocol/src/ast/block.rs index c5714963b7..6e3449af26 100644 --- a/crates/nu-protocol/src/ast/block.rs +++ b/crates/nu-protocol/src/ast/block.rs @@ -1,5 +1,5 @@ use super::Pipeline; -use crate::{engine::EngineState, IoStream, Signature, Span, Type, VarId}; +use crate::{engine::EngineState, OutDest, Signature, Span, Type, VarId}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -20,12 +20,12 @@ impl Block { self.pipelines.is_empty() } - pub fn stdio_redirect( + pub fn pipe_redirection( &self, engine_state: &EngineState, - ) -> (Option, Option) { + ) -> (Option, Option) { if let Some(first) = self.pipelines.first() { - first.stdio_redirect(engine_state) + first.pipe_redirection(engine_state) } else { (None, None) } diff --git a/crates/nu-protocol/src/ast/expr.rs b/crates/nu-protocol/src/ast/expr.rs index 4b2973a02d..85839d63a1 100644 --- a/crates/nu-protocol/src/ast/expr.rs +++ b/crates/nu-protocol/src/ast/expr.rs @@ -6,8 +6,8 @@ use super::{ RangeOperator, }; use crate::{ - ast::ImportPattern, ast::Unit, engine::EngineState, BlockId, IoStream, Signature, Span, - Spanned, VarId, + ast::ImportPattern, ast::Unit, engine::EngineState, BlockId, OutDest, Signature, Span, Spanned, + VarId, }; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -56,19 +56,19 @@ pub enum Expr { } impl Expr { - pub fn stdio_redirect( + pub fn pipe_redirection( &self, engine_state: &EngineState, - ) -> (Option, Option) { + ) -> (Option, Option) { // Usages of `$in` will be wrapped by a `collect` call by the parser, // so we do not have to worry about that when considering // which of the expressions below may consume pipeline output. match self { - Expr::Call(call) => engine_state.get_decl(call.decl_id).stdio_redirect(), + Expr::Call(call) => engine_state.get_decl(call.decl_id).pipe_redirection(), Expr::Subexpression(block_id) | Expr::Block(block_id) => engine_state .get_block(*block_id) - .stdio_redirect(engine_state), - Expr::FullCellPath(cell_path) => cell_path.head.expr.stdio_redirect(engine_state), + .pipe_redirection(engine_state), + Expr::FullCellPath(cell_path) => cell_path.head.expr.pipe_redirection(engine_state), Expr::Bool(_) | Expr::Int(_) | Expr::Float(_) @@ -89,7 +89,7 @@ impl Expr { | Expr::Nothing => { // These expressions do not use the output of the pipeline in any meaningful way, // so we can discard the previous output by redirecting it to `Null`. - (Some(IoStream::Null), None) + (Some(OutDest::Null), None) } Expr::VarDecl(_) | Expr::Operator(_) @@ -103,7 +103,7 @@ impl Expr { | Expr::Garbage => { // These should be impossible to pipe to, // but even it is, the pipeline output is not used in any way. - (Some(IoStream::Null), None) + (Some(OutDest::Null), None) } Expr::RowCondition(_) | Expr::MatchBlock(_) => { // These should be impossible to pipe to, diff --git a/crates/nu-protocol/src/ast/pipeline.rs b/crates/nu-protocol/src/ast/pipeline.rs index a1d4fea325..f03c016daf 100644 --- a/crates/nu-protocol/src/ast/pipeline.rs +++ b/crates/nu-protocol/src/ast/pipeline.rs @@ -1,7 +1,7 @@ use crate::{ ast::Expression, engine::{EngineState, StateWorkingSet}, - IoStream, Span, + OutDest, Span, }; use serde::{Deserialize, Serialize}; use std::fmt::Display; @@ -118,11 +118,11 @@ impl PipelineElement { } } - pub fn stdio_redirect( + pub fn pipe_redirection( &self, engine_state: &EngineState, - ) -> (Option, Option) { - self.expr.expr.stdio_redirect(engine_state) + ) -> (Option, Option) { + self.expr.expr.pipe_redirection(engine_state) } } @@ -164,12 +164,12 @@ impl Pipeline { self.elements.is_empty() } - pub fn stdio_redirect( + pub fn pipe_redirection( &self, engine_state: &EngineState, - ) -> (Option, Option) { + ) -> (Option, Option) { if let Some(first) = self.elements.first() { - first.stdio_redirect(engine_state) + first.pipe_redirection(engine_state) } else { (None, None) } diff --git a/crates/nu-protocol/src/engine/command.rs b/crates/nu-protocol/src/engine/command.rs index a60e412999..38119d6f8f 100644 --- a/crates/nu-protocol/src/engine/command.rs +++ b/crates/nu-protocol/src/engine/command.rs @@ -1,4 +1,4 @@ -use crate::{ast::Call, Alias, BlockId, Example, IoStream, PipelineData, ShellError, Signature}; +use crate::{ast::Call, Alias, BlockId, Example, OutDest, PipelineData, ShellError, Signature}; use super::{EngineState, Stack, StateWorkingSet}; @@ -134,7 +134,7 @@ pub trait Command: Send + Sync + CommandClone { } } - fn stdio_redirect(&self) -> (Option, Option) { + fn pipe_redirection(&self) -> (Option, Option) { (None, None) } } diff --git a/crates/nu-protocol/src/engine/mod.rs b/crates/nu-protocol/src/engine/mod.rs index 3c2189e8b0..c6e71afb37 100644 --- a/crates/nu-protocol/src/engine/mod.rs +++ b/crates/nu-protocol/src/engine/mod.rs @@ -6,9 +6,9 @@ mod engine_state; mod overlay; mod pattern_match; mod stack; +mod stack_out_dest; mod state_delta; mod state_working_set; -mod stdio; mod usage; mod variable; @@ -21,7 +21,7 @@ pub use engine_state::*; pub use overlay::*; pub use pattern_match::*; pub use stack::*; +pub use stack_out_dest::*; pub use state_delta::*; pub use state_working_set::*; -pub use stdio::*; pub use variable::*; diff --git a/crates/nu-protocol/src/engine/stack.rs b/crates/nu-protocol/src/engine/stack.rs index 990b512551..2fa71f57fa 100644 --- a/crates/nu-protocol/src/engine/stack.rs +++ b/crates/nu-protocol/src/engine/stack.rs @@ -1,9 +1,9 @@ use crate::{ engine::{ - EngineState, Redirection, StackCallArgGuard, StackCaptureGuard, StackIoGuard, StackStdio, + EngineState, Redirection, StackCallArgGuard, StackCaptureGuard, StackIoGuard, StackOutDest, DEFAULT_OVERLAY_NAME, }, - IoStream, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID, + OutDest, ShellError, Span, Value, VarId, ENV_VARIABLE_ID, NU_VARIABLE_ID, }; use std::{ collections::{HashMap, HashSet}, @@ -44,7 +44,7 @@ pub struct Stack { pub parent_stack: Option>, /// Variables that have been deleted (this is used to hide values from parent stack lookups) pub parent_deletions: Vec, - pub(crate) stdio: StackStdio, + pub(crate) out_dest: StackOutDest, } impl Default for Stack { @@ -56,7 +56,7 @@ impl Default for Stack { impl Stack { /// Create a new stack. /// - /// Stdio will be set to [`IoStream::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. /// /// Use [`Stack::capture`] afterwards if you need to evaluate an expression to a [`Value`](crate::Value) @@ -70,7 +70,7 @@ impl Stack { recursion_count: 0, parent_stack: None, parent_deletions: vec![], - stdio: StackStdio::new(), + out_dest: StackOutDest::new(), } } @@ -89,6 +89,7 @@ impl Stack { (*arc).clone() }) } + /// Create a new child stack from a parent. /// /// Changes from this child can be merged back into the parent with @@ -102,7 +103,7 @@ impl Stack { recursion_count: parent.recursion_count, vars: vec![], parent_deletions: vec![], - stdio: parent.stdio.clone(), + out_dest: parent.out_dest.clone(), parent_stack: Some(parent), } } @@ -257,10 +258,10 @@ impl Stack { } pub fn captures_to_stack(&self, captures: Vec<(VarId, Value)>) -> Stack { - self.captures_to_stack_preserve_stdio(captures).capture() + self.captures_to_stack_preserve_out_dest(captures).capture() } - pub fn captures_to_stack_preserve_stdio(&self, captures: Vec<(VarId, Value)>) -> Stack { + pub fn captures_to_stack_preserve_out_dest(&self, captures: Vec<(VarId, Value)>) -> Stack { // FIXME: this is probably slow let mut env_vars = self.env_vars.clone(); env_vars.push(HashMap::new()); @@ -273,7 +274,7 @@ impl Stack { recursion_count: self.recursion_count, parent_stack: None, parent_deletions: vec![], - stdio: self.stdio.clone(), + out_dest: self.out_dest.clone(), } } @@ -303,7 +304,7 @@ impl Stack { recursion_count: self.recursion_count, parent_stack: None, parent_deletions: vec![], - stdio: self.stdio.clone(), + out_dest: self.out_dest.clone(), } } @@ -510,45 +511,45 @@ impl Stack { self.active_overlays.retain(|o| o != name); } - /// Returns the [`IoStream`] to use for the current command's stdout. + /// Returns the [`OutDest`] to use for the current command's stdout. /// /// This will be the pipe redirection if one is set, /// otherwise it will be the current file redirection, - /// otherwise it will be the process's stdout indicated by [`IoStream::Inherit`]. - pub fn stdout(&self) -> &IoStream { - self.stdio.stdout() + /// otherwise it will be the process's stdout indicated by [`OutDest::Inherit`]. + pub fn stdout(&self) -> &OutDest { + self.out_dest.stdout() } - /// Returns the [`IoStream`] to use for the current command's stderr. + /// Returns the [`OutDest`] to use for the current command's stderr. /// /// This will be the pipe redirection if one is set, /// otherwise it will be the current file redirection, - /// otherwise it will be the process's stderr indicated by [`IoStream::Inherit`]. - pub fn stderr(&self) -> &IoStream { - self.stdio.stderr() + /// otherwise it will be the process's stderr indicated by [`OutDest::Inherit`]. + pub fn stderr(&self) -> &OutDest { + self.out_dest.stderr() } - /// Returns the [`IoStream`] to use for the last command's stdout. - pub fn pipe_stdout(&self) -> Option<&IoStream> { - self.stdio.pipe_stdout.as_ref() + /// Returns the [`OutDest`] of the pipe redirection applied to the current command's stdout. + pub fn pipe_stdout(&self) -> Option<&OutDest> { + self.out_dest.pipe_stdout.as_ref() } - /// Returns the [`IoStream`] to use for the last command's stderr. - pub fn pipe_stderr(&self) -> Option<&IoStream> { - self.stdio.pipe_stderr.as_ref() + /// Returns the [`OutDest`] of the pipe redirection applied to the current command's stderr. + pub fn pipe_stderr(&self) -> Option<&OutDest> { + self.out_dest.pipe_stderr.as_ref() } - /// Temporarily set the pipe stdout redirection to [`IoStream::Capture`]. + /// Temporarily set the pipe stdout redirection to [`OutDest::Capture`]. /// /// This is used before evaluating an expression into a `Value`. pub fn start_capture(&mut self) -> StackCaptureGuard { StackCaptureGuard::new(self) } - /// Temporarily use the stdio redirections in the parent scope. + /// Temporarily use the output redirections in the parent scope. /// /// This is used before evaluating an argument to a call. - pub fn use_call_arg_stdio(&mut self) -> StackCallArgGuard { + pub fn use_call_arg_out_dest(&mut self) -> StackCallArgGuard { StackCallArgGuard::new(self) } @@ -561,34 +562,34 @@ impl Stack { StackIoGuard::new(self, stdout, stderr) } - /// Mark stdout for the last command as [`IoStream::Capture`]. + /// Mark stdout for the last command as [`OutDest::Capture`]. /// - /// This will irreversibly alter the stdio 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`). /// - /// See [`Stack::start_capture`] which can temporarily set stdout as [`IoStream::Capture`] for a mutable `Stack` reference. + /// See [`Stack::start_capture`] which can temporarily set stdout as [`OutDest::Capture`] for a mutable `Stack` reference. pub fn capture(mut self) -> Self { - self.stdio.pipe_stdout = Some(IoStream::Capture); - self.stdio.pipe_stderr = None; + self.out_dest.pipe_stdout = Some(OutDest::Capture); + self.out_dest.pipe_stderr = None; self } - /// Clears any pipe and file redirections and resets stdout and stderr to [`IoStream::Inherit`]. + /// Clears any pipe and file redirections and resets stdout and stderr to [`OutDest::Inherit`]. /// - /// This will irreversibly reset the stdio redirections, and so it only makes sense to use this on an owned `Stack` + /// This will irreversibly reset 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`). - pub fn reset_stdio(mut self) -> Self { - self.stdio = StackStdio::new(); + pub fn reset_out_dest(mut self) -> Self { + self.out_dest = StackOutDest::new(); self } /// Clears any pipe redirections, keeping the current stdout and stderr. /// - /// This will irreversibly reset some of the stdio redirections, and so it only makes sense to use this on an owned `Stack` + /// This will irreversibly reset some of 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`). pub fn reset_pipes(mut self) -> Self { - self.stdio.pipe_stdout = None; - self.stdio.pipe_stderr = None; + self.out_dest.pipe_stdout = None; + self.out_dest.pipe_stderr = None; self } } diff --git a/crates/nu-protocol/src/engine/stdio.rs b/crates/nu-protocol/src/engine/stack_out_dest.rs similarity index 62% rename from crates/nu-protocol/src/engine/stdio.rs rename to crates/nu-protocol/src/engine/stack_out_dest.rs index 8cdafa3958..7699d29edd 100644 --- a/crates/nu-protocol/src/engine/stdio.rs +++ b/crates/nu-protocol/src/engine/stack_out_dest.rs @@ -1,4 +1,4 @@ -use crate::{engine::Stack, IoStream}; +use crate::{engine::Stack, OutDest}; use std::{ fs::File, mem, @@ -12,8 +12,8 @@ pub enum Redirection { /// /// This will only affect the last command of a block. /// This is created by pipes and pipe redirections (`|`, `e>|`, `o+e>|`, etc.), - /// or set by the next command in the pipeline (e.g., `ignore` sets stdout to [`IoStream::Null`]). - Pipe(IoStream), + /// or set by the next command in the pipeline (e.g., `ignore` sets stdout to [`OutDest::Null`]). + Pipe(OutDest), /// A file redirection. /// /// This will affect all commands in the block. @@ -28,19 +28,19 @@ impl Redirection { } #[derive(Debug, Clone)] -pub(crate) struct StackStdio { +pub(crate) struct StackOutDest { /// The stream to use for the next command's stdout. - pub pipe_stdout: Option, + pub pipe_stdout: Option, /// The stream to use for the next command's stderr. - pub pipe_stderr: Option, + pub pipe_stderr: Option, /// The stream used for the command stdout if `pipe_stdout` is `None`. /// /// This should only ever be `File` or `Inherit`. - pub stdout: IoStream, + pub stdout: OutDest, /// The stream used for the command stderr if `pipe_stderr` is `None`. /// /// This should only ever be `File` or `Inherit`. - pub stderr: IoStream, + pub stderr: OutDest, /// The previous stdout used before the current `stdout` was set. /// /// This is used only when evaluating arguments to commands, @@ -48,7 +48,7 @@ pub(crate) struct StackStdio { /// after redirections have already been applied to the command/stack. /// /// This should only ever be `File` or `Inherit`. - pub parent_stdout: Option, + pub parent_stdout: Option, /// The previous stderr used before the current `stderr` was set. /// /// This is used only when evaluating arguments to commands, @@ -56,45 +56,45 @@ pub(crate) struct StackStdio { /// after redirections have already been applied to the command/stack. /// /// This should only ever be `File` or `Inherit`. - pub parent_stderr: Option, + pub parent_stderr: Option, } -impl StackStdio { +impl StackOutDest { pub(crate) fn new() -> Self { Self { pipe_stdout: None, pipe_stderr: None, - stdout: IoStream::Inherit, - stderr: IoStream::Inherit, + stdout: OutDest::Inherit, + stderr: OutDest::Inherit, parent_stdout: None, parent_stderr: None, } } - /// Returns the [`IoStream`] to use for current command's stdout. + /// Returns the [`OutDest`] to use for current command's stdout. /// /// This will be the pipe redirection if one is set, /// otherwise it will be the current file redirection, - /// otherwise it will be the process's stdout indicated by [`IoStream::Inherit`]. - pub(crate) fn stdout(&self) -> &IoStream { + /// otherwise it will be the process's stdout indicated by [`OutDest::Inherit`]. + pub(crate) fn stdout(&self) -> &OutDest { self.pipe_stdout.as_ref().unwrap_or(&self.stdout) } - /// Returns the [`IoStream`] to use for current command's stderr. + /// Returns the [`OutDest`] to use for current command's stderr. /// /// This will be the pipe redirection if one is set, /// otherwise it will be the current file redirection, - /// otherwise it will be the process's stderr indicated by [`IoStream::Inherit`]. - pub(crate) fn stderr(&self) -> &IoStream { + /// otherwise it will be the process's stderr indicated by [`OutDest::Inherit`]. + pub(crate) fn stderr(&self) -> &OutDest { self.pipe_stderr.as_ref().unwrap_or(&self.stderr) } - fn push_stdout(&mut self, stdout: IoStream) -> Option { + fn push_stdout(&mut self, stdout: OutDest) -> Option { let stdout = mem::replace(&mut self.stdout, stdout); mem::replace(&mut self.parent_stdout, Some(stdout)) } - fn push_stderr(&mut self, stderr: IoStream) -> Option { + fn push_stderr(&mut self, stderr: OutDest) -> Option { let stderr = mem::replace(&mut self.stderr, stderr); mem::replace(&mut self.parent_stderr, Some(stderr)) } @@ -102,10 +102,10 @@ impl StackStdio { pub struct StackIoGuard<'a> { stack: &'a mut Stack, - old_pipe_stdout: Option, - old_pipe_stderr: Option, - old_parent_stdout: Option, - old_parent_stderr: Option, + old_pipe_stdout: Option, + old_pipe_stderr: Option, + old_parent_stdout: Option, + old_parent_stderr: Option, } impl<'a> StackIoGuard<'a> { @@ -114,32 +114,33 @@ impl<'a> StackIoGuard<'a> { stdout: Option, stderr: Option, ) -> Self { - let stdio = &mut stack.stdio; + let out_dest = &mut stack.out_dest; let (old_pipe_stdout, old_parent_stdout) = match stdout { Some(Redirection::Pipe(stdout)) => { - let old = mem::replace(&mut stdio.pipe_stdout, Some(stdout)); - (old, stdio.parent_stdout.take()) + let old = mem::replace(&mut out_dest.pipe_stdout, Some(stdout)); + (old, out_dest.parent_stdout.take()) } Some(Redirection::File(file)) => { - let file = IoStream::from(file); + let file = OutDest::from(file); ( - mem::replace(&mut stdio.pipe_stdout, Some(file.clone())), - stdio.push_stdout(file), + mem::replace(&mut out_dest.pipe_stdout, Some(file.clone())), + out_dest.push_stdout(file), ) } - None => (stdio.pipe_stdout.take(), stdio.parent_stdout.take()), + None => (out_dest.pipe_stdout.take(), out_dest.parent_stdout.take()), }; let (old_pipe_stderr, old_parent_stderr) = match stderr { Some(Redirection::Pipe(stderr)) => { - let old = mem::replace(&mut stdio.pipe_stderr, Some(stderr)); - (old, stdio.parent_stderr.take()) + let old = mem::replace(&mut out_dest.pipe_stderr, Some(stderr)); + (old, out_dest.parent_stderr.take()) } - Some(Redirection::File(file)) => { - (stdio.pipe_stderr.take(), stdio.push_stderr(file.into())) - } - None => (stdio.pipe_stderr.take(), stdio.parent_stderr.take()), + Some(Redirection::File(file)) => ( + out_dest.pipe_stderr.take(), + out_dest.push_stderr(file.into()), + ), + None => (out_dest.pipe_stderr.take(), out_dest.parent_stderr.take()), }; StackIoGuard { @@ -168,31 +169,31 @@ impl<'a> DerefMut for StackIoGuard<'a> { impl Drop for StackIoGuard<'_> { fn drop(&mut self) { - self.stdio.pipe_stdout = self.old_pipe_stdout.take(); - self.stdio.pipe_stderr = self.old_pipe_stderr.take(); + self.out_dest.pipe_stdout = self.old_pipe_stdout.take(); + self.out_dest.pipe_stderr = self.old_pipe_stderr.take(); let old_stdout = self.old_parent_stdout.take(); - if let Some(stdout) = mem::replace(&mut self.stdio.parent_stdout, old_stdout) { - self.stdio.stdout = stdout; + if let Some(stdout) = mem::replace(&mut self.out_dest.parent_stdout, old_stdout) { + self.out_dest.stdout = stdout; } let old_stderr = self.old_parent_stderr.take(); - if let Some(stderr) = mem::replace(&mut self.stdio.parent_stderr, old_stderr) { - self.stdio.stderr = stderr; + if let Some(stderr) = mem::replace(&mut self.out_dest.parent_stderr, old_stderr) { + self.out_dest.stderr = stderr; } } } pub struct StackCaptureGuard<'a> { stack: &'a mut Stack, - old_pipe_stdout: Option, - old_pipe_stderr: Option, + old_pipe_stdout: Option, + old_pipe_stderr: Option, } impl<'a> StackCaptureGuard<'a> { pub(crate) fn new(stack: &'a mut Stack) -> Self { - let old_pipe_stdout = mem::replace(&mut stack.stdio.pipe_stdout, Some(IoStream::Capture)); - let old_pipe_stderr = stack.stdio.pipe_stderr.take(); + let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Capture)); + let old_pipe_stderr = stack.out_dest.pipe_stderr.take(); Self { stack, old_pipe_stdout, @@ -217,35 +218,35 @@ impl<'a> DerefMut for StackCaptureGuard<'a> { impl Drop for StackCaptureGuard<'_> { fn drop(&mut self) { - self.stdio.pipe_stdout = self.old_pipe_stdout.take(); - self.stdio.pipe_stderr = self.old_pipe_stderr.take(); + self.out_dest.pipe_stdout = self.old_pipe_stdout.take(); + self.out_dest.pipe_stderr = self.old_pipe_stderr.take(); } } pub struct StackCallArgGuard<'a> { stack: &'a mut Stack, - old_pipe_stdout: Option, - old_pipe_stderr: Option, - old_stdout: Option, - old_stderr: Option, + old_pipe_stdout: Option, + old_pipe_stderr: Option, + old_stdout: Option, + old_stderr: Option, } impl<'a> StackCallArgGuard<'a> { pub(crate) fn new(stack: &'a mut Stack) -> Self { - let old_pipe_stdout = mem::replace(&mut stack.stdio.pipe_stdout, Some(IoStream::Capture)); - let old_pipe_stderr = stack.stdio.pipe_stderr.take(); + let old_pipe_stdout = mem::replace(&mut stack.out_dest.pipe_stdout, Some(OutDest::Capture)); + let old_pipe_stderr = stack.out_dest.pipe_stderr.take(); let old_stdout = stack - .stdio + .out_dest .parent_stdout .take() - .map(|stdout| mem::replace(&mut stack.stdio.stdout, stdout)); + .map(|stdout| mem::replace(&mut stack.out_dest.stdout, stdout)); let old_stderr = stack - .stdio + .out_dest .parent_stderr .take() - .map(|stderr| mem::replace(&mut stack.stdio.stderr, stderr)); + .map(|stderr| mem::replace(&mut stack.out_dest.stderr, stderr)); Self { stack, @@ -273,13 +274,13 @@ impl<'a> DerefMut for StackCallArgGuard<'a> { impl Drop for StackCallArgGuard<'_> { fn drop(&mut self) { - self.stdio.pipe_stdout = self.old_pipe_stdout.take(); - self.stdio.pipe_stderr = self.old_pipe_stderr.take(); + self.out_dest.pipe_stdout = self.old_pipe_stdout.take(); + self.out_dest.pipe_stderr = self.old_pipe_stderr.take(); if let Some(stdout) = self.old_stdout.take() { - self.stdio.push_stdout(stdout); + self.out_dest.push_stdout(stdout); } if let Some(stderr) = self.old_stderr.take() { - self.stdio.push_stderr(stderr); + self.out_dest.push_stderr(stderr); } } } diff --git a/crates/nu-protocol/src/pipeline_data/io_stream.rs b/crates/nu-protocol/src/pipeline_data/io_stream.rs deleted file mode 100644 index 57cfd02020..0000000000 --- a/crates/nu-protocol/src/pipeline_data/io_stream.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{fs::File, io, process::Stdio, sync::Arc}; - -#[derive(Debug, Clone)] -pub enum IoStream { - /// Redirect the `stdout` and/or `stderr` of one command as the input for the next command in the pipeline. - /// - /// The output pipe will be available in `PipelineData::ExternalStream::stdout`. - /// - /// If both `stdout` and `stderr` are set to `Pipe`, - /// then they will combined into `ExternalStream::stdout`. - Pipe, - /// Capture output to later be collected into a [`Value`](crate::Value), `Vec`, or used in some - /// other way. - /// - /// The output stream(s) will be available in - /// `PipelineData::ExternalStream::stdout` or `PipelineData::ExternalStream::stderr`. - /// - /// This is similar to `Pipe` but will never combine `stdout` and `stderr` - /// or place an external command's `stderr` into `PipelineData::ExternalStream::stdout`. - Capture, - /// Ignore output. - Null, - /// Output to nushell's `stdout` or `stderr`. - /// - /// This causes external commands to inherit nushell's `stdout` or `stderr`. - Inherit, - /// Redirect output to a file. - File(Arc), // Arc, since we sometimes need to clone `IoStream` into iterators, etc. -} - -impl From for IoStream { - fn from(file: File) -> Self { - Arc::new(file).into() - } -} - -impl From> for IoStream { - fn from(file: Arc) -> Self { - Self::File(file) - } -} - -impl TryFrom<&IoStream> for Stdio { - type Error = io::Error; - - fn try_from(stream: &IoStream) -> Result { - match stream { - IoStream::Pipe | IoStream::Capture => Ok(Self::piped()), - IoStream::Null => Ok(Self::null()), - IoStream::Inherit => Ok(Self::inherit()), - IoStream::File(file) => Ok(file.try_clone()?.into()), - } - } -} diff --git a/crates/nu-protocol/src/pipeline_data/mod.rs b/crates/nu-protocol/src/pipeline_data/mod.rs index d9aad30ce4..9b1b6947ba 100644 --- a/crates/nu-protocol/src/pipeline_data/mod.rs +++ b/crates/nu-protocol/src/pipeline_data/mod.rs @@ -1,9 +1,9 @@ -mod io_stream; mod metadata; +mod out_dest; mod stream; -pub use io_stream::*; pub use metadata::*; +pub use out_dest::*; pub use stream::*; use crate::{ @@ -208,14 +208,14 @@ impl PipelineData { } } - /// Writes all values or redirects all output to the current stdio streams in `stack`. + /// Writes all values or redirects all output to the current [`OutDest`]s in `stack`. /// - /// For [`IoStream::Pipe`] and [`IoStream::Capture`], this will return the `PipelineData` as is + /// For [`OutDest::Pipe`] and [`OutDest::Capture`], this will return the `PipelineData` as is /// without consuming input and without writing anything. /// - /// For the other [`IoStream`]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. - pub fn write_to_io_streams( + pub fn write_to_out_dests( self, engine_state: &EngineState, stack: &mut Stack, @@ -234,10 +234,10 @@ impl PipelineData { ) => { fn needs_redirect( stream: Option, - io_stream: &IoStream, + out_dest: &OutDest, ) -> Result> { - match (stream, io_stream) { - (Some(stream), IoStream::Pipe | IoStream::Capture) => Err(Some(stream)), + match (stream, out_dest) { + (Some(stream), OutDest::Pipe | OutDest::Capture) => Err(Some(stream)), (Some(stream), _) => Ok(stream), (None, _) => Err(None), } @@ -296,22 +296,22 @@ impl PipelineData { trim_end_newline, }) } - (data, IoStream::Pipe | IoStream::Capture) => Ok(data), + (data, OutDest::Pipe | OutDest::Capture) => Ok(data), (PipelineData::Empty, _) => Ok(PipelineData::Empty), - (PipelineData::Value(_, _), IoStream::Null) => Ok(PipelineData::Empty), - (PipelineData::ListStream(stream, _), IoStream::Null) => { + (PipelineData::Value(_, _), OutDest::Null) => Ok(PipelineData::Empty), + (PipelineData::ListStream(stream, _), OutDest::Null) => { // we need to drain the stream in case there are external commands in the pipeline stream.drain()?; Ok(PipelineData::Empty) } - (PipelineData::Value(value, _), IoStream::File(file)) => { + (PipelineData::Value(value, _), OutDest::File(file)) => { let bytes = value_to_bytes(value)?; let mut file = file.try_clone()?; file.write_all(&bytes)?; file.flush()?; Ok(PipelineData::Empty) } - (PipelineData::ListStream(stream, _), IoStream::File(file)) => { + (PipelineData::ListStream(stream, _), OutDest::File(file)) => { let mut file = file.try_clone()?; // use BufWriter here? for value in stream { @@ -324,7 +324,7 @@ impl PipelineData { } ( data @ (PipelineData::Value(_, _) | PipelineData::ListStream(_, _)), - IoStream::Inherit, + OutDest::Inherit, ) => { let config = engine_state.get_config(); @@ -1036,26 +1036,26 @@ fn drain_exit_code(exit_code: ListStream) -> Result { } } -/// Only call this if `output_stream` is not `IoStream::Pipe` or `IoStream::Capture`. -fn consume_child_output(child_output: RawStream, output_stream: &IoStream) -> io::Result<()> { +/// Only call this if `output_stream` is not `OutDest::Pipe` or `OutDest::Capture`. +fn consume_child_output(child_output: RawStream, output_stream: &OutDest) -> io::Result<()> { let mut output = ReadRawStream::new(child_output); match output_stream { - IoStream::Pipe | IoStream::Capture => { + OutDest::Pipe | OutDest::Capture => { // The point of `consume_child_output` is to redirect output *right now*, - // but IoStream::Pipe means to redirect output + // but OutDest::Pipe means to redirect output // into an OS pipe for *future use* (as input for another command). // So, this branch makes no sense, and will simply drop `output` instead of draining it. // This could trigger a `SIGPIPE` for the external command, // since there will be no reader for its pipe. debug_assert!(false) } - IoStream::Null => { + OutDest::Null => { io::copy(&mut output, &mut io::sink())?; } - IoStream::Inherit => { + OutDest::Inherit => { io::copy(&mut output, &mut io::stdout())?; } - IoStream::File(file) => { + OutDest::File(file) => { io::copy(&mut output, &mut file.try_clone()?)?; } } diff --git a/crates/nu-protocol/src/pipeline_data/out_dest.rs b/crates/nu-protocol/src/pipeline_data/out_dest.rs new file mode 100644 index 0000000000..976123e883 --- /dev/null +++ b/crates/nu-protocol/src/pipeline_data/out_dest.rs @@ -0,0 +1,55 @@ +use std::{fs::File, io, process::Stdio, sync::Arc}; + +/// Describes where to direct the stdout or stderr output stream of external command to. +#[derive(Debug, Clone)] +pub enum OutDest { + /// Redirect the stdout and/or stderr of one command as the input for the next command in the pipeline. + /// + /// The output pipe will be available as the `stdout` of `PipelineData::ExternalStream`. + /// + /// If stdout and stderr are both set to `Pipe`, + /// then they will combined into the `stdout` of `PipelineData::ExternalStream`. + Pipe, + /// Capture output to later be collected into a [`Value`](crate::Value), `Vec`, or used in some other way. + /// + /// The output stream(s) will be available in the `stdout` or `stderr` of `PipelineData::ExternalStream`. + /// + /// This is similar to `Pipe` but will never combine stdout and stderr + /// or place an external command's stderr into `stdout` of `PipelineData::ExternalStream`. + Capture, + /// Ignore output. + /// + /// This will forward output to the null device for the platform. + Null, + /// Output to nushell's stdout or stderr. + /// + /// This causes external commands to inherit nushell's stdout or stderr. + Inherit, + /// Redirect output to a file. + File(Arc), // Arc, since we sometimes need to clone `OutDest` into iterators, etc. +} + +impl From for OutDest { + fn from(file: File) -> Self { + Arc::new(file).into() + } +} + +impl From> for OutDest { + fn from(file: Arc) -> Self { + Self::File(file) + } +} + +impl TryFrom<&OutDest> for Stdio { + type Error = io::Error; + + fn try_from(out_dest: &OutDest) -> Result { + match out_dest { + OutDest::Pipe | OutDest::Capture => Ok(Self::piped()), + OutDest::Null => Ok(Self::null()), + OutDest::Inherit => Ok(Self::inherit()), + OutDest::File(file) => Ok(file.try_clone()?.into()), + } + } +}