Improve empty pipelines (#7383)

# Description

This fix changes pipelines to allow them to actually be empty. Mapping
over empty pipelines gives empty pipelines. Empty pipelines immediately
return `None` when iterated.

This removes a some of where `Span::new(0, 0)` was coming from, though
there are other cases where we still use it.

# User-Facing Changes

None

# Tests + Formatting

Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
JT 2022-12-08 07:31:57 +13:00 committed by GitHub
parent d18587330a
commit eaec480f42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 194 additions and 190 deletions

View File

@ -92,7 +92,7 @@ impl NuCompleter {
&self.engine_state,
&mut callee_stack,
block,
PipelineData::new(span),
PipelineData::empty(),
true,
true,
);

View File

@ -67,7 +67,7 @@ impl Completer for CustomCompletion {
redirect_stdout: true,
redirect_stderr: true,
},
PipelineData::new(span),
PipelineData::empty(),
);
let mut custom_completion_options = None;

View File

@ -8,7 +8,7 @@ use nu_path::canonicalize_with;
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
#[cfg(feature = "plugin")]
use nu_protocol::Spanned;
use nu_protocol::{HistoryFileFormat, PipelineData, Span};
use nu_protocol::{HistoryFileFormat, PipelineData};
use std::path::PathBuf;
#[cfg(feature = "plugin")]
@ -38,7 +38,7 @@ pub fn read_plugin_file(
stack,
&contents,
&plugin_filename,
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
}
}
@ -85,7 +85,7 @@ pub fn eval_config_contents(
stack,
&contents,
&config_filename,
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
// Merge the environment in case env vars changed in the config

View File

@ -39,13 +39,7 @@ pub fn evaluate_file(
if working_set.find_decl(b"main", &Type::Any).is_some() {
let args = format!("main {}", args.join(" "));
if !eval_source(
engine_state,
stack,
&file,
&path,
PipelineData::new(Span::new(0, 0)),
) {
if !eval_source(engine_state, stack, &file, &path, PipelineData::empty()) {
std::process::exit(1);
}
if !eval_source(engine_state, stack, args.as_bytes(), "<commandline>", input) {

View File

@ -50,14 +50,13 @@ Since this command has no output, there is no point in piping it with other comm
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
let no_newline = call.has_flag("no-newline");
let to_stderr = call.has_flag("stderr");
let head = call.head;
for arg in args {
arg.into_pipeline_data()
.print(engine_state, stack, no_newline, to_stderr)?;
}
Ok(PipelineData::new(head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -4,7 +4,7 @@ use log::info;
use nu_engine::eval_subexpression;
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
Config, PipelineData, Span, Value,
Config, PipelineData, Value,
};
use reedline::Prompt;
@ -37,12 +37,8 @@ fn get_prompt_string(
let block = engine_state.get_block(block_id);
let mut stack = stack.captures_to_stack(&captures);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(
engine_state,
&mut stack,
block,
PipelineData::new(Span::new(0, 0)), // Don't try this at home, 0 span is ignored
);
let ret_val =
eval_subexpression(engine_state, &mut stack, block, PipelineData::empty());
info!(
"get_prompt_string (block) {}:{}:{}",
file!(),
@ -62,12 +58,7 @@ fn get_prompt_string(
Value::Block { val: block_id, .. } => {
let block = engine_state.get_block(block_id);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(
engine_state,
stack,
block,
PipelineData::new(Span::new(0, 0)), // Don't try this at home, 0 span is ignored
);
let ret_val = eval_subexpression(engine_state, stack, block, PipelineData::empty());
info!(
"get_prompt_string (block) {}:{}:{}",
file!(),

View File

@ -149,7 +149,7 @@ pub fn evaluate_repl(
stack,
s.item.as_bytes(),
&format!("entry #{}", entry_num),
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
engine_state.merge_env(stack, get_guaranteed_cwd(engine_state, stack))?;
}
@ -431,7 +431,7 @@ pub fn evaluate_repl(
stack,
s.as_bytes(),
&format!("entry #{}", entry_num),
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
}
let cmd_duration = start_time.elapsed();
@ -637,7 +637,7 @@ pub fn eval_string_with_input(
let input_as_pipeline_data = match input {
Some(input) => PipelineData::Value(input, None),
None => PipelineData::new(Span::test_data()),
None => PipelineData::empty(),
};
eval_block(
@ -722,7 +722,7 @@ pub fn eval_hook(
val: "condition".to_string(),
span: value_span,
};
let mut output = PipelineData::new(Span::new(0, 0));
let mut output = PipelineData::empty();
let code_path = PathMember::String {
val: "code".to_string(),
@ -823,7 +823,7 @@ pub fn eval_hook(
};
engine_state.merge_delta(delta)?;
let input = PipelineData::new(value_span);
let input = PipelineData::empty();
let var_ids: Vec<VarId> = vars
.into_iter()
@ -943,7 +943,7 @@ pub fn run_hook_block(
) -> Result<Value, ShellError> {
let block = engine_state.get_block(block_id);
let input = optional_input.unwrap_or_else(|| PipelineData::new(span));
let input = optional_input.unwrap_or_else(PipelineData::empty);
let mut callee_stack = stack.gather_captures(&block.captures);

View File

@ -43,10 +43,10 @@ impl Command for Alias {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -37,14 +37,13 @@ impl Command for Ast {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let pipeline: Spanned<String> = call.req(engine_state, stack, 0)?;
let mut working_set = StateWorkingSet::new(engine_state);
let (output, err) = parse(&mut working_set, None, pipeline.item.as_bytes(), false, &[]);
eprintln!("output: {:#?}\nerror: {:#?}", output, err);
Ok(PipelineData::new(head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -36,10 +36,10 @@ impl Command for Def {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -62,10 +62,10 @@ def-env cd_with_fallback [arg = ""] {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -169,9 +169,9 @@ impl Command for Do {
trim_end_newline,
}),
Ok(PipelineData::Value(Value::Error { .. }, ..)) if ignore_shell_errors => {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
Err(_) if ignore_shell_errors => Ok(PipelineData::new(call.head)),
Err(_) if ignore_shell_errors => Ok(PipelineData::empty()),
r => r,
}
}

View File

@ -39,10 +39,10 @@ impl Command for ExportAlias {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -36,10 +36,10 @@ impl Command for ExportDef {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -62,10 +62,10 @@ export def-env cd_with_fallback [arg = ""] {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -35,10 +35,10 @@ impl Command for ExportExtern {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -34,10 +34,10 @@ impl Command for ExportUse {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -35,10 +35,10 @@ impl Command for Extern {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -110,7 +110,7 @@ impl Command for For {
&engine_state,
stack,
&block,
PipelineData::new(head),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
) {
@ -155,7 +155,7 @@ impl Command for For {
&engine_state,
stack,
&block,
PipelineData::new(head),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
) {
@ -181,14 +181,14 @@ impl Command for For {
&engine_state,
stack,
&block,
PipelineData::new(head),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)?
.into_value(head);
}
}
Ok(PipelineData::new(head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -62,7 +62,7 @@ This command is a parser keyword. For details, check:
stack.remove_env_var(engine_state, &env_var_name.item);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -63,7 +63,7 @@ impl Command for HideEnv {
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -102,7 +102,7 @@ impl Command for If {
.map(|res| res.0)
}
} else {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
}
x => Err(ShellError::CantConvert(

View File

@ -32,7 +32,7 @@ impl Command for Ignore {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
input.into_value(call.head);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -73,7 +73,7 @@ impl Command for Let {
//println!("Adding: {:?} to {}", rhs, var_id);
stack.add_var(var_id, rhs.into_value(call.head));
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -55,7 +55,7 @@ impl Command for Loop {
engine_state,
stack,
block,
PipelineData::new(call.head),
PipelineData::empty(),
call.redirect_stdout,
call.redirect_stderr,
) {
@ -73,7 +73,7 @@ impl Command for Loop {
}
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -35,10 +35,10 @@ impl Command for Module {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -73,7 +73,7 @@ impl Command for Mut {
//println!("Adding: {:?} to {}", rhs, var_id);
stack.add_var(var_id, rhs.into_value(call.head));
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -88,7 +88,7 @@ impl Command for OverlayHide {
stack.add_env_var(name, val);
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -49,7 +49,7 @@ This command is a parser keyword. For details, check:
stack.add_overlay(name_arg.item);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -172,7 +172,7 @@ impl Command for OverlayUse {
caller_stack.add_overlay(overlay_name);
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -49,10 +49,10 @@ impl Command for Register {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -71,12 +71,12 @@ impl Command for Try {
engine_state,
stack,
catch_block,
PipelineData::new(call.head),
PipelineData::empty(),
false,
false,
)
} else {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
}
// external command may fail to run
@ -118,12 +118,12 @@ impl Command for Try {
engine_state,
stack,
catch_block,
PipelineData::new(call.head),
PipelineData::empty(),
false,
false,
)
} else {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
} else {
Ok(PipelineData::ExternalStream {

View File

@ -112,7 +112,7 @@ impl Command for Use {
));
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -63,7 +63,7 @@ impl Command for While {
engine_state,
stack,
block,
PipelineData::new(call.head),
PipelineData::empty(),
call.redirect_stdout,
call.redirect_stderr,
) {
@ -94,7 +94,7 @@ impl Command for While {
}
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -22,7 +22,7 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
let delta = {
// Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible
let mut working_set = StateWorkingSet::new(&*engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
working_set.add_decl(Box::new(Let));
working_set.add_decl(Box::new(ToDataFrame));
working_set.add_decl(Box::new(ToLazyFrame));
@ -49,7 +49,7 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
let start = std::time::Instant::now();
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&*engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
let (output, err) = parse(
&mut working_set,
None,
@ -75,7 +75,7 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
&engine_state,
&mut stack,
&block,
PipelineData::new(Span::test_data()),
PipelineData::empty(),
true,
true,
) {

View File

@ -108,6 +108,6 @@ impl Command for ConfigReset {
}
}
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
}

View File

@ -50,7 +50,7 @@ impl Command for ExportEnv {
redirect_env(engine_state, caller_stack, &callee_stack);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -57,7 +57,7 @@ impl Command for LetEnv {
} else {
stack.add_env_var(env_var.item, rhs);
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -57,7 +57,7 @@ impl Command for LoadEnv {
stack.add_env_var(env_var, rhs);
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
None => match input {
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
@ -81,7 +81,7 @@ impl Command for LoadEnv {
stack.add_env_var(env_var, rhs);
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
_ => Err(ShellError::UnsupportedInput(
"'load-env' expects a single record".into(),

View File

@ -59,7 +59,7 @@ mod test_examples {
let delta = {
// Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible
let mut working_set = StateWorkingSet::new(&*engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
working_set.add_decl(Box::new(Let));
working_set.add_decl(Box::new(Str));
working_set.add_decl(Box::new(StrJoin));
@ -215,10 +215,10 @@ mod test_examples {
);
engine_state
.merge_env(&mut stack, &cwd)
.merge_env(&mut stack, cwd)
.expect("Error merging environment");
let empty_input = PipelineData::new(Span::test_data());
let empty_input = PipelineData::empty();
let result = eval(example.example, empty_input, cwd, engine_state);
// Note. Value implements PartialEq for Bool, Int, Float, String and Block
@ -320,7 +320,7 @@ mod test_examples {
block.pipelines[0].elements.truncate(&n_expressions - 1);
if !block.pipelines[0].elements.is_empty() {
let empty_input = PipelineData::new(Span::test_data());
let empty_input = PipelineData::empty();
Some(eval_block(block, empty_input, cwd, engine_state, delta))
} else {
Some(Value::nothing(Span::test_data()))

View File

@ -196,7 +196,7 @@ impl Command for Cd {
match have_permission(&path_tointo) {
PermissionResult::PermissionOk => {
stack.add_env_var("PWD".into(), path_value);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError(format!(
"Cannot change directory to {}: {}",

View File

@ -2,8 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, RawStream, ShellError, Signature, Span, Spanned, SyntaxShape,
Value,
Category, Example, PipelineData, RawStream, ShellError, Signature, Spanned, SyntaxShape, Value,
};
use std::fs::File;
use std::io::{BufWriter, Write};
@ -160,7 +159,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::Binary { val, .. } => {
if let Err(err) = file.write_all(&val) {
@ -169,7 +168,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::List { vals, .. } => {
let val = vals
@ -185,7 +184,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
v => Err(ShellError::UnsupportedInput(
format!("{:?} not supported", v.get_type()),
@ -194,7 +193,7 @@ impl Command for Save {
}
} else {
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(span)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
stderr,
@ -202,16 +201,16 @@ impl Command for Save {
} => {
// delegate a thread to redirect stderr to result.
let handler = stderr.map(|stderr_stream| match stderr_file {
Some(stderr_file) => std::thread::spawn(move || {
stream_to_file(stderr_stream, stderr_file, span)
}),
Some(stderr_file) => {
std::thread::spawn(move || stream_to_file(stderr_stream, stderr_file))
}
None => std::thread::spawn(move || {
let _ = stderr_stream.into_bytes();
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}),
});
let res = stream_to_file(stream, file, span);
let res = stream_to_file(stream, file);
if let Some(h) = handler {
match h.join() {
Err(err) => {
@ -236,7 +235,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::Binary { val, .. } => {
if let Err(err) = file.write_all(&val) {
@ -245,7 +244,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::List { vals, .. } => {
let val = vals
@ -261,7 +260,7 @@ impl Command for Save {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
v => Err(ShellError::UnsupportedInput(
format!("{:?} not supported", v.get_type()),
@ -303,11 +302,7 @@ impl Command for Save {
}
}
fn stream_to_file(
mut stream: RawStream,
file: File,
span: Span,
) -> Result<PipelineData, ShellError> {
fn stream_to_file(mut stream: RawStream, file: File) -> Result<PipelineData, ShellError> {
let mut writer = BufWriter::new(file);
stream
@ -331,5 +326,5 @@ fn stream_to_file(
}
Ok(())
})
.map(|_| PipelineData::new(span))
.map(|_| PipelineData::empty())
}

View File

@ -190,7 +190,7 @@ impl Command for Touch {
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -271,7 +271,7 @@ impl Command for Watch {
}
}
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -72,6 +72,7 @@ fn getcol(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(
Value::List {
vals: input_vals,

View File

@ -156,6 +156,7 @@ with 'transpose' first."#
let redirect_stderr = call.redirect_stderr;
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input
@ -223,7 +224,7 @@ with 'transpose' first."#
}
})
.into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -116,6 +116,7 @@ impl Command for EachWhile {
let redirect_stderr = call.redirect_stderr;
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input
@ -186,7 +187,7 @@ impl Command for EachWhile {
})
.fuse()
.into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -103,6 +103,7 @@ fn empty(
.into_pipeline_data())
} else {
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::ExternalStream { stdout, .. } => match stdout {
Some(s) => {
let bytes = s.into_bytes();

View File

@ -321,6 +321,7 @@ fn find_with_rest_and_highlight(
let ls_colors = get_ls_colors(ls_colors_env_str);
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(_, _) => input
.map(
move |mut x| match &mut x {
@ -446,7 +447,7 @@ fn find_with_rest_and_highlight(
)
.into_pipeline_data(ctrlc)
.set_metadata(meta)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(span)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -110,7 +110,7 @@ impl Command for Last {
if let Some(last) = last {
Ok(last.into_pipeline_data().set_metadata(metadata))
} else {
Ok(PipelineData::new(span).set_metadata(metadata))
Ok(PipelineData::empty().set_metadata(metadata))
}
}
}

View File

@ -97,6 +97,7 @@ fn getcol(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(
Value::List {
vals: input_vals,

View File

@ -71,6 +71,7 @@ impl Command for Lines {
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::ListStream(stream, ..) => {
let iter = stream
.into_iter()
@ -112,7 +113,7 @@ impl Command for Lines {
format!("Not supported input: {}", val.as_string()?),
head,
)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -81,6 +81,7 @@ impl Command for ParEach {
let redirect_stderr = call.redirect_stderr;
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { val, .. }, ..) => Ok(val
.into_range_iter(ctrlc.clone())?
.enumerate()
@ -272,7 +273,7 @@ impl Command for ParEach {
.into_iter()
.flatten()
.into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -219,7 +219,7 @@ impl Command for Reduce {
engine_state,
&mut stack,
block,
PipelineData::new(span),
PipelineData::empty(),
// redirect stdout until its the last input value
redirect_stdout || input_iter.peek().is_some(),
redirect_stderr,

View File

@ -249,7 +249,7 @@ fn select(
Ok(v.into_pipeline_data().set_metadata(metadata))
}
}
_ => Ok(PipelineData::new(span)),
_ => Ok(PipelineData::empty()),
}
}

View File

@ -96,7 +96,7 @@ impl Command for SkipUntil {
&engine_state,
&mut stack,
&block,
PipelineData::new(span),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)

View File

@ -97,7 +97,7 @@ impl Command for SkipWhile {
&engine_state,
&mut stack,
&block,
PipelineData::new(span),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)

View File

@ -92,7 +92,7 @@ impl Command for TakeUntil {
&engine_state,
&mut stack,
&block,
PipelineData::new(span),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)

View File

@ -92,7 +92,7 @@ impl Command for TakeWhile {
&engine_state,
&mut stack,
&block,
PipelineData::new(span),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)

View File

@ -62,6 +62,7 @@ impl Command for Where {
let redirect_stderr = call.redirect_stderr;
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input
@ -115,9 +116,7 @@ impl Command for Where {
}
})
.into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(call.head))
}
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -39,6 +39,7 @@ impl Command for Wrap {
let name: String = call.req(engine_state, stack, 0)?;
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::Range { .. }, ..)
| PipelineData::Value(Value::List { .. }, ..)
| PipelineData::ListStream { .. } => Ok(input

View File

@ -54,7 +54,7 @@ impl Command for History {
if clear {
let _ = std::fs::remove_file(history_path);
// TODO: FIXME also clear the auxiliary files when using sqlite
Ok(PipelineData::new(head))
Ok(PipelineData::empty())
} else {
let history_reader: Option<Box<dyn ReedlineHistory>> =
match engine_state.config.history_file_format {

View File

@ -176,7 +176,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::Binary { val, .. } => {
if let Err(err) = file.write_all(&val) {
@ -185,7 +185,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::List { vals, .. } => {
let val = vals
@ -201,7 +201,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
v => Err(ShellError::UnsupportedInput(
format!("{:?} not supported", v.get_type()),
@ -211,7 +211,7 @@ impl Command for SubCommand {
} else {
match value {
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
PipelineData::ExternalStream {
stdout: Some(mut stream),
@ -240,7 +240,7 @@ impl Command for SubCommand {
}
Ok(())
})
.map(|_| PipelineData::new(span))
.map(|_| PipelineData::empty())
}
value => match value.into_value(span) {
Value::String { val, .. } => {
@ -250,7 +250,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::Binary { val, .. } => {
if let Err(err) = file.write_all(&val) {
@ -259,7 +259,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
Value::List { vals, .. } => {
let val = vals
@ -275,7 +275,7 @@ impl Command for SubCommand {
file.flush()?
}
Ok(PipelineData::new(span))
Ok(PipelineData::empty())
}
v => Err(ShellError::UnsupportedInput(
format!("{:?} not supported", v.get_type()),

View File

@ -99,7 +99,7 @@ impl Command for Enter {
stack.add_env_var("PWD".into(), new_path);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -101,7 +101,7 @@ impl Command for Exit {
stack.add_env_var("PWD".into(), new_path);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
}

View File

@ -121,7 +121,7 @@ fn switch_shell(
stack.add_env_var("PWD".into(), new_path);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
fn list_shells(

View File

@ -180,7 +180,7 @@ fn detect_columns(
})
.into_pipeline_data(ctrlc))
} else {
Ok(PipelineData::new(name_span))
Ok(PipelineData::empty())
}
}

View File

@ -66,7 +66,7 @@ documentation link at https://docs.rs/encoding_rs/0.8.28/encoding_rs/#statics"#
let encoding: Spanned<String> = call.req(engine_state, stack, 0)?;
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -66,7 +66,7 @@ documentation link at https://docs.rs/encoding_rs/0.8.28/encoding_rs/#statics"#
let encoding: Spanned<String> = call.req(engine_state, stack, 0)?;
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
..

View File

@ -44,7 +44,7 @@ impl Command for Benchmark {
engine_state,
&mut stack,
block,
PipelineData::new(call.head),
PipelineData::empty(),
redirect_stdout,
redirect_stderr,
)?

View File

@ -88,7 +88,7 @@ prints out the list properly."#
use_grid_icons,
)?)
} else {
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
}
PipelineData::ListStream(stream, ..) => {
@ -106,7 +106,7 @@ prints out the list properly."#
)?)
} else {
// dbg!(data);
Ok(PipelineData::new(call.head))
Ok(PipelineData::empty())
}
}
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {

View File

@ -43,7 +43,7 @@ fn sets_the_column_from_a_block_full_stream_output() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
{content: null}
| update content { open --raw cargo_sample.toml | lines | first 5 }
| get content.1
| str contains "nu"
@ -58,7 +58,7 @@ fn sets_the_column_from_a_subexpression() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
{content: null}
| update content (open --raw cargo_sample.toml | lines | first 5)
| get content.1
| str contains "nu"

View File

@ -43,7 +43,7 @@ fn sets_the_column_from_a_block_full_stream_output() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
{content: null}
| upsert content { open --raw cargo_sample.toml | lines | first 5 }
| get content.1
| str contains "nu"
@ -58,7 +58,7 @@ fn sets_the_column_from_a_subexpression() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
{content: null}
| upsert content (open --raw cargo_sample.toml | lines | first 5)
| get content.1
| str contains "nu"

View File

@ -350,7 +350,7 @@ fn get_converted_value(
engine_state,
&mut stack,
block,
PipelineData::new(val_span),
PipelineData::new_with_metadata(None, val_span),
true,
true,
);

View File

@ -339,10 +339,7 @@ pub fn eval_expression(
}
Expr::Call(call) => {
// FIXME: protect this collect with ctrl-c
Ok(
eval_call(engine_state, stack, call, PipelineData::new(call.head))?
.into_value(call.head),
)
Ok(eval_call(engine_state, stack, call, PipelineData::empty())?.into_value(call.head))
}
Expr::ExternalCall(head, args, is_subexpression) => {
let span = head.span;
@ -352,7 +349,7 @@ pub fn eval_expression(
stack,
head,
args,
PipelineData::new(span),
PipelineData::empty(),
false,
false,
*is_subexpression,
@ -536,7 +533,7 @@ pub fn eval_expression(
// FIXME: protect this collect with ctrl-c
Ok(
eval_subexpression(engine_state, stack, block, PipelineData::new(expr.span))?
eval_subexpression(engine_state, stack, block, PipelineData::empty())?
.into_value(expr.span),
)
}
@ -1087,14 +1084,28 @@ pub fn eval_block(
match engine_state.find_decl("table".as_bytes(), &[]) {
Some(decl_id) => {
let table = engine_state.get_decl(decl_id).run(
engine_state,
stack,
&Call::new(Span::new(0, 0)),
input,
)?;
let table = engine_state.get_decl(decl_id);
print_or_return(table, config)?;
if let Some(block_id) = table.get_block_id() {
let block = engine_state.get_block(block_id);
eval_block(
engine_state,
stack,
block,
input,
redirect_stdout,
redirect_stderr,
)?;
} else {
let table = table.run(
engine_state,
stack,
&Call::new(Span::new(0, 0)),
input,
)?;
print_or_return(table, config)?;
}
}
None => {
print_or_return(input, config)?;
@ -1103,7 +1114,7 @@ pub fn eval_block(
}
}
input = PipelineData::new(Span::unknown())
input = PipelineData::empty()
}
}

View File

@ -5,6 +5,7 @@ use super::NuSpan;
pub fn collect_pipeline(input: PipelineData) -> (Vec<String>, Vec<Vec<Value>>) {
match input {
PipelineData::Empty => (vec![], vec![]),
PipelineData::Value(value, ..) => collect_input(value),
PipelineData::ListStream(mut stream, ..) => {
let mut records = vec![];

View File

@ -53,6 +53,7 @@ pub enum PipelineData {
metadata: Option<PipelineMetadata>,
trim_end_newline: bool,
},
Empty,
}
#[derive(Debug, Clone)]
@ -67,19 +68,20 @@ pub enum DataSource {
}
impl PipelineData {
pub fn new(span: Span) -> PipelineData {
PipelineData::Value(Value::Nothing { span }, None)
}
pub fn new_with_metadata(metadata: Option<PipelineMetadata>, span: Span) -> PipelineData {
PipelineData::Value(Value::Nothing { span }, metadata)
}
pub fn empty() -> PipelineData {
PipelineData::Empty
}
pub fn metadata(&self) -> Option<PipelineMetadata> {
match self {
PipelineData::ListStream(_, x) => x.clone(),
PipelineData::ExternalStream { metadata: x, .. } => x.clone(),
PipelineData::Value(_, x) => x.clone(),
PipelineData::Empty => None,
}
}
@ -88,6 +90,7 @@ impl PipelineData {
PipelineData::ListStream(_, x) => *x = metadata,
PipelineData::ExternalStream { metadata: x, .. } => *x = metadata,
PipelineData::Value(_, x) => *x = metadata,
PipelineData::Empty => {}
}
self
@ -95,6 +98,7 @@ impl PipelineData {
pub fn is_nothing(&self) -> bool {
matches!(self, PipelineData::Value(Value::Nothing { .. }, ..))
|| matches!(self, PipelineData::Empty)
}
/// PipelineData doesn't always have a Span, but we can try!
@ -103,11 +107,13 @@ impl PipelineData {
PipelineData::ListStream(..) => None,
PipelineData::ExternalStream { span, .. } => Some(*span),
PipelineData::Value(v, _) => v.span().ok(),
PipelineData::Empty => None,
}
}
pub fn into_value(self, span: Span) -> Value {
match self {
PipelineData::Empty => Value::nothing(span),
PipelineData::Value(Value::Nothing { .. }, ..) => Value::nothing(span),
PipelineData::Value(v, ..) => v,
PipelineData::ListStream(s, ..) => Value::List {
@ -202,6 +208,7 @@ impl PipelineData {
pub fn collect_string(self, separator: &str, config: &Config) -> Result<String, ShellError> {
match self {
PipelineData::Empty => Ok(String::new()),
PipelineData::Value(v, ..) => Ok(v.into_string(separator, config)),
PipelineData::ListStream(s, ..) => Ok(s.into_string(separator, config)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(String::new()),
@ -238,6 +245,7 @@ impl PipelineData {
span: Span,
) -> Result<(String, Option<PipelineMetadata>), ShellError> {
match self {
PipelineData::Empty => Ok((String::new(), None)),
PipelineData::Value(Value::String { val, .. }, metadata) => Ok((val, metadata)),
PipelineData::Value(val, _) => {
Err(ShellError::TypeMismatch("string".into(), val.span()?))
@ -306,10 +314,9 @@ impl PipelineData {
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc))
}
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::ListStream(stream, ..) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span::unknown()))
}
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::empty()),
PipelineData::ExternalStream {
stdout: Some(stream),
trim_end_newline,
@ -359,15 +366,14 @@ impl PipelineData {
F: FnMut(Value) -> U + 'static + Send,
{
match self {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().flat_map(f).into_pipeline_data(ctrlc))
}
PipelineData::ListStream(stream, ..) => {
Ok(stream.flat_map(f).into_pipeline_data(ctrlc))
}
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span::unknown()))
}
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::Empty),
PipelineData::ExternalStream {
stdout: Some(stream),
trim_end_newline,
@ -414,13 +420,12 @@ impl PipelineData {
F: FnMut(&Value) -> bool + 'static + Send,
{
match self {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(Value::List { vals, .. }, ..) => {
Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc))
}
PipelineData::ListStream(stream, ..) => Ok(stream.filter(f).into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span::unknown()))
}
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::Empty),
PipelineData::ExternalStream {
stdout: Some(stream),
trim_end_newline,
@ -440,7 +445,7 @@ impl PipelineData {
if f(&v) {
Ok(v.into_pipeline_data())
} else {
Ok(PipelineData::new(collected.span))
Ok(PipelineData::new_with_metadata(None, collected.span))
}
} else {
let v = Value::Binary {
@ -451,7 +456,7 @@ impl PipelineData {
if f(&v) {
Ok(v.into_pipeline_data())
} else {
Ok(PipelineData::new(collected.span))
Ok(PipelineData::new_with_metadata(None, collected.span))
}
}
}
@ -636,6 +641,7 @@ impl Iterator for PipelineIterator {
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
PipelineData::Empty => None,
PipelineData::Value(Value::Nothing { .. }, ..) => None,
PipelineData::Value(v, ..) => Some(std::mem::take(v)),
PipelineData::ListStream(stream, ..) => stream.next(),

View File

@ -3,7 +3,7 @@ use nu_cli::{eval_config_contents, eval_source, report_error};
use nu_parser::ParseError;
use nu_path::canonicalize_with;
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
use nu_protocol::{PipelineData, Span, Spanned};
use nu_protocol::{PipelineData, Spanned};
use nu_utils::{get_default_config, get_default_env};
use std::fs::File;
use std::io::Write;
@ -128,7 +128,7 @@ pub(crate) fn read_default_env_file(engine_state: &mut EngineState, stack: &mut
stack,
config_file.as_bytes(),
"default_env.nu",
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
info!("read_config_file {}:{}:{}", file!(), line!(), column!());
@ -164,7 +164,7 @@ fn eval_default_config(
} else {
"default_config.nu"
},
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
);
// Merge the environment in case env vars changed in the config

View File

@ -22,8 +22,8 @@ use nu_path::canonicalize_with;
use nu_protocol::{
ast::{Call, Expr, Expression, PipelineElement},
engine::{Command, EngineState, Stack, StateWorkingSet},
Category, Example, IntoPipelineData, PipelineData, RawStream, ShellError, Signature, Span,
Spanned, SyntaxShape, Value,
Category, Example, IntoPipelineData, PipelineData, RawStream, ShellError, Signature, Spanned,
SyntaxShape, Value,
};
use nu_utils::stdout_write_all_and_flush;
use std::{
@ -323,7 +323,7 @@ fn main() -> Result<()> {
trim_end_newline: false,
}
} else {
PipelineData::new(Span::new(0, 0))
PipelineData::empty()
};
info!("redirect_stdin {}:{}:{}", file!(), line!(), column!());

View File

@ -220,7 +220,7 @@ pub fn nu_repl() {
outcome_err(&engine_state, &err);
}
let input = PipelineData::new(Span::test_data());
let input = PipelineData::empty();
let config = engine_state.get_config();
match eval_block(&engine_state, &mut stack, &block, input, false, false) {