mirror of
https://github.com/nushell/nushell
synced 2024-12-28 14:03:09 +00:00
Rename IoStream
to OutDest
(#12433)
# Description I spent a while trying to come up with a good name for what is currently `IoStream`. Looking back, this name is not the best, because it: 1. Implies that it is a stream, when it all it really does is specify the output destination for a stream/pipeline. 2. Implies that it handles input and output, when it really only handles output. So, this PR renames `IoStream` to `OutDest` instead, which should be more clear.
This commit is contained in:
parent
6536fa5ff7
commit
d7ba8872bf
28 changed files with 263 additions and 260 deletions
|
@ -25,7 +25,7 @@ impl NuCompleter {
|
|||
pub fn new(engine_state: Arc<EngineState>, stack: Stack) -> Self {
|
||||
Self {
|
||||
engine_state,
|
||||
stack: stack.reset_stdio().capture(),
|
||||
stack: stack.reset_out_dest().capture(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ impl CustomCompletion {
|
|||
pub fn new(engine_state: Arc<EngineState>, 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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
(Some(IoStream::Null), None)
|
||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||
(Some(OutDest::Null), None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
6
crates/nu-command/src/env/config/utils.rs
vendored
6
crates/nu-command/src/env/config/utils.rs
vendored
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
2
crates/nu-command/src/env/with_env.rs
vendored
2
crates/nu-command/src/env/with_env.rs
vendored
|
@ -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<String, Value> = HashMap::new();
|
||||
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
(Some(IoStream::Capture), Some(IoStream::Capture))
|
||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
(Some(IoStream::Capture), Some(IoStream::Capture))
|
||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
(Some(IoStream::Capture), Some(IoStream::Capture))
|
||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||
(Some(OutDest::Capture), Some(OutDest::Capture))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PipelineData, ShellError> {
|
||||
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())?;
|
||||
|
|
|
@ -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<String>,
|
||||
pub args: Vec<Spanned<String>>,
|
||||
pub arg_keep_raw: Vec<bool>,
|
||||
pub out: IoStream,
|
||||
pub err: IoStream,
|
||||
pub out: OutDest,
|
||||
pub err: OutDest,
|
||||
pub env_vars: HashMap<String, String>,
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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::<WithoutDebug>(engine_state, stack, expr)?;
|
||||
match result {
|
||||
Value::Bool { val, .. } => Ok(val),
|
||||
|
@ -96,7 +96,7 @@ impl CallExt for Call {
|
|||
name: &str,
|
||||
) -> Result<Option<T>, 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::<WithoutDebug>(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<Vec<T>, 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<Option<T>, 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::<WithoutDebug>(engine_state, stack, expr)?;
|
||||
FromValue::from_value(result).map(Some)
|
||||
} else {
|
||||
|
@ -157,7 +157,7 @@ impl CallExt for Call {
|
|||
pos: usize,
|
||||
) -> Result<T, 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::<WithoutDebug>(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<T, ShellError> {
|
||||
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::<WithoutDebug>(engine_state, stack, expr)?;
|
||||
FromValue::from_value(result)
|
||||
} else if self.parser_info.is_empty() {
|
||||
|
|
|
@ -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<D: DebugContext>(
|
|||
// 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<D: DebugContext>(
|
|||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
target: &RedirectionTarget,
|
||||
next_out: Option<IoStream>,
|
||||
next_out: Option<OutDest>,
|
||||
) -> Result<Redirection, ShellError> {
|
||||
match target {
|
||||
RedirectionTarget::File { expr, append, .. } => {
|
||||
|
@ -337,7 +337,7 @@ fn eval_redirection<D: DebugContext>(
|
|||
}
|
||||
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<D: DebugContext>(
|
|||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
element_redirection: Option<&PipelineRedirection>,
|
||||
pipe_redirection: (Option<IoStream>, Option<IoStream>),
|
||||
pipe_redirection: (Option<OutDest>, Option<OutDest>),
|
||||
) -> Result<(Option<Redirection>, Option<Redirection>), ShellError> {
|
||||
let (next_out, next_err) = pipe_redirection;
|
||||
|
||||
|
@ -363,7 +363,7 @@ fn eval_element_redirection<D: DebugContext>(
|
|||
target,
|
||||
} => {
|
||||
let stderr = eval_redirection::<D>(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<D: DebugContext>(
|
|||
}
|
||||
}
|
||||
|
||||
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<D: DebugContext>(
|
|||
|
||||
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::<D>(
|
||||
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) =
|
||||
|
|
|
@ -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::<WithoutDebug>(engine_state, stack, &block, input)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
) -> (Option<OutDest>, Option<OutDest>) {
|
||||
if let Some(first) = self.pipelines.first() {
|
||||
first.stdio_redirect(engine_state)
|
||||
first.pipe_redirection(engine_state)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
) -> (Option<OutDest>, Option<OutDest>) {
|
||||
// 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,
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
self.expr.expr.stdio_redirect(engine_state)
|
||||
) -> (Option<OutDest>, Option<OutDest>) {
|
||||
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<IoStream>, Option<IoStream>) {
|
||||
) -> (Option<OutDest>, Option<OutDest>) {
|
||||
if let Some(first) = self.elements.first() {
|
||||
first.stdio_redirect(engine_state)
|
||||
first.pipe_redirection(engine_state)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
|
|
|
@ -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<IoStream>, Option<IoStream>) {
|
||||
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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<Arc<Stack>>,
|
||||
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
|
||||
pub parent_deletions: Vec<VarId>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<IoStream>,
|
||||
pub pipe_stdout: Option<OutDest>,
|
||||
/// The stream to use for the next command's stderr.
|
||||
pub pipe_stderr: Option<IoStream>,
|
||||
pub pipe_stderr: Option<OutDest>,
|
||||
/// 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<IoStream>,
|
||||
pub parent_stdout: Option<OutDest>,
|
||||
/// 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<IoStream>,
|
||||
pub parent_stderr: Option<OutDest>,
|
||||
}
|
||||
|
||||
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<IoStream> {
|
||||
fn push_stdout(&mut self, stdout: OutDest) -> Option<OutDest> {
|
||||
let stdout = mem::replace(&mut self.stdout, stdout);
|
||||
mem::replace(&mut self.parent_stdout, Some(stdout))
|
||||
}
|
||||
|
||||
fn push_stderr(&mut self, stderr: IoStream) -> Option<IoStream> {
|
||||
fn push_stderr(&mut self, stderr: OutDest) -> Option<OutDest> {
|
||||
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<IoStream>,
|
||||
old_pipe_stderr: Option<IoStream>,
|
||||
old_parent_stdout: Option<IoStream>,
|
||||
old_parent_stderr: Option<IoStream>,
|
||||
old_pipe_stdout: Option<OutDest>,
|
||||
old_pipe_stderr: Option<OutDest>,
|
||||
old_parent_stdout: Option<OutDest>,
|
||||
old_parent_stderr: Option<OutDest>,
|
||||
}
|
||||
|
||||
impl<'a> StackIoGuard<'a> {
|
||||
|
@ -114,32 +114,33 @@ impl<'a> StackIoGuard<'a> {
|
|||
stdout: Option<Redirection>,
|
||||
stderr: Option<Redirection>,
|
||||
) -> 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<IoStream>,
|
||||
old_pipe_stderr: Option<IoStream>,
|
||||
old_pipe_stdout: Option<OutDest>,
|
||||
old_pipe_stderr: Option<OutDest>,
|
||||
}
|
||||
|
||||
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<IoStream>,
|
||||
old_pipe_stderr: Option<IoStream>,
|
||||
old_stdout: Option<IoStream>,
|
||||
old_stderr: Option<IoStream>,
|
||||
old_pipe_stdout: Option<OutDest>,
|
||||
old_pipe_stderr: Option<OutDest>,
|
||||
old_stdout: Option<OutDest>,
|
||||
old_stderr: Option<OutDest>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<File>), // Arc<File>, since we sometimes need to clone `IoStream` into iterators, etc.
|
||||
}
|
||||
|
||||
impl From<File> for IoStream {
|
||||
fn from(file: File) -> Self {
|
||||
Arc::new(file).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<File>> for IoStream {
|
||||
fn from(file: Arc<File>) -> Self {
|
||||
Self::File(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&IoStream> for Stdio {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(stream: &IoStream) -> Result<Self, Self::Error> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<RawStream>,
|
||||
io_stream: &IoStream,
|
||||
out_dest: &OutDest,
|
||||
) -> Result<RawStream, Option<RawStream>> {
|
||||
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<i64, ShellError> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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()?)?;
|
||||
}
|
||||
}
|
||||
|
|
55
crates/nu-protocol/src/pipeline_data/out_dest.rs
Normal file
55
crates/nu-protocol/src/pipeline_data/out_dest.rs
Normal file
|
@ -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<File>), // Arc<File>, since we sometimes need to clone `OutDest` into iterators, etc.
|
||||
}
|
||||
|
||||
impl From<File> for OutDest {
|
||||
fn from(file: File) -> Self {
|
||||
Arc::new(file).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<File>> for OutDest {
|
||||
fn from(file: Arc<File>) -> Self {
|
||||
Self::File(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&OutDest> for Stdio {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(out_dest: &OutDest) -> Result<Self, Self::Error> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue