From b6d269e90a6e183f0db2f504f720ea31e85e7447 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 25 Oct 2021 17:01:02 +1300 Subject: [PATCH] WIP --- Cargo.lock | 67 +++- crates/nu-cli/src/completions.rs | 16 +- .../nu-command/src/conversions/into/binary.rs | 41 +- .../src/conversions/into/command.rs | 10 +- .../src/conversions/into/filesize.rs | 45 +-- crates/nu-command/src/conversions/into/int.rs | 47 +-- crates/nu-command/src/core_commands/alias.rs | 9 +- crates/nu-command/src/core_commands/def.rs | 9 +- crates/nu-command/src/core_commands/do_.rs | 10 +- .../src/core_commands/export_def.rs | 9 +- crates/nu-command/src/core_commands/for_.rs | 34 +- crates/nu-command/src/core_commands/help.rs | 26 +- crates/nu-command/src/core_commands/hide.rs | 9 +- crates/nu-command/src/core_commands/if_.rs | 18 +- crates/nu-command/src/core_commands/let_.rs | 11 +- crates/nu-command/src/core_commands/module.rs | 9 +- crates/nu-command/src/core_commands/source.rs | 13 +- crates/nu-command/src/core_commands/use_.rs | 9 +- crates/nu-command/src/env/let_env.rs | 11 +- crates/nu-command/src/example_test.rs | 14 +- crates/nu-command/src/experimental/git.rs | 14 +- .../src/experimental/git_checkout.rs | 14 +- .../src/experimental/list_git_branches.rs | 16 +- crates/nu-command/src/filesystem/cd.rs | 9 +- crates/nu-command/src/filesystem/cp.rs | 9 +- crates/nu-command/src/filesystem/ls.rs | 120 +++--- crates/nu-command/src/filesystem/mkdir.rs | 13 +- crates/nu-command/src/filesystem/mv.rs | 9 +- crates/nu-command/src/filesystem/rm.rs | 17 +- crates/nu-command/src/filesystem/touch.rs | 9 +- crates/nu-command/src/filters/each.rs | 349 +++++++++--------- crates/nu-command/src/filters/get.rs | 7 +- crates/nu-command/src/filters/length.rs | 33 +- crates/nu-command/src/filters/lines.rs | 23 +- crates/nu-command/src/filters/select.rs | 66 ++-- crates/nu-command/src/filters/where_.rs | 65 ++-- crates/nu-command/src/filters/wrap.rs | 48 ++- crates/nu-command/src/formats/from/command.rs | 9 +- crates/nu-command/src/formats/from/json.rs | 32 +- crates/nu-command/src/strings/build_string.rs | 12 +- crates/nu-command/src/strings/size.rs | 35 +- crates/nu-command/src/strings/split/chars.rs | 16 +- crates/nu-command/src/strings/split/column.rs | 17 +- .../nu-command/src/strings/split/command.rs | 9 +- crates/nu-command/src/strings/split/row.rs | 17 +- crates/nu-command/src/system/benchmark.rs | 16 +- crates/nu-command/src/system/ps.rs | 11 +- crates/nu-command/src/system/run_external.rs | 53 +-- crates/nu-command/src/system/sys.rs | 12 +- crates/nu-command/src/viewers/griddle.rs | 1 + crates/nu-command/src/viewers/table.rs | 1 + crates/nu-engine/src/documentation.rs | 7 +- crates/nu-engine/src/eval.rs | 63 ++-- crates/nu-parser/tests/test_parser.rs | 5 +- crates/nu-protocol/Cargo.toml | 3 +- crates/nu-protocol/src/engine/command.rs | 27 +- crates/nu-protocol/src/engine/engine_state.rs | 80 ++-- .../src/engine/evaluation_context.rs | 112 +++--- crates/nu-protocol/src/lib.rs | 2 + crates/nu-protocol/src/pipeline_data.rs | 62 ++++ crates/nu-protocol/src/signature.rs | 12 +- crates/nu-protocol/src/value/mod.rs | 127 +------ crates/nu-protocol/src/value/stream.rs | 109 +++--- 63 files changed, 1075 insertions(+), 1013 deletions(-) create mode 100644 crates/nu-protocol/src/pipeline_data.rs diff --git a/Cargo.lock b/Cargo.lock index 696b84d35..f4ea08395 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + [[package]] name = "bstr" version = "0.2.17" @@ -378,6 +387,20 @@ dependencies = [ "libc", ] +[[package]] +name = "im" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111c1983f3c5bb72732df25cddacee9b546d08325fb584b5ebd38148be7b0246" +dependencies = [ + "bitmaps", + "rand_core 0.5.1", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + [[package]] name = "instant" version = "0.1.11" @@ -640,6 +663,7 @@ dependencies = [ "byte-unit", "chrono", "chrono-humanize", + "im", "miette", "serde", "thiserror", @@ -823,7 +847,7 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.3", "rand_hc", ] @@ -834,9 +858,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + [[package]] name = "rand_core" version = "0.6.3" @@ -852,7 +882,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_xoshiro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -1032,6 +1071,16 @@ dependencies = [ "libc", ] +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "smallvec" version = "1.7.0" @@ -1198,6 +1247,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + [[package]] name = "unicode-linebreak" version = "0.1.2" @@ -1237,6 +1292,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "vte" version = "0.10.1" diff --git a/crates/nu-cli/src/completions.rs b/crates/nu-cli/src/completions.rs index 5a7009eb2..0bd47c507 100644 --- a/crates/nu-cli/src/completions.rs +++ b/crates/nu-cli/src/completions.rs @@ -4,26 +4,25 @@ use nu_engine::eval_block; use nu_parser::{flatten_block, parse}; use nu_protocol::{ engine::{EngineState, EvaluationContext, Stack, StateWorkingSet}, - Value, + PipelineData, Value, }; use reedline::Completer; const SEP: char = std::path::MAIN_SEPARATOR; pub struct NuCompleter { - engine_state: Rc>, + engine_state: Box, } impl NuCompleter { - pub fn new(engine_state: Rc>) -> Self { + pub fn new(engine_state: Box) -> Self { Self { engine_state } } } impl Completer for NuCompleter { fn complete(&self, line: &str, pos: usize) -> Vec<(reedline::Span, String)> { - let engine_state = self.engine_state.borrow(); - let mut working_set = StateWorkingSet::new(&*engine_state); + let mut working_set = StateWorkingSet::new(&*self.engine_state); let offset = working_set.next_span_start(); let pos = offset + pos; let (output, _err) = parse(&mut working_set, Some("completer"), line.as_bytes(), false); @@ -49,7 +48,7 @@ impl Completer for NuCompleter { } } } - for scope in &engine_state.scope { + for scope in &self.engine_state.scope { for v in &scope.vars { if v.0.starts_with(prefix) { output.push(( @@ -76,11 +75,10 @@ impl Completer for NuCompleter { engine_state: self.engine_state.clone(), stack: Stack::default(), }; - let result = eval_block(&context, &block, Value::nothing()); + let result = eval_block(&context, &block, PipelineData::new()); let v: Vec<_> = match result { - Ok(Value::List { vals, .. }) => vals - .into_iter() + Ok(pd) => pd .map(move |x| { let s = x.as_string().expect( "FIXME: better error handling for custom completions", diff --git a/crates/nu-command/src/conversions/into/binary.rs b/crates/nu-command/src/conversions/into/binary.rs index 4778d1c07..0658cdb0e 100644 --- a/crates/nu-command/src/conversions/into/binary.rs +++ b/crates/nu-command/src/conversions/into/binary.rs @@ -1,9 +1,10 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, ShellError, Signature, Span, SyntaxShape, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -27,8 +28,8 @@ impl Command for SubCommand { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { into_binary(context, call, input) } @@ -86,26 +87,28 @@ impl Command for SubCommand { fn into_binary( _context: &EvaluationContext, call: &Call, - input: Value, -) -> Result { + input: PipelineData, +) -> Result { let head = call.head; // let column_paths: Vec = call.rest(context, 0)?; - input.map(head, move |v| { - action(v, head) - // FIXME: Add back in cell_path support - // if column_paths.is_empty() { - // action(v, head) - // } else { - // let mut ret = v; - // for path in &column_paths { - // ret = - // ret.swap_data_by_cell_path(path, Box::new(move |old| action(old, old.tag())))?; - // } + Ok(input + .map(move |v| { + action(v, head) + // FIXME: Add back in cell_path support + // if column_paths.is_empty() { + // action(v, head) + // } else { + // let mut ret = v; + // for path in &column_paths { + // ret = + // ret.swap_data_by_cell_path(path, Box::new(move |old| action(old, old.tag())))?; + // } - // Ok(ret) - // } - }) + // Ok(ret) + // } + }) + .into_pipeline_data()) } fn int_to_endian(n: i64) -> Vec { diff --git a/crates/nu-command/src/conversions/into/command.rs b/crates/nu-command/src/conversions/into/command.rs index f74c6436c..37741e7f4 100644 --- a/crates/nu-command/src/conversions/into/command.rs +++ b/crates/nu-command/src/conversions/into/command.rs @@ -2,9 +2,10 @@ use nu_engine::get_full_help; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Signature, Value, + IntoPipelineData, PipelineData, Signature, Value, }; +#[derive(Clone)] pub struct Into; impl Command for Into { @@ -24,12 +25,13 @@ impl Command for Into { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { Ok(Value::String { val: get_full_help(&Into.signature(), &[], context), span: call.head, - }) + } + .into_pipeline_data()) } } diff --git a/crates/nu-command/src/conversions/into/filesize.rs b/crates/nu-command/src/conversions/into/filesize.rs index 1e1b73007..bb2a2a813 100644 --- a/crates/nu-command/src/conversions/into/filesize.rs +++ b/crates/nu-command/src/conversions/into/filesize.rs @@ -1,9 +1,10 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, ShellError, Signature, Span, SyntaxShape, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -27,8 +28,8 @@ impl Command for SubCommand { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { into_filesize(context, call, input) } @@ -114,29 +115,31 @@ impl Command for SubCommand { fn into_filesize( _context: &EvaluationContext, call: &Call, - input: Value, -) -> Result { + input: PipelineData, +) -> Result { let head = call.head; // let call_paths: Vec = args.rest(0)?; - input.map(head, move |v| { - action(v, head) + Ok(input + .map(move |v| { + action(v, head) - // FIXME: Add back cell_path support - // if column_paths.is_empty() { - // action(&v, v.tag()) - // } else { - // let mut ret = v; - // for path in &column_paths { - // ret = ret.swap_data_by_column_path( - // path, - // Box::new(move |old| action(old, old.tag())), - // )?; - // } + // FIXME: Add back cell_path support + // if column_paths.is_empty() { + // action(&v, v.tag()) + // } else { + // let mut ret = v; + // for path in &column_paths { + // ret = ret.swap_data_by_column_path( + // path, + // Box::new(move |old| action(old, old.tag())), + // )?; + // } - // Ok(ret) - // } - }) + // Ok(ret) + // } + }) + .into_pipeline_data()) } pub fn action(input: Value, span: Span) -> Value { diff --git a/crates/nu-command/src/conversions/into/int.rs b/crates/nu-command/src/conversions/into/int.rs index f53aee083..b0b29a2dc 100644 --- a/crates/nu-command/src/conversions/into/int.rs +++ b/crates/nu-command/src/conversions/into/int.rs @@ -1,9 +1,10 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -27,8 +28,8 @@ impl Command for SubCommand { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { into_int(context, call, input) } @@ -78,10 +79,8 @@ impl Command for SubCommand { Example { description: "Convert bool to integer", example: "[$false, $true] | into int", - result: Some(Value::Stream { - stream: vec![Value::test_int(0), Value::test_int(1)] - .into_iter() - .into_value_stream(), + result: Some(Value::List { + vals: vec![Value::test_int(0), Value::test_int(1)], span: Span::unknown(), }), }, @@ -92,26 +91,28 @@ impl Command for SubCommand { fn into_int( _context: &EvaluationContext, call: &Call, - input: Value, -) -> Result { + input: PipelineData, +) -> Result { let head = call.head; // let column_paths: Vec = call.rest(context, 0)?; - input.map(head, move |v| { - action(v, head) - // FIXME: Add back cell_path support - // if column_paths.is_empty() { - // action(&v, v.tag()) - // } else { - // let mut ret = v; - // for path in &column_paths { - // ret = ret - // .swap_data_by_column_path(path, Box::new(move |old| action(old, old.tag())))?; - // } + Ok(input + .map(move |v| { + action(v, head) + // FIXME: Add back cell_path support + // if column_paths.is_empty() { + // action(&v, v.tag()) + // } else { + // let mut ret = v; + // for path in &column_paths { + // ret = ret + // .swap_data_by_column_path(path, Box::new(move |old| action(old, old.tag())))?; + // } - // Ok(ret) - // } - }) + // Ok(ret) + // } + }) + .into_pipeline_data()) } pub fn action(input: Value, span: Span) -> Value { diff --git a/crates/nu-command/src/core_commands/alias.rs b/crates/nu-command/src/core_commands/alias.rs index 91beec2fd..971d04443 100644 --- a/crates/nu-command/src/core_commands/alias.rs +++ b/crates/nu-command/src/core_commands/alias.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Alias; impl Command for Alias { @@ -27,8 +28,8 @@ impl Command for Alias { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/def.rs b/crates/nu-command/src/core_commands/def.rs index 0f6ef1b56..4d3808bc7 100644 --- a/crates/nu-command/src/core_commands/def.rs +++ b/crates/nu-command/src/core_commands/def.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Def; impl Command for Def { @@ -28,8 +29,8 @@ impl Command for Def { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/do_.rs b/crates/nu-command/src/core_commands/do_.rs index ab4c97d85..8bc4435d7 100644 --- a/crates/nu-command/src/core_commands/do_.rs +++ b/crates/nu-command/src/core_commands/do_.rs @@ -1,8 +1,9 @@ use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Do; impl Command for Do { @@ -29,15 +30,14 @@ impl Command for Do { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let block_id = call.positional[0] .as_block() .expect("internal error: expected block"); let rest: Vec = call.rest(context, 1)?; - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + let block = context.engine_state.get_block(block_id); let state = context.enter_scope(); diff --git a/crates/nu-command/src/core_commands/export_def.rs b/crates/nu-command/src/core_commands/export_def.rs index b82418c48..2ab2430b1 100644 --- a/crates/nu-command/src/core_commands/export_def.rs +++ b/crates/nu-command/src/core_commands/export_def.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct ExportDef; impl Command for ExportDef { @@ -28,8 +29,8 @@ impl Command for ExportDef { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/for_.rs b/crates/nu-command/src/core_commands/for_.rs index bd995ce99..5ce82dc60 100644 --- a/crates/nu-command/src/core_commands/for_.rs +++ b/crates/nu-command/src/core_commands/for_.rs @@ -1,8 +1,9 @@ use nu_engine::{eval_block, eval_expression}; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, Signature, Span, SyntaxShape, Value}; +use nu_protocol::{Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value}; +#[derive(Clone)] pub struct For; impl Command for For { @@ -38,8 +39,8 @@ impl Command for For { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let var_id = call.positional[0] .as_var() .expect("internal error: missing variable"); @@ -55,19 +56,26 @@ impl Command for For { let context = context.clone(); - values.map(call.head, move |x| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block); + match values { + Value::List { vals, span } => Ok(vals + .into_iter() + .map(move |x| { + let block = context.engine_state.get_block(block); - let state = context.enter_scope(); + let state = context.enter_scope(); - state.add_var(var_id, x); + state.add_var(var_id, x); - match eval_block(&state, block, Value::nothing()) { - Ok(value) => value, - Err(error) => Value::Error { error }, - } - }) + match eval_block(&state, block, PipelineData::new()) { + Ok(value) => Value::List { + vals: value.collect(), + span, + }, + Err(error) => Value::Error { error }, + } + }) + .into_pipeline_data()), + } } fn examples(&self) -> Vec { diff --git a/crates/nu-command/src/core_commands/help.rs b/crates/nu-command/src/core_commands/help.rs index 6bc36ef54..dc96f3bc4 100644 --- a/crates/nu-command/src/core_commands/help.rs +++ b/crates/nu-command/src/core_commands/help.rs @@ -1,11 +1,13 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - span, Example, ShellError, Signature, Spanned, SyntaxShape, Value, + span, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned, SyntaxShape, + Value, }; use nu_engine::{get_full_help, CallExt}; +#[derive(Clone)] pub struct Help; impl Command for Help { @@ -36,8 +38,8 @@ impl Command for Help { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { help(context, call) } @@ -72,7 +74,7 @@ impl Command for Help { } } -fn help(context: &EvaluationContext, call: &Call) -> Result { +fn help(context: &EvaluationContext, call: &Call) -> Result { let head = call.head; let find: Option> = call.get_flag(context, "find")?; let rest: Vec> = call.rest(context, 0)?; @@ -114,10 +116,7 @@ fn help(context: &EvaluationContext, call: &Call) -> Result { } } - return Ok(Value::List { - vals: found_cmds_vec, - span: head, - }); + return Ok(found_cmds_vec.into_iter().into_pipeline_data()); } if !rest.is_empty() { @@ -151,10 +150,7 @@ fn help(context: &EvaluationContext, call: &Call) -> Result { }); } - Ok(Value::List { - vals: found_cmds_vec, - span: head, - }) + Ok(found_cmds_vec.into_iter().into_pipeline_data()) } else { let mut name = String::new(); let mut output = String::new(); @@ -177,7 +173,8 @@ fn help(context: &EvaluationContext, call: &Call) -> Result { Ok(Value::String { val: output, span: call.head, - }) + } + .into_pipeline_data()) } else { Err(ShellError::CommandNotFound(span(&[ rest[0].span, @@ -355,7 +352,8 @@ You can also learn more at https://www.nushell.sh/book/"#; Ok(Value::String { val: msg.into(), span: head, - }) + } + .into_pipeline_data()) } } diff --git a/crates/nu-command/src/core_commands/hide.rs b/crates/nu-command/src/core_commands/hide.rs index 9c9d611e1..dcfe34549 100644 --- a/crates/nu-command/src/core_commands/hide.rs +++ b/crates/nu-command/src/core_commands/hide.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Hide; impl Command for Hide { @@ -21,8 +22,8 @@ impl Command for Hide { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/if_.rs b/crates/nu-command/src/core_commands/if_.rs index fdb103dac..16217142d 100644 --- a/crates/nu-command/src/core_commands/if_.rs +++ b/crates/nu-command/src/core_commands/if_.rs @@ -1,8 +1,9 @@ use nu_engine::{eval_block, eval_expression}; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct If; impl Command for If { @@ -29,8 +30,8 @@ impl Command for If { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let cond = &call.positional[0]; let then_block = call.positional[1] .as_block() @@ -40,25 +41,24 @@ impl Command for If { let result = eval_expression(context, cond)?; match result { Value::Bool { val, span } => { - let engine_state = context.engine_state.borrow(); if val { - let block = engine_state.get_block(then_block); + let block = context.engine_state.get_block(then_block); let state = context.enter_scope(); eval_block(&state, block, input) } else if let Some(else_case) = else_case { if let Some(else_expr) = else_case.as_keyword() { if let Some(block_id) = else_expr.as_block() { - let block = engine_state.get_block(block_id); + let block = context.engine_state.get_block(block_id); let state = context.enter_scope(); eval_block(&state, block, input) } else { - eval_expression(context, else_expr) + eval_expression(context, else_expr).map(|x| x.into_pipeline_data()) } } else { - eval_expression(context, else_case) + eval_expression(context, else_case).map(|x| x.into_pipeline_data()) } } else { - Ok(Value::Nothing { span }) + Ok(PipelineData::new()) } } _ => Err(ShellError::CantConvert("bool".into(), result.span()?)), diff --git a/crates/nu-command/src/core_commands/let_.rs b/crates/nu-command/src/core_commands/let_.rs index 6e3a2d2fd..64a7437b0 100644 --- a/crates/nu-command/src/core_commands/let_.rs +++ b/crates/nu-command/src/core_commands/let_.rs @@ -1,8 +1,9 @@ use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Let; impl Command for Let { @@ -28,8 +29,8 @@ impl Command for Let { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let var_id = call.positional[0] .as_var() .expect("internal error: missing variable"); @@ -43,8 +44,6 @@ impl Command for Let { //println!("Adding: {:?} to {}", rhs, var_id); context.add_var(var_id, rhs); - Ok(Value::Nothing { - span: call.positional[0].span, - }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/module.rs b/crates/nu-command/src/core_commands/module.rs index e2cec960d..d7e59882a 100644 --- a/crates/nu-command/src/core_commands/module.rs +++ b/crates/nu-command/src/core_commands/module.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Module; impl Command for Module { @@ -27,8 +28,8 @@ impl Command for Module { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/core_commands/source.rs b/crates/nu-command/src/core_commands/source.rs index aacd3564c..17881b215 100644 --- a/crates/nu-command/src/core_commands/source.rs +++ b/crates/nu-command/src/core_commands/source.rs @@ -1,9 +1,10 @@ use nu_engine::{eval_block, CallExt}; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value}; /// Source a file for environment variables. +#[derive(Clone)] pub struct Source; impl Command for Source { @@ -27,17 +28,13 @@ impl Command for Source { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { // Note: this hidden positional is the block_id that corresponded to the 0th position // it is put here by the parser let block_id: i64 = call.req(context, 1)?; - let block = context - .engine_state - .borrow() - .get_block(block_id as usize) - .clone(); + let block = context.engine_state.get_block(block_id as usize).clone(); eval_block(context, &block, input) } } diff --git a/crates/nu-command/src/core_commands/use_.rs b/crates/nu-command/src/core_commands/use_.rs index 3cfae2e49..ed3781b38 100644 --- a/crates/nu-command/src/core_commands/use_.rs +++ b/crates/nu-command/src/core_commands/use_.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Use; impl Command for Use { @@ -21,8 +22,8 @@ impl Command for Use { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { - Ok(Value::Nothing { span: call.head }) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/env/let_env.rs b/crates/nu-command/src/env/let_env.rs index 39ed4800e..112cfa40d 100644 --- a/crates/nu-command/src/env/let_env.rs +++ b/crates/nu-command/src/env/let_env.rs @@ -1,8 +1,9 @@ use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct LetEnv; impl Command for LetEnv { @@ -28,8 +29,8 @@ impl Command for LetEnv { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let env_var = call.positional[0] .as_string() .expect("internal error: missing variable"); @@ -44,8 +45,6 @@ impl Command for LetEnv { //println!("Adding: {:?} to {}", rhs, var_id); context.add_env_var(env_var, rhs); - Ok(Value::Nothing { - span: call.positional[0].span, - }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/example_test.rs b/crates/nu-command/src/example_test.rs index 621d5540e..8b41ead79 100644 --- a/crates/nu-command/src/example_test.rs +++ b/crates/nu-command/src/example_test.rs @@ -4,19 +4,18 @@ use nu_engine::eval_block; use nu_parser::parse; use nu_protocol::{ engine::{Command, EngineState, EvaluationContext, StateWorkingSet}, - Value, + PipelineData, Value, }; use super::{From, Into, Split}; pub fn test_examples(cmd: impl Command + 'static) { let examples = cmd.examples(); - let engine_state = Rc::new(RefCell::new(EngineState::new())); + let mut engine_state = Box::new(EngineState::new()); 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 engine_state = engine_state.borrow(); let mut working_set = StateWorkingSet::new(&*engine_state); working_set.add_decl(Box::new(From)); working_set.add_decl(Box::new(Into)); @@ -28,7 +27,7 @@ pub fn test_examples(cmd: impl Command + 'static) { working_set.render() }; - EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); + EngineState::merge_delta(&mut *engine_state, delta); for example in examples { // Skip tests that don't have results to compare to @@ -38,7 +37,7 @@ pub fn test_examples(cmd: impl Command + 'static) { let start = std::time::Instant::now(); let (block, delta) = { - let engine_state = engine_state.borrow(); + let engine_state = engine_state; let mut working_set = StateWorkingSet::new(&*engine_state); let (output, err) = parse(&mut working_set, None, example.example.as_bytes(), false); @@ -49,16 +48,17 @@ pub fn test_examples(cmd: impl Command + 'static) { (output, working_set.render()) }; - EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); + EngineState::merge_delta(&mut *engine_state, delta); let state = EvaluationContext { engine_state: engine_state.clone(), stack: nu_protocol::engine::Stack::new(), }; - match eval_block(&state, &block, Value::nothing()) { + match eval_block(&state, &block, PipelineData::new()) { Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err), Ok(result) => { + let result = result.into_value(); println!("input: {}", example.example); println!("result: {:?}", result); println!("done: {:?}", start.elapsed()); diff --git a/crates/nu-command/src/experimental/git.rs b/crates/nu-command/src/experimental/git.rs index cef4a27db..57fe52c21 100644 --- a/crates/nu-command/src/experimental/git.rs +++ b/crates/nu-command/src/experimental/git.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value}; +#[derive(Clone)] pub struct Git; impl Command for Git { @@ -21,8 +22,8 @@ impl Command for Git { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { use std::process::Command as ProcessCommand; use std::process::Stdio; @@ -37,17 +38,18 @@ impl Command for Git { Ok(Value::String { val: String::from_utf8_lossy(&result).to_string(), span: call.head, - }) + } + .into_pipeline_data()) } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(Value::nothing()) + Ok(PipelineData::new()) } } } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(Value::nothing()) + Ok(PipelineData::new()) } } } diff --git a/crates/nu-command/src/experimental/git_checkout.rs b/crates/nu-command/src/experimental/git_checkout.rs index d25d607d7..02b1ac01a 100644 --- a/crates/nu-command/src/experimental/git_checkout.rs +++ b/crates/nu-command/src/experimental/git_checkout.rs @@ -1,8 +1,9 @@ use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct GitCheckout; impl Command for GitCheckout { @@ -26,8 +27,8 @@ impl Command for GitCheckout { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { use std::process::Command as ProcessCommand; use std::process::Stdio; @@ -52,17 +53,18 @@ impl Command for GitCheckout { Ok(Value::String { val: String::from_utf8_lossy(&result).to_string(), span: call.head, - }) + } + .into_pipeline_data()) } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(Value::nothing()) + Ok(PipelineData::new()) } } } Err(_err) => { // FIXME: Move this to an external signature and add better error handling - Ok(Value::nothing()) + Ok(PipelineData::new()) } } } diff --git a/crates/nu-command/src/experimental/list_git_branches.rs b/crates/nu-command/src/experimental/list_git_branches.rs index 3a0a14892..065b5bf2c 100644 --- a/crates/nu-command/src/experimental/list_git_branches.rs +++ b/crates/nu-command/src/experimental/list_git_branches.rs @@ -5,8 +5,11 @@ use std::process::Stdio; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::IntoPipelineData; +use nu_protocol::PipelineData; use nu_protocol::{Signature, Value}; +#[derive(Clone)] pub struct ListGitBranches; //NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one. @@ -27,8 +30,8 @@ impl Command for ListGitBranches { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let list_branches = ProcessCommand::new("git") .arg("branch") .stdout(Stdio::piped()) @@ -55,15 +58,12 @@ impl Command for ListGitBranches { }) .collect(); - Ok(Value::List { - vals: lines, - span: call.head, - }) + Ok(lines.into_iter().into_pipeline_data()) } else { - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } else { - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } } diff --git a/crates/nu-command/src/filesystem/cd.rs b/crates/nu-command/src/filesystem/cd.rs index 919e11e02..cbde266c4 100644 --- a/crates/nu-command/src/filesystem/cd.rs +++ b/crates/nu-command/src/filesystem/cd.rs @@ -1,8 +1,9 @@ use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Cd; impl Command for Cd { @@ -22,8 +23,8 @@ impl Command for Cd { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let path: Option = call.opt(context, 0)?; let path = match path { @@ -41,6 +42,6 @@ impl Command for Cd { //FIXME: this only changes the current scope, but instead this environment variable //should probably be a block that loads the information from the state in the overlay context.add_env_var("PWD".into(), path); - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/filesystem/cp.rs b/crates/nu-command/src/filesystem/cp.rs index 80d2b3955..71d5a255a 100644 --- a/crates/nu-command/src/filesystem/cp.rs +++ b/crates/nu-command/src/filesystem/cp.rs @@ -6,10 +6,11 @@ use nu_engine::CallExt; use nu_path::canonicalize_with; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value}; use crate::filesystem::util::FileStructure; +#[derive(Clone)] pub struct Cp; #[allow(unused_must_use)] @@ -39,8 +40,8 @@ impl Command for Cp { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let source: String = call.req(context, 0)?; let destination: String = call.req(context, 1)?; let interactive = call.has_flag("interactive"); @@ -202,6 +203,6 @@ impl Command for Cp { } } - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/filesystem/ls.rs b/crates/nu-command/src/filesystem/ls.rs index 36fbaff74..8c35698bb 100644 --- a/crates/nu-command/src/filesystem/ls.rs +++ b/crates/nu-command/src/filesystem/ls.rs @@ -2,8 +2,9 @@ use chrono::{DateTime, Utc}; use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{IntoValueStream, Signature, SyntaxShape, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Ls; //NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one. @@ -28,8 +29,8 @@ impl Command for Ls { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let pattern = if let Some(expr) = call.positional.get(0) { let result = eval_expression(context, expr)?; let mut result = result.as_string()?; @@ -50,69 +51,66 @@ impl Command for Ls { let call_span = call.head; let glob = glob::glob(&pattern).unwrap(); - Ok(Value::Stream { - stream: glob - .into_iter() - .map(move |x| match x { - Ok(path) => match std::fs::symlink_metadata(&path) { - Ok(metadata) => { - let is_file = metadata.is_file(); - let is_dir = metadata.is_dir(); - let filesize = metadata.len(); + Ok(glob + .into_iter() + .map(move |x| match x { + Ok(path) => match std::fs::symlink_metadata(&path) { + Ok(metadata) => { + let is_file = metadata.is_file(); + let is_dir = metadata.is_dir(); + let filesize = metadata.len(); - let mut cols = vec!["name".into(), "type".into(), "size".into()]; + let mut cols = vec!["name".into(), "type".into(), "size".into()]; - let mut vals = vec![ - Value::String { - val: path.to_string_lossy().to_string(), - span: call_span, - }, - if is_file { - Value::string("File", call_span) - } else if is_dir { - Value::string("Dir", call_span) - } else { - Value::Nothing { span: call_span } - }, - Value::Filesize { - val: filesize as i64, - span: call_span, - }, - ]; - - if let Ok(date) = metadata.modified() { - let utc: DateTime = date.into(); - - cols.push("modified".into()); - vals.push(Value::Date { - val: utc.into(), - span: call_span, - }); - } - - Value::Record { - cols, - vals, + let mut vals = vec![ + Value::String { + val: path.to_string_lossy().to_string(), span: call_span, - } + }, + if is_file { + Value::string("File", call_span) + } else if is_dir { + Value::string("Dir", call_span) + } else { + Value::Nothing { span: call_span } + }, + Value::Filesize { + val: filesize as i64, + span: call_span, + }, + ]; + + if let Ok(date) = metadata.modified() { + let utc: DateTime = date.into(); + + cols.push("modified".into()); + vals.push(Value::Date { + val: utc.into(), + span: call_span, + }); } - Err(_) => Value::Record { - cols: vec!["name".into(), "type".into(), "size".into()], - vals: vec![ - Value::String { - val: path.to_string_lossy().to_string(), - span: call_span, - }, - Value::Nothing { span: call_span }, - Value::Nothing { span: call_span }, - ], + + Value::Record { + cols, + vals, span: call_span, - }, + } + } + Err(_) => Value::Record { + cols: vec!["name".into(), "type".into(), "size".into()], + vals: vec![ + Value::String { + val: path.to_string_lossy().to_string(), + span: call_span, + }, + Value::Nothing { span: call_span }, + Value::Nothing { span: call_span }, + ], + span: call_span, }, - _ => Value::Nothing { span: call_span }, - }) - .into_value_stream(), - span: call_span, - }) + }, + _ => Value::Nothing { span: call_span }, + }) + .into_pipeline_data()) } } diff --git a/crates/nu-command/src/filesystem/mkdir.rs b/crates/nu-command/src/filesystem/mkdir.rs index 5635c8553..43990605b 100644 --- a/crates/nu-command/src/filesystem/mkdir.rs +++ b/crates/nu-command/src/filesystem/mkdir.rs @@ -4,8 +4,11 @@ use std::env::current_dir; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value, ValueStream}; +use nu_protocol::{ + IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value, ValueStream, +}; +#[derive(Clone)] pub struct Mkdir; impl Command for Mkdir { @@ -31,8 +34,8 @@ impl Command for Mkdir { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let path = current_dir()?; let mut directories = call .rest::(context, 0)? @@ -67,8 +70,6 @@ impl Command for Mkdir { } } - let stream = ValueStream::from_stream(stream.into_iter()); - let span = call.head; - Ok(Value::Stream { stream, span }) + Ok(stream.into_iter().into_pipeline_data()) } } diff --git a/crates/nu-command/src/filesystem/mv.rs b/crates/nu-command/src/filesystem/mv.rs index c9f46cd87..ba709729e 100644 --- a/crates/nu-command/src/filesystem/mv.rs +++ b/crates/nu-command/src/filesystem/mv.rs @@ -5,8 +5,9 @@ use super::util::get_interactive_confirmation; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Mv; #[allow(unused_must_use)] @@ -39,8 +40,8 @@ impl Command for Mv { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { // TODO: handle invalid directory or insufficient permissions when moving let source: String = call.req(context, 0)?; let destination: String = call.req(context, 1)?; @@ -128,7 +129,7 @@ impl Command for Mv { move_file(call, &entry, &destination)? } - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/filesystem/rm.rs b/crates/nu-command/src/filesystem/rm.rs index 0beb63f15..d64764d78 100644 --- a/crates/nu-command/src/filesystem/rm.rs +++ b/crates/nu-command/src/filesystem/rm.rs @@ -8,8 +8,11 @@ use super::util::get_interactive_confirmation; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value, ValueStream}; +use nu_protocol::{ + IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value, ValueStream, +}; +#[derive(Clone)] pub struct Rm; // Where self.0 is the unexpanded target's positional index (i.e. call.positional[self.0].span) @@ -58,13 +61,13 @@ impl Command for Rm { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { rm(context, call) } } -fn rm(context: &EvaluationContext, call: &Call) -> Result { +fn rm(context: &EvaluationContext, call: &Call) -> Result { let trash = call.has_flag("trash"); let permanent = call.has_flag("permanent"); let interactive = call.has_flag("interactive"); @@ -164,11 +167,7 @@ fn rm(context: &EvaluationContext, call: &Call) -> Result { // let temp = rm_helper(call, args).flatten(); // let temp = input.flatten(call.head, move |_| rm_helper(call, args)); - Ok(Value::Stream { - stream: ValueStream::from_stream(response.into_iter()), - span: call.head, - }) - + Ok(response.into_iter().into_pipeline_data()) // Ok(Value::Nothing { span }) } diff --git a/crates/nu-command/src/filesystem/touch.rs b/crates/nu-command/src/filesystem/touch.rs index bb23d4718..3d323c71d 100644 --- a/crates/nu-command/src/filesystem/touch.rs +++ b/crates/nu-command/src/filesystem/touch.rs @@ -3,8 +3,9 @@ use std::fs::OpenOptions; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Touch; impl Command for Touch { @@ -30,8 +31,8 @@ impl Command for Touch { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let target: String = call.req(context, 0)?; let rest: Vec = call.rest(context, 1)?; @@ -47,6 +48,6 @@ impl Command for Touch { } } - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/filters/each.rs b/crates/nu-command/src/filters/each.rs index f2e6de61f..7293e9c9e 100644 --- a/crates/nu-command/src/filters/each.rs +++ b/crates/nu-command/src/filters/each.rs @@ -1,8 +1,9 @@ use nu_engine::eval_block; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, IntoValueStream, Signature, Span, SyntaxShape, Value}; +use nu_protocol::{Example, PipelineData, Signature, Span, SyntaxShape, Value}; +#[derive(Clone)] pub struct Each; impl Command for Each { @@ -43,8 +44,8 @@ impl Command for Each { vec![Example { example: "[1 2 3] | each { 2 * $it }", description: "Multiplies elements in list", - result: Some(Value::Stream { - stream: stream_test_1.into_iter().into_value_stream(), + result: Some(Value::List { + vals: stream_test_1, span: Span::unknown(), }), }] @@ -54,8 +55,8 @@ impl Command for Each { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let block_id = call.positional[0] .as_block() .expect("internal error: expected block"); @@ -64,190 +65,186 @@ impl Command for Each { let context = context.clone(); let span = call.head; - match input { - Value::Range { val, .. } => Ok(Value::Stream { - stream: val - .into_range_iter()? - .enumerate() - .map(move |(idx, x)| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + // match input { + // Value::Range { val, .. } => Ok(val + // .into_range_iter()? + // .enumerate() + // .map(move |(idx, x)| { + // let block = context.engine_state.get_block(block_id); - let state = context.enter_scope(); + // let state = context.enter_scope(); - if let Some(var) = block.signature.get_positional(0) { - if let Some(var_id) = &var.var_id { - if numbered { - state.add_var( - *var_id, - Value::Record { - cols: vec!["index".into(), "item".into()], - vals: vec![ - Value::Int { - val: idx as i64, - span, - }, - x, - ], - span, - }, - ); - } else { - state.add_var(*var_id, x); - } - } - } + // if let Some(var) = block.signature.get_positional(0) { + // if let Some(var_id) = &var.var_id { + // if numbered { + // state.add_var( + // *var_id, + // Value::Record { + // cols: vec!["index".into(), "item".into()], + // vals: vec![ + // Value::Int { + // val: idx as i64, + // span, + // }, + // x, + // ], + // span, + // }, + // ); + // } else { + // state.add_var(*var_id, x); + // } + // } + // } - match eval_block(&state, block, Value::nothing()) { - Ok(v) => v, - Err(error) => Value::Error { error }, - } - }) - .into_value_stream(), - span: call.head, - }), - Value::List { vals: val, .. } => Ok(Value::Stream { - stream: val - .into_iter() - .enumerate() - .map(move |(idx, x)| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + // match eval_block(&state, block, Value::nothing()) { + // Ok(v) => v, + // Err(error) => Value::Error { error }, + // } + // }) + // .into_pipeline_data()), + // Value::List { vals: val, .. } => Ok(Value::Stream { + // stream: val + // .into_iter() + // .enumerate() + // .map(move |(idx, x)| { + // let engine_state = context.engine_state.borrow(); + // let block = engine_state.get_block(block_id); - let state = context.enter_scope(); - if let Some(var) = block.signature.get_positional(0) { - if let Some(var_id) = &var.var_id { - if numbered { - state.add_var( - *var_id, - Value::Record { - cols: vec!["index".into(), "item".into()], - vals: vec![ - Value::Int { - val: idx as i64, - span, - }, - x, - ], - span, - }, - ); - } else { - state.add_var(*var_id, x); - } - } - } + // let state = context.enter_scope(); + // if let Some(var) = block.signature.get_positional(0) { + // if let Some(var_id) = &var.var_id { + // if numbered { + // state.add_var( + // *var_id, + // Value::Record { + // cols: vec!["index".into(), "item".into()], + // vals: vec![ + // Value::Int { + // val: idx as i64, + // span, + // }, + // x, + // ], + // span, + // }, + // ); + // } else { + // state.add_var(*var_id, x); + // } + // } + // } - match eval_block(&state, block, Value::nothing()) { - Ok(v) => v, - Err(error) => Value::Error { error }, - } - }) - .into_value_stream(), - span: call.head, - }), - Value::Stream { stream, .. } => Ok(Value::Stream { - stream: stream - .enumerate() - .map(move |(idx, x)| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + // match eval_block(&state, block, Value::nothing()) { + // Ok(v) => v, + // Err(error) => Value::Error { error }, + // } + // }) + // .into_value_stream(), + // span: call.head, + // }), + // Value::Stream { stream, .. } => Ok(Value::Stream { + // stream: stream + // .enumerate() + // .map(move |(idx, x)| { + // let engine_state = context.engine_state.borrow(); + // let block = engine_state.get_block(block_id); - let state = context.enter_scope(); - if let Some(var) = block.signature.get_positional(0) { - if let Some(var_id) = &var.var_id { - if numbered { - state.add_var( - *var_id, - Value::Record { - cols: vec!["index".into(), "item".into()], - vals: vec![ - Value::Int { - val: idx as i64, - span, - }, - x, - ], - span, - }, - ); - } else { - state.add_var(*var_id, x); - } - } - } + // let state = context.enter_scope(); + // if let Some(var) = block.signature.get_positional(0) { + // if let Some(var_id) = &var.var_id { + // if numbered { + // state.add_var( + // *var_id, + // Value::Record { + // cols: vec!["index".into(), "item".into()], + // vals: vec![ + // Value::Int { + // val: idx as i64, + // span, + // }, + // x, + // ], + // span, + // }, + // ); + // } else { + // state.add_var(*var_id, x); + // } + // } + // } - match eval_block(&state, block, Value::nothing()) { - Ok(v) => v, - Err(error) => Value::Error { error }, - } - }) - .into_value_stream(), - span: call.head, - }), - Value::Record { cols, vals, .. } => { - let mut output_cols = vec![]; - let mut output_vals = vec![]; + // match eval_block(&state, block, Value::nothing()) { + // Ok(v) => v, + // Err(error) => Value::Error { error }, + // } + // }) + // .into_value_stream(), + // span: call.head, + // }), + // Value::Record { cols, vals, .. } => { + // let mut output_cols = vec![]; + // let mut output_vals = vec![]; - for (col, val) in cols.into_iter().zip(vals.into_iter()) { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + // for (col, val) in cols.into_iter().zip(vals.into_iter()) { + // let engine_state = context.engine_state.borrow(); + // let block = engine_state.get_block(block_id); - let state = context.enter_scope(); - if let Some(var) = block.signature.get_positional(0) { - if let Some(var_id) = &var.var_id { - state.add_var( - *var_id, - Value::Record { - cols: vec!["column".into(), "value".into()], - vals: vec![ - Value::String { - val: col.clone(), - span: call.head, - }, - val, - ], - span: call.head, - }, - ); - } - } + // let state = context.enter_scope(); + // if let Some(var) = block.signature.get_positional(0) { + // if let Some(var_id) = &var.var_id { + // state.add_var( + // *var_id, + // Value::Record { + // cols: vec!["column".into(), "value".into()], + // vals: vec![ + // Value::String { + // val: col.clone(), + // span: call.head, + // }, + // val, + // ], + // span: call.head, + // }, + // ); + // } + // } - match eval_block(&state, block, Value::nothing())? { - Value::Record { - mut cols, mut vals, .. - } => { - // TODO check that the lengths match when traversing record - output_cols.append(&mut cols); - output_vals.append(&mut vals); - } - x => { - output_cols.push(col); - output_vals.push(x); - } - } - } + // match eval_block(&state, block, Value::nothing())? { + // Value::Record { + // mut cols, mut vals, .. + // } => { + // // TODO check that the lengths match when traversing record + // output_cols.append(&mut cols); + // output_vals.append(&mut vals); + // } + // x => { + // output_cols.push(col); + // output_vals.push(x); + // } + // } + // } - Ok(Value::Record { - cols: output_cols, - vals: output_vals, - span: call.head, - }) - } - x => { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block_id); + // Ok(Value::Record { + // cols: output_cols, + // vals: output_vals, + // span: call.head, + // }) + // } + // x => { + // let engine_state = context.engine_state.borrow(); + // let block = engine_state.get_block(block_id); - let state = context.enter_scope(); - if let Some(var) = block.signature.get_positional(0) { - if let Some(var_id) = &var.var_id { - state.add_var(*var_id, x); - } - } + // let state = context.enter_scope(); + // if let Some(var) = block.signature.get_positional(0) { + // if let Some(var_id) = &var.var_id { + // state.add_var(*var_id, x); + // } + // } - eval_block(&state, block, Value::nothing()) - } - } + // eval_block(&state, block, Value::nothing()) + // } + // } } } diff --git a/crates/nu-command/src/filters/get.rs b/crates/nu-command/src/filters/get.rs index 7ad1c1282..9cf3dd796 100644 --- a/crates/nu-command/src/filters/get.rs +++ b/crates/nu-command/src/filters/get.rs @@ -1,8 +1,9 @@ use nu_engine::CallExt; use nu_protocol::ast::{Call, CellPath}; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Get; impl Command for Get { @@ -26,8 +27,8 @@ impl Command for Get { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let cell_path: CellPath = call.req(context, 0)?; input.follow_cell_path(&cell_path.members) diff --git a/crates/nu-command/src/filters/length.rs b/crates/nu-command/src/filters/length.rs index d2c33fad5..5c7967fe8 100644 --- a/crates/nu-command/src/filters/length.rs +++ b/crates/nu-command/src/filters/length.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value}; +#[derive(Clone)] pub struct Length; impl Command for Length { @@ -21,33 +22,19 @@ impl Command for Length { &self, _context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { match input { - Value::List { vals: val, .. } => { - let length = val.len(); - - Ok(Value::Int { - val: length as i64, - span: call.head, - }) - } - Value::Stream { stream, .. } => { - let length = stream.count(); - - Ok(Value::Int { - val: length as i64, - span: call.head, - }) - } - Value::Nothing { .. } => Ok(Value::Int { + PipelineData::Value(Value::Nothing { .. }) => Ok(Value::Int { val: 0, span: call.head, - }), + } + .into_pipeline_data()), _ => Ok(Value::Int { - val: 1, + val: input.count() as i64, span: call.head, - }), + } + .into_pipeline_data()), } } } diff --git a/crates/nu-command/src/filters/lines.rs b/crates/nu-command/src/filters/lines.rs index 2a32b54ca..ec59b9d61 100644 --- a/crates/nu-command/src/filters/lines.rs +++ b/crates/nu-command/src/filters/lines.rs @@ -3,8 +3,9 @@ use std::rc::Rc; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, Value, ValueStream}; +use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, Value, ValueStream}; +#[derive(Clone)] pub struct Lines; const SPLIT_CHAR: char = '\n'; @@ -26,15 +27,15 @@ impl Command for Lines { &self, _context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let span = call.head; match input { #[allow(clippy::needless_collect)] // Collect is needed because the string may not live long enough for // the Rc structure to continue using it. If split could take ownership // of the split values, then this wouldn't be needed - Value::String { val, span } => { + PipelineData::Value(Value::String { val, span }) => { let lines = val .split(SPLIT_CHAR) .map(|s| s.to_string()) @@ -48,12 +49,9 @@ impl Command for Lines { } }); - Ok(Value::Stream { - stream: ValueStream(Rc::new(RefCell::new(iter))), - span, - }) + Ok(iter.into_pipeline_data()) } - Value::Stream { stream, span: _ } => { + PipelineData::Stream(stream) => { let iter = stream .into_iter() .filter_map(|value| { @@ -79,12 +77,9 @@ impl Command for Lines { }) .flatten(); - Ok(Value::Stream { - stream: ValueStream(Rc::new(RefCell::new(iter))), - span, - }) + Ok(iter.into_pipeline_data()) } - val => Err(ShellError::UnsupportedInput( + PipelineData::Value(val) => Err(ShellError::UnsupportedInput( format!("Not supported input: {}", val.as_string()?), call.head, )), diff --git a/crates/nu-command/src/filters/select.rs b/crates/nu-command/src/filters/select.rs index 7a828aca5..6849c545c 100644 --- a/crates/nu-command/src/filters/select.rs +++ b/crates/nu-command/src/filters/select.rs @@ -1,8 +1,11 @@ use nu_engine::CallExt; use nu_protocol::ast::{Call, CellPath}; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value}; +use nu_protocol::{ + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, +}; +#[derive(Clone)] pub struct Select; impl Command for Select { @@ -26,8 +29,8 @@ impl Command for Select { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let columns: Vec = call.rest(context, 0)?; let span = call.head; @@ -50,16 +53,20 @@ impl Command for Select { } } -fn select(span: Span, columns: Vec, input: Value) -> Result { +fn select( + span: Span, + columns: Vec, + input: PipelineData, +) -> Result { if columns.is_empty() { - return Err(ShellError::CantFindColumn(span, input.span()?)); + return Err(ShellError::CantFindColumn(span, span)); //FIXME? } match input { - Value::List { + PipelineData::Value(Value::List { vals: input_vals, span, - } => { + }) => { let mut output = vec![]; for input_val in input_vals { @@ -76,33 +83,30 @@ fn select(span: Span, columns: Vec, input: Value) -> Result Ok(Value::Stream { - stream: stream - .map(move |x| { - let mut cols = vec![]; - let mut vals = vec![]; - for path in &columns { - //FIXME: improve implementation to not clone - match x.clone().follow_cell_path(&path.members) { - Ok(value) => { - cols.push(path.into_string()); - vals.push(value); - } - Err(error) => { - cols.push(path.into_string()); - vals.push(Value::Error { error }); - } + PipelineData::Stream(stream) => Ok(stream + .map(move |x| { + let mut cols = vec![]; + let mut vals = vec![]; + for path in &columns { + //FIXME: improve implementation to not clone + match x.clone().follow_cell_path(&path.members) { + Ok(value) => { + cols.push(path.into_string()); + vals.push(value); + } + Err(error) => { + cols.push(path.into_string()); + vals.push(Value::Error { error }); } } + } - Value::Record { cols, vals, span } - }) - .into_value_stream(), - span, - }), - v => { + Value::Record { cols, vals, span } + }) + .into_pipeline_data()), + PipelineData::Value(v) => { let mut cols = vec![]; let mut vals = vec![]; @@ -114,7 +118,7 @@ fn select(span: Span, columns: Vec, input: Value) -> Result Result { + input: PipelineData, + ) -> Result { let cond = call.positional[0].clone(); let context = context.enter_scope(); @@ -37,54 +38,40 @@ impl Command for Where { }; match input { - Value::Stream { stream, span } => { - let output_stream = stream - .filter(move |value| { - context.add_var(var_id, value.clone()); + PipelineData::Stream(stream) => Ok(stream + .filter(move |value| { + context.add_var(var_id, value.clone()); - let result = eval_expression(&context, &cond); + let result = eval_expression(&context, &cond); - match result { - Ok(result) => result.is_true(), - _ => false, - } - }) - .into_value_stream(); - - Ok(Value::Stream { - stream: output_stream, - span, + match result { + Ok(result) => result.is_true(), + _ => false, + } }) - } - Value::List { vals, span } => { - let output_stream = vals - .into_iter() - .filter(move |value| { - context.add_var(var_id, value.clone()); + .into_pipeline_data()), + PipelineData::Value(Value::List { vals, span }) => Ok(vals + .into_iter() + .filter(move |value| { + context.add_var(var_id, value.clone()); - let result = eval_expression(&context, &cond); + let result = eval_expression(&context, &cond); - match result { - Ok(result) => result.is_true(), - _ => false, - } - }) - .into_value_stream(); - - Ok(Value::Stream { - stream: output_stream, - span, + match result { + Ok(result) => result.is_true(), + _ => false, + } }) - } - x => { + .into_pipeline_data()), + PipelineData::Value(x) => { context.add_var(var_id, x.clone()); let result = eval_expression(&context, &cond)?; if result.is_true() { - Ok(x) + Ok(x.into_pipeline_data()) } else { - Ok(Value::Nothing { span: call.head }) + Ok(PipelineData::new()) } } } diff --git a/crates/nu-command/src/filters/wrap.rs b/crates/nu-command/src/filters/wrap.rs index f23624ad2..9c924800e 100644 --- a/crates/nu-command/src/filters/wrap.rs +++ b/crates/nu-command/src/filters/wrap.rs @@ -1,8 +1,9 @@ use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{IntoValueStream, Signature, SyntaxShape, Value}; +use nu_protocol::{IntoPipelineData, PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Wrap; impl Command for Wrap { @@ -22,38 +23,33 @@ impl Command for Wrap { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let span = call.head; let name: String = call.req(context, 0)?; match input { - Value::List { vals, .. } => Ok(Value::List { - vals: vals - .into_iter() - .map(move |x| Value::Record { - cols: vec![name.clone()], - vals: vec![x], - span, - }) - .collect(), - span, - }), - Value::Stream { stream, .. } => Ok(Value::Stream { - stream: stream - .map(move |x| Value::Record { - cols: vec![name.clone()], - vals: vec![x], - span, - }) - .into_value_stream(), - span, - }), - _ => Ok(Value::Record { + PipelineData::Value(Value::List { vals, .. }) => Ok(vals + .into_iter() + .map(move |x| Value::Record { + cols: vec![name.clone()], + vals: vec![x], + span, + }) + .into_pipeline_data()), + PipelineData::Stream(stream) => Ok(stream + .map(move |x| Value::Record { + cols: vec![name.clone()], + vals: vec![x], + span, + }) + .into_pipeline_data()), + PipelineData::Value(input) => Ok(Value::Record { cols: vec![name], vals: vec![input], span, - }), + } + .into_pipeline_data()), } } } diff --git a/crates/nu-command/src/formats/from/command.rs b/crates/nu-command/src/formats/from/command.rs index cc2b6b2da..23b3d84f6 100644 --- a/crates/nu-command/src/formats/from/command.rs +++ b/crates/nu-command/src/formats/from/command.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{ShellError, Signature, Value}; +use nu_protocol::{PipelineData, ShellError, Signature, Value}; +#[derive(Clone)] pub struct From; impl Command for From { @@ -21,8 +22,8 @@ impl Command for From { &self, _context: &EvaluationContext, _call: &Call, - _input: Value, - ) -> Result { - Ok(Value::nothing()) + _input: PipelineData, + ) -> Result { + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/formats/from/json.rs b/crates/nu-command/src/formats/from/json.rs index c643f1ba0..37ee0f81f 100644 --- a/crates/nu-command/src/formats/from/json.rs +++ b/crates/nu-command/src/formats/from/json.rs @@ -1,7 +1,8 @@ use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, IntoValueStream, ShellError, Signature, Span, Value}; +use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value}; +#[derive(Clone)] pub struct FromJson; impl Command for FromJson { @@ -69,8 +70,8 @@ impl Command for FromJson { &self, _context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let span = input.span()?; let mut string_input = input.collect_string(); string_input.push('\n'); @@ -79,21 +80,18 @@ impl Command for FromJson { if call.has_flag("objects") { #[allow(clippy::needless_collect)] let lines: Vec = string_input.lines().map(|x| x.to_string()).collect(); - Ok(Value::Stream { - stream: lines - .into_iter() - .map(move |mut x| { - x.push('\n'); - match convert_string_to_value(x, span) { - Ok(v) => v, - Err(error) => Value::Error { error }, - } - }) - .into_value_stream(), - span, - }) + Ok(lines + .into_iter() + .map(move |mut x| { + x.push('\n'); + match convert_string_to_value(x, span) { + Ok(v) => v, + Err(error) => Value::Error { error }, + } + }) + .into_pipeline_data()) } else { - convert_string_to_value(string_input, span) + Ok(convert_string_to_value(string_input, span)?.into_pipeline_data()) } } } diff --git a/crates/nu-command/src/strings/build_string.rs b/crates/nu-command/src/strings/build_string.rs index d9121034d..4e80d1128 100644 --- a/crates/nu-command/src/strings/build_string.rs +++ b/crates/nu-command/src/strings/build_string.rs @@ -1,8 +1,11 @@ use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, ShellError, Signature, Span, SyntaxShape, Value}; +use nu_protocol::{ + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, +}; +#[derive(Clone)] pub struct BuildString; impl Command for BuildString { @@ -43,8 +46,8 @@ impl Command for BuildString { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let output = call .positional .iter() @@ -54,7 +57,8 @@ impl Command for BuildString { Ok(Value::String { val: output.join(""), span: call.head, - }) + } + .into_pipeline_data()) } } diff --git a/crates/nu-command/src/strings/size.rs b/crates/nu-command/src/strings/size.rs index 245abdc75..b40f3abf4 100644 --- a/crates/nu-command/src/strings/size.rs +++ b/crates/nu-command/src/strings/size.rs @@ -4,8 +4,11 @@ use unicode_segmentation::UnicodeSegmentation; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, ShellError, Signature, Span, Type, Value}; +use nu_protocol::{ + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value, +}; +#[derive(Clone)] pub struct Size; impl Command for Size { @@ -25,8 +28,8 @@ impl Command for Size { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { size(context, call, input) } @@ -98,18 +101,24 @@ impl Command for Size { } } -fn size(_context: &EvaluationContext, call: &Call, input: Value) -> Result { +fn size( + _context: &EvaluationContext, + call: &Call, + input: PipelineData, +) -> Result { let span = call.head; - input.map(span, move |v| match v.as_string() { - Ok(s) => count(&s, span), - Err(_) => Value::Error { - error: ShellError::PipelineMismatch { - expected: Type::String, - expected_span: span, - origin: span, + Ok(input + .map(move |v| match v.as_string() { + Ok(s) => count(&s, span), + Err(_) => Value::Error { + error: ShellError::PipelineMismatch { + expected: Type::String, + expected_span: span, + origin: span, + }, }, - }, - }) + }) + .into_pipeline_data()) } fn count(contents: &str, span: Span) -> Value { diff --git a/crates/nu-command/src/strings/split/chars.rs b/crates/nu-command/src/strings/split/chars.rs index c74dce2f1..e0ceaa9cb 100644 --- a/crates/nu-command/src/strings/split/chars.rs +++ b/crates/nu-command/src/strings/split/chars.rs @@ -1,9 +1,10 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, ShellError, Signature, Span, Type, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -40,16 +41,21 @@ impl Command for SubCommand { &self, _context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { split_chars(call, input) } } -fn split_chars(call: &Call, input: Value) -> Result { +fn split_chars( + call: &Call, + input: PipelineData, +) -> Result { let span = call.head; - Ok(input.flat_map(span, move |x| split_chars_helper(&x, span))) + Ok(input + .flat_map(move |x| split_chars_helper(&x, span)) + .into_pipeline_data()) } fn split_chars_helper(v: &Value, name: Span) -> Vec { diff --git a/crates/nu-command/src/strings/split/column.rs b/crates/nu-command/src/strings/split/column.rs index ace779bd2..3b7bcae08 100644 --- a/crates/nu-command/src/strings/split/column.rs +++ b/crates/nu-command/src/strings/split/column.rs @@ -2,9 +2,10 @@ use nu_engine::CallExt; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, + IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -35,8 +36,8 @@ impl Command for SubCommand { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { split_column(context, call, input) } } @@ -44,16 +45,16 @@ impl Command for SubCommand { fn split_column( context: &EvaluationContext, call: &Call, - input: Value, -) -> Result { + input: PipelineData, +) -> Result { let name_span = call.head; let separator: Spanned = call.req(context, 0)?; let rest: Vec> = call.rest(context, 1)?; let collapse_empty = call.has_flag("collapse-empty"); - input.map(name_span, move |x| { - split_column_helper(&x, &separator, &rest, collapse_empty, name_span) - }) + Ok(input + .map(move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span)) + .into_pipeline_data()) } fn split_column_helper( diff --git a/crates/nu-command/src/strings/split/command.rs b/crates/nu-command/src/strings/split/command.rs index 87df22927..2afaaee62 100644 --- a/crates/nu-command/src/strings/split/command.rs +++ b/crates/nu-command/src/strings/split/command.rs @@ -2,7 +2,7 @@ use nu_engine::get_full_help; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Signature, Value, + IntoPipelineData, PipelineData, Signature, Value, }; #[derive(Clone)] @@ -25,12 +25,13 @@ impl Command for SplitCommand { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { Ok(Value::String { val: get_full_help(&SplitCommand.signature(), &SplitCommand.examples(), context), span: call.head, - }) + } + .into_pipeline_data()) } } diff --git a/crates/nu-command/src/strings/split/row.rs b/crates/nu-command/src/strings/split/row.rs index afda96977..6b24e2c79 100644 --- a/crates/nu-command/src/strings/split/row.rs +++ b/crates/nu-command/src/strings/split/row.rs @@ -2,9 +2,10 @@ use nu_engine::CallExt; use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, + IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, }; +#[derive(Clone)] pub struct SubCommand; impl Command for SubCommand { @@ -28,8 +29,8 @@ impl Command for SubCommand { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { split_row(context, call, input) } } @@ -37,14 +38,14 @@ impl Command for SubCommand { fn split_row( context: &EvaluationContext, call: &Call, - input: Value, -) -> Result { + input: PipelineData, +) -> Result { let name_span = call.head; let separator: Spanned = call.req(context, 0)?; - Ok(input.flat_map(name_span, move |x| { - split_row_helper(&x, &separator, name_span) - })) + Ok(input + .flat_map(move |x| split_row_helper(&x, &separator, name_span)) + .into_pipeline_data()) } fn split_row_helper(v: &Value, separator: &Spanned, name: Span) -> Vec { diff --git a/crates/nu-command/src/system/benchmark.rs b/crates/nu-command/src/system/benchmark.rs index 1590e8af8..932b8b126 100644 --- a/crates/nu-command/src/system/benchmark.rs +++ b/crates/nu-command/src/system/benchmark.rs @@ -3,8 +3,9 @@ use std::time::Instant; use nu_engine::eval_block; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{PipelineData, Signature, SyntaxShape, Value}; +#[derive(Clone)] pub struct Benchmark; impl Command for Benchmark { @@ -28,21 +29,18 @@ impl Command for Benchmark { &self, context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { let block = call.positional[0] .as_block() .expect("internal error: expected block"); - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block); + let block = context.engine_state.get_block(block); let state = context.enter_scope(); let start_time = Instant::now(); - eval_block(&state, block, Value::nothing())?; + eval_block(&state, block, PipelineData::new())?; let end_time = Instant::now(); println!("{} ms", (end_time - start_time).as_millis()); - Ok(Value::Nothing { - span: call.positional[0].span, - }) + Ok(PipelineData::new()) } } diff --git a/crates/nu-command/src/system/ps.rs b/crates/nu-command/src/system/ps.rs index 68f9409a8..6e5072ae7 100644 --- a/crates/nu-command/src/system/ps.rs +++ b/crates/nu-command/src/system/ps.rs @@ -1,10 +1,11 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, ShellError, Signature, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Value, }; use sysinfo::{ProcessExt, System, SystemExt}; +#[derive(Clone)] pub struct Ps; impl Command for Ps { @@ -31,8 +32,8 @@ impl Command for Ps { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { run_ps(call) } @@ -45,7 +46,7 @@ impl Command for Ps { } } -fn run_ps(call: &Call) -> Result { +fn run_ps(call: &Call) -> Result { let span = call.head; let long = call.has_flag("long"); let mut sys = System::new_all(); @@ -124,5 +125,5 @@ fn run_ps(call: &Call) -> Result { } } - Ok(Value::List { vals: output, span }) + Ok(output.into_iter().into_pipeline_data()) } diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 8d03b4a7d..9ac2817a4 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -11,12 +11,13 @@ use nu_protocol::{ engine::{Command, EvaluationContext}, ShellError, Signature, SyntaxShape, Value, }; -use nu_protocol::{Span, ValueStream}; +use nu_protocol::{IntoPipelineData, PipelineData, Span, ValueStream}; use nu_engine::eval_expression; const OUTPUT_BUFFER_SIZE: usize = 8192; +#[derive(Clone)] pub struct External; impl Command for External { @@ -38,8 +39,8 @@ impl Command for External { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result { + input: PipelineData, + ) -> Result { let command = ExternalCommand::try_new(call, context)?; command.run_with_input(input) } @@ -82,7 +83,7 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { .collect() } - pub fn run_with_input(&self, input: Value) -> Result { + pub fn run_with_input(&self, input: PipelineData) -> Result { let mut process = self.create_command(); // TODO. We don't have a way to know the current directory @@ -101,11 +102,11 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { // If there is an input from the pipeline. The stdin from the process // is piped so it can be used to send the input information - if let Value::String { .. } = input { + if let PipelineData::Value(Value::String { .. }) = input { process.stdin(Stdio::piped()); } - if let Value::Stream { .. } = input { + if let PipelineData::Stream { .. } = input { process.stdin(Stdio::piped()); } @@ -116,33 +117,18 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { )), Ok(mut child) => { // if there is a string or a stream, that is sent to the pipe std - match input { - Value::String { val, span: _ } => { - if let Some(mut stdin_write) = child.stdin.take() { - self.write_to_stdin(&mut stdin_write, val.as_bytes())? - } - } - Value::Binary { val, span: _ } => { - if let Some(mut stdin_write) = child.stdin.take() { - self.write_to_stdin(&mut stdin_write, &val)? - } - } - Value::Stream { stream, span: _ } => { - if let Some(mut stdin_write) = child.stdin.take() { - for value in stream { - match value { - Value::String { val, span: _ } => { - self.write_to_stdin(&mut stdin_write, val.as_bytes())? - } - Value::Binary { val, span: _ } => { - self.write_to_stdin(&mut stdin_write, &val)? - } - _ => continue, - } + if let Some(mut stdin_write) = child.stdin.take() { + for value in input { + match value { + Value::String { val, span: _ } => { + self.write_to_stdin(&mut stdin_write, val.as_bytes())? } + Value::Binary { val, span: _ } => { + self.write_to_stdin(&mut stdin_write, &val)? + } + _ => continue, } } - _ => (), } // If this external is not the last expression, then its output is piped to a channel @@ -185,12 +171,9 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { }); // The ValueStream is consumed by the next expression in the pipeline - Value::Stream { - stream: ValueStream(Rc::new(RefCell::new(ChannelReceiver::new(rx)))), - span: Span::unknown(), - } + ChannelReceiver::new(rx).into_pipeline_data() } else { - Value::nothing() + PipelineData::new() }; match child.wait() { diff --git a/crates/nu-command/src/system/sys.rs b/crates/nu-command/src/system/sys.rs index b0323ffdf..8541b4649 100644 --- a/crates/nu-command/src/system/sys.rs +++ b/crates/nu-command/src/system/sys.rs @@ -1,10 +1,11 @@ use nu_protocol::{ ast::Call, engine::{Command, EvaluationContext}, - Example, ShellError, Signature, Span, Value, + Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value, }; use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt}; +#[derive(Clone)] pub struct Sys; impl Command for Sys { @@ -26,8 +27,8 @@ impl Command for Sys { &self, _context: &EvaluationContext, call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { run_sys(call) } @@ -40,7 +41,7 @@ impl Command for Sys { } } -fn run_sys(call: &Call) -> Result { +fn run_sys(call: &Call) -> Result { let span = call.head; let mut sys = System::new(); @@ -76,7 +77,8 @@ fn run_sys(call: &Call) -> Result { cols: headers, vals: values, span, - }) + } + .into_pipeline_data()) } pub fn trim_cstyle_null(s: String) -> String { diff --git a/crates/nu-command/src/viewers/griddle.rs b/crates/nu-command/src/viewers/griddle.rs index b44d468a8..42d66d7ed 100644 --- a/crates/nu-command/src/viewers/griddle.rs +++ b/crates/nu-command/src/viewers/griddle.rs @@ -8,6 +8,7 @@ use nu_protocol::{ use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions}; use terminal_size::{Height, Width}; +#[derive(Clone)] pub struct Griddle; impl Command for Griddle { diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index 93338f358..3d5f94992 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -5,6 +5,7 @@ use nu_table::StyledString; use std::collections::HashMap; use terminal_size::{Height, Width}; +#[derive(Clone)] pub struct Table; //NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one. diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index 84fe44fa1..c028625d7 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -26,11 +26,10 @@ fn generate_doc(name: &str, context: &EvaluationContext) -> (Vec, Vec Result { } } -fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result { - let engine_state = context.engine_state.borrow(); - let decl = engine_state.get_decl(call.decl_id); +fn eval_call( + context: &EvaluationContext, + call: &Call, + input: PipelineData, +) -> Result { + let decl = context.engine_state.get_decl(call.decl_id); if call.named.iter().any(|(flag, _)| flag.item == "help") { let full_help = get_full_help(&decl.signature(), &decl.examples(), context); Ok(Value::String { val: full_help, span: call.head, - }) + } + .into_pipeline_data()) } else if let Some(block_id) = decl.get_block_id() { - let state = context.enter_scope(); + let mut state = context.enter_scope(); for (arg, param) in call.positional.iter().zip( decl.signature() .required_positional @@ -102,8 +108,7 @@ fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result Result { - let engine_state = context.engine_state.borrow(); - - let decl_id = engine_state +) -> Result { + let decl_id = context + .engine_state .find_decl("run_external".as_bytes()) .ok_or_else(|| ShellError::ExternalNotSupported(*name_span))?; - let command = engine_state.get_decl(decl_id); + let command = context.engine_state.get_decl(decl_id); let mut call = Call::new(); @@ -216,9 +220,20 @@ pub fn eval_expression( value.follow_cell_path(&cell_path.tail) } Expr::RowCondition(_, expr) => eval_expression(context, expr), - Expr::Call(call) => eval_call(context, call, Value::nothing()), + Expr::Call(call) => { + // FIXME: protect this collect with ctrl-c + Ok(Value::List { + vals: eval_call(context, call, PipelineData::new())?.collect(), + span: expr.span, + }) + } Expr::ExternalCall(name, span, args) => { - eval_external(context, name, span, args, Value::nothing(), true) + // FIXME: protect this collect with ctrl-c + Ok(Value::List { + vals: eval_external(context, name, span, args, PipelineData::new(), true)? + .collect(), + span: expr.span, + }) } Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }), Expr::BinaryOp(lhs, op, rhs) => { @@ -249,11 +264,15 @@ pub fn eval_expression( } } Expr::Subexpression(block_id) => { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(*block_id); + let block = context.engine_state.get_block(*block_id); let state = context.enter_scope(); - eval_block(&state, block, Value::nothing()) + + // FIXME: protect this collect with ctrl-c + Ok(Value::List { + vals: eval_block(&state, block, PipelineData::new())?.collect(), + span: expr.span, + }) } Expr::Block(block_id) => Ok(Value::Block { val: *block_id, @@ -313,8 +332,8 @@ pub fn eval_expression( pub fn eval_block( context: &EvaluationContext, block: &Block, - mut input: Value, -) -> Result { + mut input: PipelineData, +) -> Result { for stmt in block.stmts.iter() { if let Statement::Pipeline(pipeline) = stmt { for (i, elem) in pipeline.expressions.iter().enumerate() { @@ -340,7 +359,7 @@ pub fn eval_block( } elem => { - input = eval_expression(context, elem)?; + input = eval_expression(context, elem)?.into_pipeline_data(); } } } diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index 7a418767f..da45d1f1c 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -7,6 +7,7 @@ use nu_protocol::{ }; #[cfg(test)] +#[derive(Clone)] pub struct Let; #[cfg(test)] @@ -33,8 +34,8 @@ impl Command for Let { &self, _context: &nu_protocol::engine::EvaluationContext, _call: &nu_protocol::ast::Call, - _input: nu_protocol::Value, - ) -> Result { + _input: nu_protocol::PipelineData, + ) -> Result { todo!() } } diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml index c44b03cf0..842aba468 100644 --- a/crates/nu-protocol/Cargo.toml +++ b/crates/nu-protocol/Cargo.toml @@ -11,4 +11,5 @@ miette = "3.0.0" serde = {version = "1.0.130", features = ["derive"]} chrono = { version="0.4.19", features=["serde"] } chrono-humanize = "0.2.1" -byte-unit = "4.0.9" \ No newline at end of file +byte-unit = "4.0.9" +im = "15.0.0" \ No newline at end of file diff --git a/crates/nu-protocol/src/engine/command.rs b/crates/nu-protocol/src/engine/command.rs index ce322eb87..a8b3a5581 100644 --- a/crates/nu-protocol/src/engine/command.rs +++ b/crates/nu-protocol/src/engine/command.rs @@ -1,8 +1,8 @@ -use crate::{ast::Call, value::Value, BlockId, Example, ShellError, Signature}; +use crate::{ast::Call, value::Value, BlockId, Example, PipelineData, ShellError, Signature}; use super::EvaluationContext; -pub trait Command: Send + Sync { +pub trait Command: Send + Sync + CommandClone { fn name(&self) -> &str; fn signature(&self) -> Signature { @@ -19,8 +19,8 @@ pub trait Command: Send + Sync { &self, context: &EvaluationContext, call: &Call, - input: Value, - ) -> Result; + input: PipelineData, + ) -> Result; fn is_binary(&self) -> bool { false @@ -55,3 +55,22 @@ pub trait Command: Send + Sync { None } } + +pub trait CommandClone { + fn clone_box(&self) -> Box; +} + +impl CommandClone for T +where + T: 'static + Command + Clone, +{ + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.clone_box() + } +} diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 830cd6569..a82853037 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -3,13 +3,14 @@ use crate::{ast::Block, BlockId, DeclId, Example, Signature, Span, Type, VarId}; use core::panic; use std::{collections::HashMap, slice::Iter}; +#[derive(Clone)] pub struct EngineState { - files: Vec<(String, usize, usize)>, - file_contents: Vec, - vars: Vec, - decls: Vec>, - blocks: Vec, - pub scope: Vec, + files: im::Vector<(String, usize, usize)>, + file_contents: im::Vector<(Vec, usize, usize)>, + vars: im::Vector, + decls: im::Vector>, + blocks: im::Vector, + pub scope: im::Vector, } // Tells whether a decl etc. is visible or not @@ -53,7 +54,7 @@ impl Visibility { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ScopeFrame { pub vars: HashMap, VarId>, predecls: HashMap, DeclId>, // temporary storage for predeclarations @@ -95,12 +96,12 @@ impl Default for EngineState { impl EngineState { pub fn new() -> Self { Self { - files: vec![], - file_contents: vec![], - vars: vec![], - decls: vec![], - blocks: vec![], - scope: vec![ScopeFrame::new()], + files: im::vector![], + file_contents: im::vector![], + vars: im::vector![], + decls: im::vector![], + blocks: im::vector![], + scope: im::vector![ScopeFrame::new()], } } @@ -112,7 +113,7 @@ impl EngineState { this.vars.extend(delta.vars); this.blocks.extend(delta.blocks); - if let Some(last) = this.scope.last_mut() { + if let Some(last) = this.scope.back_mut() { let first = delta.scope.remove(0); for item in first.decls.into_iter() { last.decls.insert(item.0, item.1); @@ -165,8 +166,10 @@ impl EngineState { } pub fn print_contents(&self) { - let string = String::from_utf8_lossy(&self.file_contents); - println!("{}", string); + for (contents, _, _) in self.file_contents.iter() { + let string = String::from_utf8_lossy(&contents); + println!("{}", string); + } } pub fn find_decl(&self, name: &[u8]) -> Option { @@ -200,7 +203,13 @@ impl EngineState { } pub fn get_span_contents(&self, span: &Span) -> &[u8] { - &self.file_contents[span.start..span.end] + for (contents, start, finish) in &self.file_contents { + if span.start >= *start && span.start < *finish { + return &contents[(span.start - start)..(span.end - start)]; + } + } + + panic!("internal error: span missing in file contents cache") } pub fn get_var(&self, var_id: VarId) -> &Type { @@ -256,7 +265,7 @@ impl EngineState { self.file_contents.len() } - pub fn files(&self) -> Iter<(String, usize, usize)> { + pub fn files(&self) -> impl Iterator { self.files.iter() } @@ -273,8 +282,11 @@ impl EngineState { pub fn get_file_source(&self, file_id: usize) -> String { for file in self.files.iter().enumerate() { if file.0 == file_id { - let output = - String::from_utf8_lossy(&self.file_contents[file.1 .1..file.1 .2]).to_string(); + let contents = self.get_span_contents(&Span { + start: file.1 .1, + end: file.1 .2, + }); + let output = String::from_utf8_lossy(contents).to_string(); return output; } @@ -286,12 +298,13 @@ impl EngineState { #[allow(unused)] pub(crate) fn add_file(&mut self, filename: String, contents: Vec) -> usize { let next_span_start = self.next_span_start(); + let next_span_end = next_span_start + contents.len(); - self.file_contents.extend(&contents); + self.file_contents + .push_back((contents, next_span_start, next_span_end)); - let next_span_end = self.next_span_start(); - - self.files.push((filename, next_span_start, next_span_end)); + self.files + .push_back((filename, next_span_start, next_span_end)); self.num_files() - 1 } @@ -304,7 +317,7 @@ pub struct StateWorkingSet<'a> { pub struct StateDelta { files: Vec<(String, usize, usize)>, - pub(crate) file_contents: Vec, + pub(crate) file_contents: Vec<(Vec, usize, usize)>, vars: Vec, // indexed by VarId decls: Vec>, // indexed by DeclId blocks: Vec, // indexed by BlockId @@ -520,10 +533,11 @@ impl<'a> StateWorkingSet<'a> { pub fn add_file(&mut self, filename: String, contents: &[u8]) -> usize { let next_span_start = self.next_span_start(); + let next_span_end = next_span_start + contents.len(); - self.delta.file_contents.extend(contents); - - let next_span_end = self.next_span_start(); + self.delta + .file_contents + .push((contents.to_vec(), next_span_start, next_span_end)); self.delta .files @@ -535,10 +549,16 @@ impl<'a> StateWorkingSet<'a> { pub fn get_span_contents(&self, span: Span) -> &[u8] { let permanent_end = self.permanent_state.next_span_start(); if permanent_end <= span.start { - &self.delta.file_contents[(span.start - permanent_end)..(span.end - permanent_end)] + for (contents, start, finish) in &self.delta.file_contents { + if (span.start >= *start) && (span.start < *finish) { + return &contents[(span.start - permanent_end)..(span.end - permanent_end)]; + } + } } else { - &self.permanent_state.file_contents[span.start..span.end] + return self.permanent_state.get_span_contents(&span); } + + panic!("internal error: missing span contents in file cache") } pub fn enter_scope(&mut self) { diff --git a/crates/nu-protocol/src/engine/evaluation_context.rs b/crates/nu-protocol/src/engine/evaluation_context.rs index b37629404..5fd4d17bc 100644 --- a/crates/nu-protocol/src/engine/evaluation_context.rs +++ b/crates/nu-protocol/src/engine/evaluation_context.rs @@ -5,7 +5,7 @@ use crate::{Example, ShellError, Signature, Value, VarId}; #[derive(Clone)] pub struct EvaluationContext { - pub engine_state: Rc>, + pub engine_state: Box, pub stack: Stack, } @@ -21,25 +21,11 @@ impl EvaluationContext { } } - pub fn add_var(&self, var_id: VarId, value: Value) { - // We need to make values concreate before we assign them to variables, as stream values - // will drain and remain drained. - // - // TODO: find a good home for converting a stream->list when storing into a variable - // TODO: add ctrl-c support when setting a var - - let value = match value { - Value::Stream { stream, span } => Value::List { - vals: stream.collect(), - span, - }, - x => x, - }; - + pub fn add_var(&mut self, var_id: VarId, value: Value) { self.stack.add_var(var_id, value); } - pub fn add_env_var(&self, var: String, value: String) { + pub fn add_env_var(&mut self, var: String, value: String) { self.stack.add_env_var(var, value); } @@ -48,23 +34,22 @@ impl EvaluationContext { } pub fn get_signatures(&self) -> Vec { - self.engine_state.borrow().get_signatures() + self.engine_state.get_signatures() } pub fn get_signatures_with_examples(&self) -> Vec<(Signature, Vec)> { - self.engine_state.borrow().get_signatures_with_examples() + self.engine_state.get_signatures_with_examples() } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct StackFrame { pub vars: HashMap, pub env_vars: HashMap, - pub parent: Option, } #[derive(Clone, Debug)] -pub struct Stack(Rc>); +pub struct Stack(Vec); impl Default for Stack { fn default() -> Self { @@ -74,64 +59,77 @@ impl Default for Stack { impl Stack { pub fn new() -> Stack { - Stack(Rc::new(RefCell::new(StackFrame { + Stack(vec![StackFrame { vars: HashMap::new(), env_vars: HashMap::new(), - parent: None, - }))) + }]) } pub fn get_var(&self, var_id: VarId) -> Result { - let this = self.0.borrow(); - match this.vars.get(&var_id) { - Some(v) => Ok(v.clone()), - _ => { - if let Some(parent) = &this.parent { - parent.get_var(var_id) - } else { - Err(ShellError::InternalError("variable not found".into())) - } + for frame in self.0.iter().rev() { + if let Some(v) = frame.vars.get(&var_id) { + return Ok(v.clone()); } } + Err(ShellError::InternalError("variable not found".into())) } - pub fn add_var(&self, var_id: VarId, value: Value) { - let mut this = self.0.borrow_mut(); - this.vars.insert(var_id, value); + pub fn add_var(&mut self, var_id: VarId, value: Value) { + let frame = self + .0 + .last_mut() + .expect("internal error: can't access stack frame"); + frame.vars.insert(var_id, value); } - pub fn add_env_var(&self, var: String, value: String) { - let mut this = self.0.borrow_mut(); - this.env_vars.insert(var, value); + pub fn add_env_var(&mut self, var: String, value: String) { + let frame = self + .0 + .last_mut() + .expect("internal error: can't access stack frame"); + frame.env_vars.insert(var, value); } - pub fn enter_scope(self) -> Stack { - Stack(Rc::new(RefCell::new(StackFrame { + pub fn enter_scope(&self) -> Stack { + // FIXME: VERY EXPENSIVE to clone entire stack + let mut output = self.clone(); + output.0.push(StackFrame { vars: HashMap::new(), env_vars: HashMap::new(), - parent: Some(self), - }))) + }); + + output } pub fn get_env_vars(&self) -> HashMap { - self.0.borrow().env_vars.clone() + let mut output = HashMap::new(); + + for frame in &self.0 { + output.extend(frame.env_vars.clone().into_iter()); + } + + output } pub fn get_env_var(&self, name: &str) -> Option { - self.0.borrow().env_vars.get(name).cloned() + for frame in self.0.iter().rev() { + if let Some(v) = frame.env_vars.get(name) { + return Some(v.to_string()); + } + } + None } pub fn print_stack(&self) { - println!("===frame==="); - println!("vars:"); - for (var, val) in &self.0.borrow().vars { - println!(" {}: {:?}", var, val); - } - println!("env vars:"); - for (var, val) in &self.0.borrow().env_vars { - println!(" {}: {:?}", var, val); - } - if let Some(parent) = &self.0.borrow().parent { - parent.print_stack() + for frame in self.0.iter().rev() { + println!("===frame==="); + println!("vars:"); + for (var, val) in &frame.vars { + println!(" {}: {:?}", var, val); + } + println!("env vars:"); + for (var, val) in &frame.env_vars { + println!(" {}: {:?}", var, val); + } } } } diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs index 6bd566bfa..081a9b0b4 100644 --- a/crates/nu-protocol/src/lib.rs +++ b/crates/nu-protocol/src/lib.rs @@ -2,6 +2,7 @@ pub mod ast; pub mod engine; mod example; mod id; +mod pipeline_data; mod shell_error; mod signature; mod span; @@ -12,6 +13,7 @@ pub use value::Value; pub use example::*; pub use id::*; +pub use pipeline_data::*; pub use shell_error::*; pub use signature::*; pub use span::*; diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs new file mode 100644 index 000000000..9b110f641 --- /dev/null +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -0,0 +1,62 @@ +use crate::{Span, Value, ValueStream}; + +pub enum PipelineData { + Value(Value), + Stream(ValueStream), +} + +impl PipelineData { + pub fn new() -> PipelineData { + PipelineData::Value(Value::nothing()) + } + + pub fn into_value(self) -> Value { + match self { + PipelineData::Value(v) => v, + PipelineData::Stream(s) => Value::List { + vals: s.collect(), + span: Span::unknown(), // FIXME? + }, + } + } +} + +impl Default for PipelineData { + fn default() -> Self { + PipelineData::new() + } +} + +impl Iterator for PipelineData { + type Item = Value; + + fn next(&mut self) -> Option { + match self { + PipelineData::Value(Value::Nothing { .. }) => None, + PipelineData::Value(v) => { + let prev = std::mem::take(v); + Some(prev) + } + PipelineData::Stream(stream) => stream.next(), + } + } +} + +pub trait IntoPipelineData { + fn into_pipeline_data(self) -> PipelineData; +} + +impl IntoPipelineData for Value { + fn into_pipeline_data(self) -> PipelineData { + PipelineData::Value(self) + } +} + +impl IntoPipelineData for T +where + T: Iterator + Send + 'static, +{ + fn into_pipeline_data(self) -> PipelineData { + PipelineData::Stream(ValueStream(Box::new(self))) + } +} diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index e29d4b79c..4c2a36313 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -1,7 +1,9 @@ use crate::ast::Call; use crate::engine::Command; +use crate::engine::CommandClone; use crate::engine::EvaluationContext; use crate::BlockId; +use crate::PipelineData; use crate::SyntaxShape; use crate::Value; use crate::VarId; @@ -335,6 +337,7 @@ impl Signature { } } +#[derive(Clone)] struct Predeclaration { signature: Signature, } @@ -356,12 +359,13 @@ impl Command for Predeclaration { &self, _context: &EvaluationContext, _call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { panic!("Internal error: can't run a predeclaration without a body") } } +#[derive(Clone)] struct BlockCommand { signature: Signature, block_id: BlockId, @@ -384,8 +388,8 @@ impl Command for BlockCommand { &self, _context: &EvaluationContext, _call: &Call, - _input: Value, - ) -> Result { + _input: PipelineData, + ) -> Result { panic!("Internal error: can't run custom command with 'run', use block_id"); } diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 976cb9b6b..3cd0b0a48 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -59,10 +59,6 @@ pub enum Value { vals: Vec, span: Span, }, - Stream { - stream: ValueStream, - span: Span, - }, List { vals: Vec, span: Span, @@ -110,7 +106,6 @@ impl Value { Value::Record { span, .. } => Ok(*span), Value::List { span, .. } => Ok(*span), Value::Block { span, .. } => Ok(*span), - Value::Stream { span, .. } => Ok(*span), Value::Nothing { span, .. } => Ok(*span), Value::Binary { span, .. } => Ok(*span), Value::CellPath { span, .. } => Ok(*span), @@ -129,7 +124,6 @@ impl Value { Value::Range { span, .. } => *span = new_span, Value::String { span, .. } => *span = new_span, Value::Record { span, .. } => *span = new_span, - Value::Stream { span, .. } => *span = new_span, Value::List { span, .. } => *span = new_span, Value::Block { span, .. } => *span = new_span, Value::Nothing { span, .. } => *span = new_span, @@ -158,7 +152,6 @@ impl Value { Value::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME Value::Nothing { .. } => Type::Nothing, Value::Block { .. } => Type::Block, - Value::Stream { .. } => Type::ValueStream, Value::Error { .. } => Type::Error, Value::Binary { .. } => Type::Binary, Value::CellPath { .. } => Type::CellPath, @@ -186,7 +179,6 @@ impl Value { Err(error) => format!("{:?}", error), }, Value::String { val, .. } => val, - Value::Stream { stream, .. } => stream.into_string(), Value::List { vals: val, .. } => format!( "[{}]", val.into_iter() @@ -228,7 +220,6 @@ impl Value { } }, Value::String { val, .. } => val, - Value::Stream { stream, .. } => stream.collect_string(), Value::List { vals: val, .. } => val .into_iter() .map(|x| x.collect_string()) @@ -274,13 +265,6 @@ impl Value { return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span)); } } - Value::Stream { stream, .. } => { - if let Some(item) = stream.nth(*count) { - current = item; - } else { - return Err(ShellError::AccessBeyondEndOfStream(*origin_span)); - } - } x => { return Err(ShellError::IncompatiblePathAccess( format!("{}", x.get_type()), @@ -329,27 +313,6 @@ impl Value { span: *span, }; } - Value::Stream { stream, span } => { - let mut output = vec![]; - for val in stream { - output.push(val.clone().follow_cell_path(&[PathMember::String { - val: column_name.clone(), - span: *origin_span, - }])?); - // if let Value::Record { cols, vals, .. } = val { - // for col in cols.iter().enumerate() { - // if col.1 == column_name { - // output.push(vals[col.0].clone()); - // } - // } - // } - } - - current = Value::List { - vals: output, - span: *span, - }; - } x => { return Err(ShellError::IncompatiblePathAccess( format!("{}", x.get_type()), @@ -374,64 +337,6 @@ impl Value { } } - pub fn map(self, span: Span, mut f: F) -> Result - where - Self: Sized, - F: FnMut(Self) -> Value + 'static, - { - match self { - Value::List { vals, .. } => Ok(Value::Stream { - stream: vals.into_iter().map(f).into_value_stream(), - span, - }), - Value::Stream { stream, .. } => Ok(Value::Stream { - stream: stream.map(f).into_value_stream(), - span, - }), - Value::Range { val, .. } => Ok(Value::Stream { - stream: val.into_range_iter()?.map(f).into_value_stream(), - span, - }), - v => { - let output = f(v); - match output { - Value::Error { error } => Err(error), - v => Ok(v), - } - } - } - } - - pub fn flat_map(self, span: Span, mut f: F) -> Value - where - Self: Sized, - U: IntoIterator, - ::IntoIter: 'static, - F: FnMut(Self) -> U + 'static, - { - match self { - Value::List { vals, .. } => Value::Stream { - stream: vals.into_iter().map(f).flatten().into_value_stream(), - span, - }, - Value::Stream { stream, .. } => Value::Stream { - stream: stream.map(f).flatten().into_value_stream(), - span, - }, - Value::Range { val, .. } => match val.into_range_iter() { - Ok(iter) => Value::Stream { - stream: iter.map(f).flatten().into_value_stream(), - span, - }, - Err(error) => Value::Error { error }, - }, - v => Value::Stream { - stream: f(v).into_iter().into_value_stream(), - span, - }, - } - } - pub fn string(val: impl Into, span: Span) -> Value { Value::String { val: val.into(), @@ -460,6 +365,12 @@ impl Value { } } +impl Default for Value { + fn default() -> Self { + Value::nothing() + } +} + impl PartialOrd for Value { fn partial_cmp(&self, other: &Self) -> Option { // Compare two floating point numbers. The decision interval for equality is dynamically @@ -511,24 +422,6 @@ impl PartialOrd for Value { .. }, ) if lhs_headers == rhs_headers && lhs == rhs => Some(Ordering::Equal), - (Value::Stream { stream: lhs, .. }, Value::Stream { stream: rhs, .. }) => { - lhs.clone().partial_cmp(rhs.clone()) - } - (Value::Stream { stream: lhs, .. }, Value::String { val: rhs, .. }) => { - lhs.clone().collect_string().partial_cmp(rhs) - } - (Value::String { val: lhs, .. }, Value::Stream { stream: rhs, .. }) => { - lhs.partial_cmp(&rhs.clone().collect_string()) - } - // NOTE: This may look a bit strange, but a `Stream` is still just a `List`, it just - // happens to be in an iterator form instead of a concrete form. The contained values - // can be compared. - (Value::Stream { stream: lhs, .. }, Value::List { vals: rhs, .. }) => { - lhs.clone().collect::>().partial_cmp(rhs) - } - (Value::List { vals: lhs, .. }, Value::Stream { stream: rhs, .. }) => { - lhs.partial_cmp(&rhs.clone().collect::>()) - } (Value::Binary { val: lhs, .. }, Value::Binary { val: rhs, .. }) => { lhs.partial_cmp(rhs) } @@ -852,10 +745,6 @@ impl Value { val: rhs.contains(lhs), span, }), - (lhs, Value::Stream { stream: rhs, .. }) => Ok(Value::Bool { - val: rhs.clone().any(|x| lhs == &x), - span, - }), _ => Err(ShellError::OperatorMismatch { op_span: op, lhs_ty: self.get_type(), @@ -886,10 +775,6 @@ impl Value { val: !rhs.contains(lhs), span, }), - (lhs, Value::Stream { stream: rhs, .. }) => Ok(Value::Bool { - val: rhs.clone().all(|x| lhs != &x), - span, - }), _ => Err(ShellError::OperatorMismatch { op_span: op, lhs_ty: self.get_type(), diff --git a/crates/nu-protocol/src/value/stream.rs b/crates/nu-protocol/src/value/stream.rs index 87ab2fec7..81aec0f0a 100644 --- a/crates/nu-protocol/src/value/stream.rs +++ b/crates/nu-protocol/src/value/stream.rs @@ -1,10 +1,7 @@ use crate::*; -use std::{cell::RefCell, fmt::Debug, rc::Rc}; +use std::fmt::Debug; -use serde::{ser::SerializeSeq, Deserialize, Serialize}; - -#[derive(Clone)] -pub struct ValueStream(pub Rc>>); +pub struct ValueStream(pub Box + Send + 'static>); impl ValueStream { pub fn into_string(self) -> String { @@ -22,8 +19,8 @@ impl ValueStream { .join("\n") } - pub fn from_stream(input: impl Iterator + 'static) -> ValueStream { - ValueStream(Rc::new(RefCell::new(input))) + pub fn from_stream(input: impl Iterator + Send + 'static) -> ValueStream { + ValueStream(Box::new(input)) } } @@ -38,66 +35,66 @@ impl Iterator for ValueStream { fn next(&mut self) -> Option { { - self.0.borrow_mut().next() + self.0.next() } } } -impl Serialize for ValueStream { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut seq = serializer.serialize_seq(None)?; +// impl Serialize for ValueStream { +// fn serialize(&self, serializer: S) -> Result +// where +// S: serde::Serializer, +// { +// let mut seq = serializer.serialize_seq(None)?; - for element in self.0.borrow_mut().into_iter() { - seq.serialize_element(&element)?; - } - seq.end() - } -} +// for element in self.0.borrow_mut().into_iter() { +// seq.serialize_element(&element)?; +// } +// seq.end() +// } +// } -impl<'de> Deserialize<'de> for ValueStream { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_seq(MySeqVisitor) - } -} +// impl<'de> Deserialize<'de> for ValueStream { +// fn deserialize(deserializer: D) -> Result +// where +// D: serde::Deserializer<'de>, +// { +// deserializer.deserialize_seq(MySeqVisitor) +// } +// } -struct MySeqVisitor; +// struct MySeqVisitor; -impl<'a> serde::de::Visitor<'a> for MySeqVisitor { - type Value = ValueStream; +// impl<'a> serde::de::Visitor<'a> for MySeqVisitor { +// type Value = ValueStream; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a value stream") - } +// fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { +// formatter.write_str("a value stream") +// } - fn visit_seq(self, mut seq: A) -> Result - where - A: serde::de::SeqAccess<'a>, - { - let mut output: Vec = vec![]; +// fn visit_seq(self, mut seq: A) -> Result +// where +// A: serde::de::SeqAccess<'a>, +// { +// let mut output: Vec = vec![]; - while let Some(value) = seq.next_element()? { - output.push(value); - } +// while let Some(value) = seq.next_element()? { +// output.push(value); +// } - Ok(ValueStream(Rc::new(RefCell::new(output.into_iter())))) - } -} +// Ok(ValueStream(Rc::new(RefCell::new(output.into_iter())))) +// } +// } -pub trait IntoValueStream { - fn into_value_stream(self) -> ValueStream; -} +// pub trait IntoValueStream { +// fn into_value_stream(self) -> ValueStream; +// } -impl IntoValueStream for T -where - T: Iterator + 'static, -{ - fn into_value_stream(self) -> ValueStream { - ValueStream::from_stream(self) - } -} +// impl IntoValueStream for T +// where +// T: Iterator + 'static, +// { +// fn into_value_stream(self) -> ValueStream { +// ValueStream::from_stream(self) +// } +// }