This commit is contained in:
JT 2021-10-25 17:01:02 +13:00
parent ab9d6b206d
commit b6d269e90a
63 changed files with 1075 additions and 1013 deletions

67
Cargo.lock generated
View File

@ -93,6 +93,15 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitmaps"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
dependencies = [
"typenum",
]
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "0.2.17" version = "0.2.17"
@ -378,6 +387,20 @@ dependencies = [
"libc", "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]] [[package]]
name = "instant" name = "instant"
version = "0.1.11" version = "0.1.11"
@ -640,6 +663,7 @@ dependencies = [
"byte-unit", "byte-unit",
"chrono", "chrono",
"chrono-humanize", "chrono-humanize",
"im",
"miette", "miette",
"serde", "serde",
"thiserror", "thiserror",
@ -823,7 +847,7 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha", "rand_chacha",
"rand_core", "rand_core 0.6.3",
"rand_hc", "rand_hc",
] ]
@ -834,9 +858,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [ dependencies = [
"ppv-lite86", "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]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.6.3" version = "0.6.3"
@ -852,7 +882,16 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [ 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]] [[package]]
@ -1032,6 +1071,16 @@ dependencies = [
"libc", "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]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.7.0" version = "1.7.0"
@ -1198,6 +1247,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]] [[package]]
name = "unicode-linebreak" name = "unicode-linebreak"
version = "0.1.2" version = "0.1.2"
@ -1237,6 +1292,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]] [[package]]
name = "vte" name = "vte"
version = "0.10.1" version = "0.10.1"

View File

@ -4,26 +4,25 @@ use nu_engine::eval_block;
use nu_parser::{flatten_block, parse}; use nu_parser::{flatten_block, parse};
use nu_protocol::{ use nu_protocol::{
engine::{EngineState, EvaluationContext, Stack, StateWorkingSet}, engine::{EngineState, EvaluationContext, Stack, StateWorkingSet},
Value, PipelineData, Value,
}; };
use reedline::Completer; use reedline::Completer;
const SEP: char = std::path::MAIN_SEPARATOR; const SEP: char = std::path::MAIN_SEPARATOR;
pub struct NuCompleter { pub struct NuCompleter {
engine_state: Rc<RefCell<EngineState>>, engine_state: Box<EngineState>,
} }
impl NuCompleter { impl NuCompleter {
pub fn new(engine_state: Rc<RefCell<EngineState>>) -> Self { pub fn new(engine_state: Box<EngineState>) -> Self {
Self { engine_state } Self { engine_state }
} }
} }
impl Completer for NuCompleter { impl Completer for NuCompleter {
fn complete(&self, line: &str, pos: usize) -> Vec<(reedline::Span, String)> { fn complete(&self, line: &str, pos: usize) -> Vec<(reedline::Span, String)> {
let engine_state = self.engine_state.borrow(); let mut working_set = StateWorkingSet::new(&*self.engine_state);
let mut working_set = StateWorkingSet::new(&*engine_state);
let offset = working_set.next_span_start(); let offset = working_set.next_span_start();
let pos = offset + pos; let pos = offset + pos;
let (output, _err) = parse(&mut working_set, Some("completer"), line.as_bytes(), false); 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 { for v in &scope.vars {
if v.0.starts_with(prefix) { if v.0.starts_with(prefix) {
output.push(( output.push((
@ -76,11 +75,10 @@ impl Completer for NuCompleter {
engine_state: self.engine_state.clone(), engine_state: self.engine_state.clone(),
stack: Stack::default(), stack: Stack::default(),
}; };
let result = eval_block(&context, &block, Value::nothing()); let result = eval_block(&context, &block, PipelineData::new());
let v: Vec<_> = match result { let v: Vec<_> = match result {
Ok(Value::List { vals, .. }) => vals Ok(pd) => pd
.into_iter()
.map(move |x| { .map(move |x| {
let s = x.as_string().expect( let s = x.as_string().expect(
"FIXME: better error handling for custom completions", "FIXME: better error handling for custom completions",

View File

@ -1,9 +1,10 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -27,8 +28,8 @@ impl Command for SubCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_binary(context, call, input) into_binary(context, call, input)
} }
@ -86,26 +87,28 @@ impl Command for SubCommand {
fn into_binary( fn into_binary(
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?; // let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(head, move |v| { Ok(input
action(v, head) .map(move |v| {
// FIXME: Add back in cell_path support action(v, head)
// if column_paths.is_empty() { // FIXME: Add back in cell_path support
// action(v, head) // if column_paths.is_empty() {
// } else { // action(v, head)
// let mut ret = v; // } else {
// for path in &column_paths { // let mut ret = v;
// ret = // for path in &column_paths {
// ret.swap_data_by_cell_path(path, Box::new(move |old| action(old, old.tag())))?; // 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<u8> { fn int_to_endian(n: i64) -> Vec<u8> {

View File

@ -2,9 +2,10 @@ use nu_engine::get_full_help;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Signature, Value, IntoPipelineData, PipelineData, Signature, Value,
}; };
#[derive(Clone)]
pub struct Into; pub struct Into;
impl Command for Into { impl Command for Into {
@ -24,12 +25,13 @@ impl Command for Into {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::String { Ok(Value::String {
val: get_full_help(&Into.signature(), &[], context), val: get_full_help(&Into.signature(), &[], context),
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} }
} }

View File

@ -1,9 +1,10 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -27,8 +28,8 @@ impl Command for SubCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_filesize(context, call, input) into_filesize(context, call, input)
} }
@ -114,29 +115,31 @@ impl Command for SubCommand {
fn into_filesize( fn into_filesize(
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let call_paths: Vec<ColumnPath> = args.rest(0)?; // let call_paths: Vec<ColumnPath> = args.rest(0)?;
input.map(head, move |v| { Ok(input
action(v, head) .map(move |v| {
action(v, head)
// FIXME: Add back cell_path support // FIXME: Add back cell_path support
// if column_paths.is_empty() { // if column_paths.is_empty() {
// action(&v, v.tag()) // action(&v, v.tag())
// } else { // } else {
// let mut ret = v; // let mut ret = v;
// for path in &column_paths { // for path in &column_paths {
// ret = ret.swap_data_by_column_path( // ret = ret.swap_data_by_column_path(
// path, // path,
// Box::new(move |old| action(old, old.tag())), // Box::new(move |old| action(old, old.tag())),
// )?; // )?;
// } // }
// Ok(ret) // Ok(ret)
// } // }
}) })
.into_pipeline_data())
} }
pub fn action(input: Value, span: Span) -> Value { pub fn action(input: Value, span: Span) -> Value {

View File

@ -1,9 +1,10 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, IntoValueStream, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -27,8 +28,8 @@ impl Command for SubCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_int(context, call, input) into_int(context, call, input)
} }
@ -78,10 +79,8 @@ impl Command for SubCommand {
Example { Example {
description: "Convert bool to integer", description: "Convert bool to integer",
example: "[$false, $true] | into int", example: "[$false, $true] | into int",
result: Some(Value::Stream { result: Some(Value::List {
stream: vec![Value::test_int(0), Value::test_int(1)] vals: vec![Value::test_int(0), Value::test_int(1)],
.into_iter()
.into_value_stream(),
span: Span::unknown(), span: Span::unknown(),
}), }),
}, },
@ -92,26 +91,28 @@ impl Command for SubCommand {
fn into_int( fn into_int(
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head; let head = call.head;
// let column_paths: Vec<CellPath> = call.rest(context, 0)?; // let column_paths: Vec<CellPath> = call.rest(context, 0)?;
input.map(head, move |v| { Ok(input
action(v, head) .map(move |v| {
// FIXME: Add back cell_path support action(v, head)
// if column_paths.is_empty() { // FIXME: Add back cell_path support
// action(&v, v.tag()) // if column_paths.is_empty() {
// } else { // action(&v, v.tag())
// let mut ret = v; // } else {
// for path in &column_paths { // let mut ret = v;
// ret = ret // for path in &column_paths {
// .swap_data_by_column_path(path, Box::new(move |old| action(old, old.tag())))?; // 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 { pub fn action(input: Value, span: Span) -> Value {

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Alias; pub struct Alias;
impl Command for Alias { impl Command for Alias {
@ -27,8 +28,8 @@ impl Command for Alias {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Def; pub struct Def;
impl Command for Def { impl Command for Def {
@ -28,8 +29,8 @@ impl Command for Def {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, CallExt}; use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Do; pub struct Do;
impl Command for Do { impl Command for Do {
@ -29,15 +30,14 @@ impl Command for Do {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0] let block_id = call.positional[0]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
let rest: Vec<Value> = call.rest(context, 1)?; let rest: Vec<Value> = call.rest(context, 1)?;
let engine_state = context.engine_state.borrow(); let block = context.engine_state.get_block(block_id);
let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct ExportDef; pub struct ExportDef;
impl Command for ExportDef { impl Command for ExportDef {
@ -28,8 +29,8 @@ impl Command for ExportDef {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, eval_expression}; use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct For;
impl Command for For { impl Command for For {
@ -38,8 +39,8 @@ impl Command for For {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let var_id = call.positional[0] let var_id = call.positional[0]
.as_var() .as_var()
.expect("internal error: missing variable"); .expect("internal error: missing variable");
@ -55,19 +56,26 @@ impl Command for For {
let context = context.clone(); let context = context.clone();
values.map(call.head, move |x| { match values {
let engine_state = context.engine_state.borrow(); Value::List { vals, span } => Ok(vals
let block = engine_state.get_block(block); .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()) { match eval_block(&state, block, PipelineData::new()) {
Ok(value) => value, Ok(value) => Value::List {
Err(error) => Value::Error { error }, vals: value.collect(),
} span,
}) },
Err(error) => Value::Error { error },
}
})
.into_pipeline_data()),
}
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {

View File

@ -1,11 +1,13 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, 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}; use nu_engine::{get_full_help, CallExt};
#[derive(Clone)]
pub struct Help; pub struct Help;
impl Command for Help { impl Command for Help {
@ -36,8 +38,8 @@ impl Command for Help {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
help(context, call) help(context, call)
} }
@ -72,7 +74,7 @@ impl Command for Help {
} }
} }
fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> { fn help(context: &EvaluationContext, call: &Call) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let find: Option<Spanned<String>> = call.get_flag(context, "find")?; let find: Option<Spanned<String>> = call.get_flag(context, "find")?;
let rest: Vec<Spanned<String>> = call.rest(context, 0)?; let rest: Vec<Spanned<String>> = call.rest(context, 0)?;
@ -114,10 +116,7 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
} }
} }
return Ok(Value::List { return Ok(found_cmds_vec.into_iter().into_pipeline_data());
vals: found_cmds_vec,
span: head,
});
} }
if !rest.is_empty() { if !rest.is_empty() {
@ -151,10 +150,7 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
}); });
} }
Ok(Value::List { Ok(found_cmds_vec.into_iter().into_pipeline_data())
vals: found_cmds_vec,
span: head,
})
} else { } else {
let mut name = String::new(); let mut name = String::new();
let mut output = String::new(); let mut output = String::new();
@ -177,7 +173,8 @@ fn help(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
Ok(Value::String { Ok(Value::String {
val: output, val: output,
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} else { } else {
Err(ShellError::CommandNotFound(span(&[ Err(ShellError::CommandNotFound(span(&[
rest[0].span, rest[0].span,
@ -355,7 +352,8 @@ You can also learn more at https://www.nushell.sh/book/"#;
Ok(Value::String { Ok(Value::String {
val: msg.into(), val: msg.into(),
span: head, span: head,
}) }
.into_pipeline_data())
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Hide; pub struct Hide;
impl Command for Hide { impl Command for Hide {
@ -21,8 +22,8 @@ impl Command for Hide {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, eval_expression}; use nu_engine::{eval_block, eval_expression};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct If;
impl Command for If { impl Command for If {
@ -29,8 +30,8 @@ impl Command for If {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = &call.positional[0]; let cond = &call.positional[0];
let then_block = call.positional[1] let then_block = call.positional[1]
.as_block() .as_block()
@ -40,25 +41,24 @@ impl Command for If {
let result = eval_expression(context, cond)?; let result = eval_expression(context, cond)?;
match result { match result {
Value::Bool { val, span } => { Value::Bool { val, span } => {
let engine_state = context.engine_state.borrow();
if val { if val {
let block = engine_state.get_block(then_block); let block = context.engine_state.get_block(then_block);
let state = context.enter_scope(); let state = context.enter_scope();
eval_block(&state, block, input) eval_block(&state, block, input)
} else if let Some(else_case) = else_case { } else if let Some(else_case) = else_case {
if let Some(else_expr) = else_case.as_keyword() { if let Some(else_expr) = else_case.as_keyword() {
if let Some(block_id) = else_expr.as_block() { 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(); let state = context.enter_scope();
eval_block(&state, block, input) eval_block(&state, block, input)
} else { } else {
eval_expression(context, else_expr) eval_expression(context, else_expr).map(|x| x.into_pipeline_data())
} }
} else { } else {
eval_expression(context, else_case) eval_expression(context, else_case).map(|x| x.into_pipeline_data())
} }
} else { } else {
Ok(Value::Nothing { span }) Ok(PipelineData::new())
} }
} }
_ => Err(ShellError::CantConvert("bool".into(), result.span()?)), _ => Err(ShellError::CantConvert("bool".into(), result.span()?)),

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Let; pub struct Let;
impl Command for Let { impl Command for Let {
@ -28,8 +29,8 @@ impl Command for Let {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let var_id = call.positional[0] let var_id = call.positional[0]
.as_var() .as_var()
.expect("internal error: missing variable"); .expect("internal error: missing variable");
@ -43,8 +44,6 @@ impl Command for Let {
//println!("Adding: {:?} to {}", rhs, var_id); //println!("Adding: {:?} to {}", rhs, var_id);
context.add_var(var_id, rhs); context.add_var(var_id, rhs);
Ok(Value::Nothing { Ok(PipelineData::new())
span: call.positional[0].span,
})
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Module; pub struct Module;
impl Command for Module { impl Command for Module {
@ -27,8 +28,8 @@ impl Command for Module {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,9 +1,10 @@
use nu_engine::{eval_block, CallExt}; use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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. /// Source a file for environment variables.
#[derive(Clone)]
pub struct Source; pub struct Source;
impl Command for Source { impl Command for Source {
@ -27,17 +28,13 @@ impl Command for Source {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
// Note: this hidden positional is the block_id that corresponded to the 0th position // Note: this hidden positional is the block_id that corresponded to the 0th position
// it is put here by the parser // it is put here by the parser
let block_id: i64 = call.req(context, 1)?; let block_id: i64 = call.req(context, 1)?;
let block = context let block = context.engine_state.get_block(block_id as usize).clone();
.engine_state
.borrow()
.get_block(block_id as usize)
.clone();
eval_block(context, &block, input) eval_block(context, &block, input)
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Use; pub struct Use;
impl Command for Use { impl Command for Use {
@ -21,8 +22,8 @@ impl Command for Use {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct LetEnv; pub struct LetEnv;
impl Command for LetEnv { impl Command for LetEnv {
@ -28,8 +29,8 @@ impl Command for LetEnv {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let env_var = call.positional[0] let env_var = call.positional[0]
.as_string() .as_string()
.expect("internal error: missing variable"); .expect("internal error: missing variable");
@ -44,8 +45,6 @@ impl Command for LetEnv {
//println!("Adding: {:?} to {}", rhs, var_id); //println!("Adding: {:?} to {}", rhs, var_id);
context.add_env_var(env_var, rhs); context.add_env_var(env_var, rhs);
Ok(Value::Nothing { Ok(PipelineData::new())
span: call.positional[0].span,
})
} }
} }

View File

@ -4,19 +4,18 @@ use nu_engine::eval_block;
use nu_parser::parse; use nu_parser::parse;
use nu_protocol::{ use nu_protocol::{
engine::{Command, EngineState, EvaluationContext, StateWorkingSet}, engine::{Command, EngineState, EvaluationContext, StateWorkingSet},
Value, PipelineData, Value,
}; };
use super::{From, Into, Split}; use super::{From, Into, Split};
pub fn test_examples(cmd: impl Command + 'static) { pub fn test_examples(cmd: impl Command + 'static) {
let examples = cmd.examples(); let examples = cmd.examples();
let engine_state = Rc::new(RefCell::new(EngineState::new())); let mut engine_state = Box::new(EngineState::new());
let delta = { let delta = {
// Base functions that are needed for testing // Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible // 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); let mut working_set = StateWorkingSet::new(&*engine_state);
working_set.add_decl(Box::new(From)); working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(Into)); working_set.add_decl(Box::new(Into));
@ -28,7 +27,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
working_set.render() working_set.render()
}; };
EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); EngineState::merge_delta(&mut *engine_state, delta);
for example in examples { for example in examples {
// Skip tests that don't have results to compare to // 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 start = std::time::Instant::now();
let (block, delta) = { let (block, delta) = {
let engine_state = engine_state.borrow(); let engine_state = engine_state;
let mut working_set = StateWorkingSet::new(&*engine_state); let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) = parse(&mut working_set, None, example.example.as_bytes(), false); 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()) (output, working_set.render())
}; };
EngineState::merge_delta(&mut *engine_state.borrow_mut(), delta); EngineState::merge_delta(&mut *engine_state, delta);
let state = EvaluationContext { let state = EvaluationContext {
engine_state: engine_state.clone(), engine_state: engine_state.clone(),
stack: nu_protocol::engine::Stack::new(), 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), Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
Ok(result) => { Ok(result) => {
let result = result.into_value();
println!("input: {}", example.example); println!("input: {}", example.example);
println!("result: {:?}", result); println!("result: {:?}", result);
println!("done: {:?}", start.elapsed()); println!("done: {:?}", start.elapsed());

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, Value}; use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value};
#[derive(Clone)]
pub struct Git; pub struct Git;
impl Command for Git { impl Command for Git {
@ -21,8 +22,8 @@ impl Command for Git {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
use std::process::Command as ProcessCommand; use std::process::Command as ProcessCommand;
use std::process::Stdio; use std::process::Stdio;
@ -37,17 +38,18 @@ impl Command for Git {
Ok(Value::String { Ok(Value::String {
val: String::from_utf8_lossy(&result).to_string(), val: String::from_utf8_lossy(&result).to_string(),
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} }
Err(_err) => { Err(_err) => {
// FIXME: Move this to an external signature and add better error handling // FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing()) Ok(PipelineData::new())
} }
} }
} }
Err(_err) => { Err(_err) => {
// FIXME: Move this to an external signature and add better error handling // FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing()) Ok(PipelineData::new())
} }
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct GitCheckout;
impl Command for GitCheckout { impl Command for GitCheckout {
@ -26,8 +27,8 @@ impl Command for GitCheckout {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
use std::process::Command as ProcessCommand; use std::process::Command as ProcessCommand;
use std::process::Stdio; use std::process::Stdio;
@ -52,17 +53,18 @@ impl Command for GitCheckout {
Ok(Value::String { Ok(Value::String {
val: String::from_utf8_lossy(&result).to_string(), val: String::from_utf8_lossy(&result).to_string(),
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} }
Err(_err) => { Err(_err) => {
// FIXME: Move this to an external signature and add better error handling // FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing()) Ok(PipelineData::new())
} }
} }
} }
Err(_err) => { Err(_err) => {
// FIXME: Move this to an external signature and add better error handling // FIXME: Move this to an external signature and add better error handling
Ok(Value::nothing()) Ok(PipelineData::new())
} }
} }
} }

View File

@ -5,8 +5,11 @@ use std::process::Stdio;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::IntoPipelineData;
use nu_protocol::PipelineData;
use nu_protocol::{Signature, Value}; use nu_protocol::{Signature, Value};
#[derive(Clone)]
pub struct ListGitBranches; 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. //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, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let list_branches = ProcessCommand::new("git") let list_branches = ProcessCommand::new("git")
.arg("branch") .arg("branch")
.stdout(Stdio::piped()) .stdout(Stdio::piped())
@ -55,15 +58,12 @@ impl Command for ListGitBranches {
}) })
.collect(); .collect();
Ok(Value::List { Ok(lines.into_iter().into_pipeline_data())
vals: lines,
span: call.head,
})
} else { } else {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} else { } else {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Cd; pub struct Cd;
impl Command for Cd { impl Command for Cd {
@ -22,8 +23,8 @@ impl Command for Cd {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let path: Option<String> = call.opt(context, 0)?; let path: Option<String> = call.opt(context, 0)?;
let path = match path { let path = match path {
@ -41,6 +42,6 @@ impl Command for Cd {
//FIXME: this only changes the current scope, but instead this environment variable //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 //should probably be a block that loads the information from the state in the overlay
context.add_env_var("PWD".into(), path); context.add_env_var("PWD".into(), path);
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -6,10 +6,11 @@ use nu_engine::CallExt;
use nu_path::canonicalize_with; use nu_path::canonicalize_with;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; use crate::filesystem::util::FileStructure;
#[derive(Clone)]
pub struct Cp; pub struct Cp;
#[allow(unused_must_use)] #[allow(unused_must_use)]
@ -39,8 +40,8 @@ impl Command for Cp {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
let source: String = call.req(context, 0)?; let source: String = call.req(context, 0)?;
let destination: String = call.req(context, 1)?; let destination: String = call.req(context, 1)?;
let interactive = call.has_flag("interactive"); let interactive = call.has_flag("interactive");
@ -202,6 +203,6 @@ impl Command for Cp {
} }
} }
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -2,8 +2,9 @@ use chrono::{DateTime, Utc};
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; 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. //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, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let pattern = if let Some(expr) = call.positional.get(0) { let pattern = if let Some(expr) = call.positional.get(0) {
let result = eval_expression(context, expr)?; let result = eval_expression(context, expr)?;
let mut result = result.as_string()?; let mut result = result.as_string()?;
@ -50,69 +51,66 @@ impl Command for Ls {
let call_span = call.head; let call_span = call.head;
let glob = glob::glob(&pattern).unwrap(); let glob = glob::glob(&pattern).unwrap();
Ok(Value::Stream { Ok(glob
stream: glob .into_iter()
.into_iter() .map(move |x| match x {
.map(move |x| match x { Ok(path) => match std::fs::symlink_metadata(&path) {
Ok(path) => match std::fs::symlink_metadata(&path) { Ok(metadata) => {
Ok(metadata) => { let is_file = metadata.is_file();
let is_file = metadata.is_file(); let is_dir = metadata.is_dir();
let is_dir = metadata.is_dir(); let filesize = metadata.len();
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![ let mut vals = vec![
Value::String { Value::String {
val: path.to_string_lossy().to_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<Utc> = date.into();
cols.push("modified".into());
vals.push(Value::Date {
val: utc.into(),
span: call_span,
});
}
Value::Record {
cols,
vals,
span: call_span, 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<Utc> = 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()], Value::Record {
vals: vec![ cols,
Value::String { vals,
val: path.to_string_lossy().to_string(),
span: call_span,
},
Value::Nothing { span: call_span },
Value::Nothing { span: call_span },
],
span: call_span, 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 }, },
}) _ => Value::Nothing { span: call_span },
.into_value_stream(), })
span: call_span, .into_pipeline_data())
})
} }
} }

View File

@ -4,8 +4,11 @@ use std::env::current_dir;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Mkdir;
impl Command for Mkdir { impl Command for Mkdir {
@ -31,8 +34,8 @@ impl Command for Mkdir {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
let path = current_dir()?; let path = current_dir()?;
let mut directories = call let mut directories = call
.rest::<String>(context, 0)? .rest::<String>(context, 0)?
@ -67,8 +70,6 @@ impl Command for Mkdir {
} }
} }
let stream = ValueStream::from_stream(stream.into_iter()); Ok(stream.into_iter().into_pipeline_data())
let span = call.head;
Ok(Value::Stream { stream, span })
} }
} }

View File

@ -5,8 +5,9 @@ use super::util::get_interactive_confirmation;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Mv;
#[allow(unused_must_use)] #[allow(unused_must_use)]
@ -39,8 +40,8 @@ impl Command for Mv {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
// TODO: handle invalid directory or insufficient permissions when moving // TODO: handle invalid directory or insufficient permissions when moving
let source: String = call.req(context, 0)?; let source: String = call.req(context, 0)?;
let destination: String = call.req(context, 1)?; let destination: String = call.req(context, 1)?;
@ -128,7 +129,7 @@ impl Command for Mv {
move_file(call, &entry, &destination)? move_file(call, &entry, &destination)?
} }
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -8,8 +8,11 @@ use super::util::get_interactive_confirmation;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Rm;
// Where self.0 is the unexpanded target's positional index (i.e. call.positional[self.0].span) // 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, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
rm(context, call) rm(context, call)
} }
} }
fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> { fn rm(context: &EvaluationContext, call: &Call) -> Result<PipelineData, ShellError> {
let trash = call.has_flag("trash"); let trash = call.has_flag("trash");
let permanent = call.has_flag("permanent"); let permanent = call.has_flag("permanent");
let interactive = call.has_flag("interactive"); let interactive = call.has_flag("interactive");
@ -164,11 +167,7 @@ fn rm(context: &EvaluationContext, call: &Call) -> Result<Value, ShellError> {
// let temp = rm_helper(call, args).flatten(); // let temp = rm_helper(call, args).flatten();
// let temp = input.flatten(call.head, move |_| rm_helper(call, args)); // let temp = input.flatten(call.head, move |_| rm_helper(call, args));
Ok(Value::Stream { Ok(response.into_iter().into_pipeline_data())
stream: ValueStream::from_stream(response.into_iter()),
span: call.head,
})
// Ok(Value::Nothing { span }) // Ok(Value::Nothing { span })
} }

View File

@ -3,8 +3,9 @@ use std::fs::OpenOptions;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Touch;
impl Command for Touch { impl Command for Touch {
@ -30,8 +31,8 @@ impl Command for Touch {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
let target: String = call.req(context, 0)?; let target: String = call.req(context, 0)?;
let rest: Vec<String> = call.rest(context, 1)?; let rest: Vec<String> = call.rest(context, 1)?;
@ -47,6 +48,6 @@ impl Command for Touch {
} }
} }
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Each;
impl Command for Each { impl Command for Each {
@ -43,8 +44,8 @@ impl Command for Each {
vec![Example { vec![Example {
example: "[1 2 3] | each { 2 * $it }", example: "[1 2 3] | each { 2 * $it }",
description: "Multiplies elements in list", description: "Multiplies elements in list",
result: Some(Value::Stream { result: Some(Value::List {
stream: stream_test_1.into_iter().into_value_stream(), vals: stream_test_1,
span: Span::unknown(), span: Span::unknown(),
}), }),
}] }]
@ -54,8 +55,8 @@ impl Command for Each {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0] let block_id = call.positional[0]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
@ -64,190 +65,186 @@ impl Command for Each {
let context = context.clone(); let context = context.clone();
let span = call.head; let span = call.head;
match input { // match input {
Value::Range { val, .. } => Ok(Value::Stream { // Value::Range { val, .. } => Ok(val
stream: val // .into_range_iter()?
.into_range_iter()? // .enumerate()
.enumerate() // .map(move |(idx, x)| {
.map(move |(idx, x)| { // let block = context.engine_state.get_block(block_id);
let engine_state = context.engine_state.borrow();
let block = 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) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { // if let Some(var_id) = &var.var_id {
if numbered { // if numbered {
state.add_var( // state.add_var(
*var_id, // *var_id,
Value::Record { // Value::Record {
cols: vec!["index".into(), "item".into()], // cols: vec!["index".into(), "item".into()],
vals: vec![ // vals: vec![
Value::Int { // Value::Int {
val: idx as i64, // val: idx as i64,
span, // span,
}, // },
x, // x,
], // ],
span, // span,
}, // },
); // );
} else { // } else {
state.add_var(*var_id, x); // state.add_var(*var_id, x);
} // }
} // }
} // }
match eval_block(&state, block, Value::nothing()) { // match eval_block(&state, block, Value::nothing()) {
Ok(v) => v, // Ok(v) => v,
Err(error) => Value::Error { error }, // Err(error) => Value::Error { error },
} // }
}) // })
.into_value_stream(), // .into_pipeline_data()),
span: call.head, // Value::List { vals: val, .. } => Ok(Value::Stream {
}), // stream: val
Value::List { vals: val, .. } => Ok(Value::Stream { // .into_iter()
stream: val // .enumerate()
.into_iter() // .map(move |(idx, x)| {
.enumerate() // let engine_state = context.engine_state.borrow();
.map(move |(idx, x)| { // let block = engine_state.get_block(block_id);
let engine_state = context.engine_state.borrow();
let block = 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) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { // if let Some(var_id) = &var.var_id {
if numbered { // if numbered {
state.add_var( // state.add_var(
*var_id, // *var_id,
Value::Record { // Value::Record {
cols: vec!["index".into(), "item".into()], // cols: vec!["index".into(), "item".into()],
vals: vec![ // vals: vec![
Value::Int { // Value::Int {
val: idx as i64, // val: idx as i64,
span, // span,
}, // },
x, // x,
], // ],
span, // span,
}, // },
); // );
} else { // } else {
state.add_var(*var_id, x); // state.add_var(*var_id, x);
} // }
} // }
} // }
match eval_block(&state, block, Value::nothing()) { // match eval_block(&state, block, Value::nothing()) {
Ok(v) => v, // Ok(v) => v,
Err(error) => Value::Error { error }, // Err(error) => Value::Error { error },
} // }
}) // })
.into_value_stream(), // .into_value_stream(),
span: call.head, // span: call.head,
}), // }),
Value::Stream { stream, .. } => Ok(Value::Stream { // Value::Stream { stream, .. } => Ok(Value::Stream {
stream: stream // stream: stream
.enumerate() // .enumerate()
.map(move |(idx, x)| { // .map(move |(idx, x)| {
let engine_state = context.engine_state.borrow(); // let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); // let block = 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) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { // if let Some(var_id) = &var.var_id {
if numbered { // if numbered {
state.add_var( // state.add_var(
*var_id, // *var_id,
Value::Record { // Value::Record {
cols: vec!["index".into(), "item".into()], // cols: vec!["index".into(), "item".into()],
vals: vec![ // vals: vec![
Value::Int { // Value::Int {
val: idx as i64, // val: idx as i64,
span, // span,
}, // },
x, // x,
], // ],
span, // span,
}, // },
); // );
} else { // } else {
state.add_var(*var_id, x); // state.add_var(*var_id, x);
} // }
} // }
} // }
match eval_block(&state, block, Value::nothing()) { // match eval_block(&state, block, Value::nothing()) {
Ok(v) => v, // Ok(v) => v,
Err(error) => Value::Error { error }, // Err(error) => Value::Error { error },
} // }
}) // })
.into_value_stream(), // .into_value_stream(),
span: call.head, // span: call.head,
}), // }),
Value::Record { cols, vals, .. } => { // Value::Record { cols, vals, .. } => {
let mut output_cols = vec![]; // let mut output_cols = vec![];
let mut output_vals = vec![]; // let mut output_vals = vec![];
for (col, val) in cols.into_iter().zip(vals.into_iter()) { // for (col, val) in cols.into_iter().zip(vals.into_iter()) {
let engine_state = context.engine_state.borrow(); // let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); // let block = 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) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { // if let Some(var_id) = &var.var_id {
state.add_var( // state.add_var(
*var_id, // *var_id,
Value::Record { // Value::Record {
cols: vec!["column".into(), "value".into()], // cols: vec!["column".into(), "value".into()],
vals: vec![ // vals: vec![
Value::String { // Value::String {
val: col.clone(), // val: col.clone(),
span: call.head, // span: call.head,
}, // },
val, // val,
], // ],
span: call.head, // span: call.head,
}, // },
); // );
} // }
} // }
match eval_block(&state, block, Value::nothing())? { // match eval_block(&state, block, Value::nothing())? {
Value::Record { // Value::Record {
mut cols, mut vals, .. // mut cols, mut vals, ..
} => { // } => {
// TODO check that the lengths match when traversing record // // TODO check that the lengths match when traversing record
output_cols.append(&mut cols); // output_cols.append(&mut cols);
output_vals.append(&mut vals); // output_vals.append(&mut vals);
} // }
x => { // x => {
output_cols.push(col); // output_cols.push(col);
output_vals.push(x); // output_vals.push(x);
} // }
} // }
} // }
Ok(Value::Record { // Ok(Value::Record {
cols: output_cols, // cols: output_cols,
vals: output_vals, // vals: output_vals,
span: call.head, // span: call.head,
}) // })
} // }
x => { // x => {
let engine_state = context.engine_state.borrow(); // let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); // let block = 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) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { // if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x); // state.add_var(*var_id, x);
} // }
} // }
eval_block(&state, block, Value::nothing()) // eval_block(&state, block, Value::nothing())
} // }
} // }
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath}; use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Get; pub struct Get;
impl Command for Get { impl Command for Get {
@ -26,8 +27,8 @@ impl Command for Get {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cell_path: CellPath = call.req(context, 0)?; let cell_path: CellPath = call.req(context, 0)?;
input.follow_cell_path(&cell_path.members) input.follow_cell_path(&cell_path.members)

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, Value}; use nu_protocol::{IntoPipelineData, PipelineData, Signature, Value};
#[derive(Clone)]
pub struct Length; pub struct Length;
impl Command for Length { impl Command for Length {
@ -21,33 +22,19 @@ impl Command for Length {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
match input { match input {
Value::List { vals: val, .. } => { PipelineData::Value(Value::Nothing { .. }) => Ok(Value::Int {
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 {
val: 0, val: 0,
span: call.head, span: call.head,
}), }
.into_pipeline_data()),
_ => Ok(Value::Int { _ => Ok(Value::Int {
val: 1, val: input.count() as i64,
span: call.head, span: call.head,
}), }
.into_pipeline_data()),
} }
} }
} }

View File

@ -3,8 +3,9 @@ use std::rc::Rc;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Lines;
const SPLIT_CHAR: char = '\n'; const SPLIT_CHAR: char = '\n';
@ -26,15 +27,15 @@ impl Command for Lines {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head; let span = call.head;
match input { match input {
#[allow(clippy::needless_collect)] #[allow(clippy::needless_collect)]
// Collect is needed because the string may not live long enough for // Collect is needed because the string may not live long enough for
// the Rc structure to continue using it. If split could take ownership // the Rc structure to continue using it. If split could take ownership
// of the split values, then this wouldn't be needed // of the split values, then this wouldn't be needed
Value::String { val, span } => { PipelineData::Value(Value::String { val, span }) => {
let lines = val let lines = val
.split(SPLIT_CHAR) .split(SPLIT_CHAR)
.map(|s| s.to_string()) .map(|s| s.to_string())
@ -48,12 +49,9 @@ impl Command for Lines {
} }
}); });
Ok(Value::Stream { Ok(iter.into_pipeline_data())
stream: ValueStream(Rc::new(RefCell::new(iter))),
span,
})
} }
Value::Stream { stream, span: _ } => { PipelineData::Stream(stream) => {
let iter = stream let iter = stream
.into_iter() .into_iter()
.filter_map(|value| { .filter_map(|value| {
@ -79,12 +77,9 @@ impl Command for Lines {
}) })
.flatten(); .flatten();
Ok(Value::Stream { Ok(iter.into_pipeline_data())
stream: ValueStream(Rc::new(RefCell::new(iter))),
span,
})
} }
val => Err(ShellError::UnsupportedInput( PipelineData::Value(val) => Err(ShellError::UnsupportedInput(
format!("Not supported input: {}", val.as_string()?), format!("Not supported input: {}", val.as_string()?),
call.head, call.head,
)), )),

View File

@ -1,8 +1,11 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath}; use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Select;
impl Command for Select { impl Command for Select {
@ -26,8 +29,8 @@ impl Command for Select {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let columns: Vec<CellPath> = call.rest(context, 0)?; let columns: Vec<CellPath> = call.rest(context, 0)?;
let span = call.head; let span = call.head;
@ -50,16 +53,20 @@ impl Command for Select {
} }
} }
fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, ShellError> { fn select(
span: Span,
columns: Vec<CellPath>,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
if columns.is_empty() { if columns.is_empty() {
return Err(ShellError::CantFindColumn(span, input.span()?)); return Err(ShellError::CantFindColumn(span, span)); //FIXME?
} }
match input { match input {
Value::List { PipelineData::Value(Value::List {
vals: input_vals, vals: input_vals,
span, span,
} => { }) => {
let mut output = vec![]; let mut output = vec![];
for input_val in input_vals { for input_val in input_vals {
@ -76,33 +83,30 @@ fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, She
output.push(Value::Record { cols, vals, span }) output.push(Value::Record { cols, vals, span })
} }
Ok(Value::List { vals: output, span }) Ok(output.into_iter().into_pipeline_data())
} }
Value::Stream { stream, span } => Ok(Value::Stream { PipelineData::Stream(stream) => Ok(stream
stream: stream .map(move |x| {
.map(move |x| { let mut cols = vec![];
let mut cols = vec![]; let mut vals = vec![];
let mut vals = vec![]; for path in &columns {
for path in &columns { //FIXME: improve implementation to not clone
//FIXME: improve implementation to not clone match x.clone().follow_cell_path(&path.members) {
match x.clone().follow_cell_path(&path.members) { Ok(value) => {
Ok(value) => { cols.push(path.into_string());
cols.push(path.into_string()); vals.push(value);
vals.push(value); }
} Err(error) => {
Err(error) => { cols.push(path.into_string());
cols.push(path.into_string()); vals.push(Value::Error { error });
vals.push(Value::Error { error });
}
} }
} }
}
Value::Record { cols, vals, span } Value::Record { cols, vals, span }
}) })
.into_value_stream(), .into_pipeline_data()),
span, PipelineData::Value(v) => {
}),
v => {
let mut cols = vec![]; let mut cols = vec![];
let mut vals = vec![]; let mut vals = vec![];
@ -114,7 +118,7 @@ fn select(span: Span, columns: Vec<CellPath>, input: Value) -> Result<Value, She
vals.push(result); vals.push(result);
} }
Ok(Value::Record { cols, vals, span }) Ok(Value::Record { cols, vals, span }.into_pipeline_data())
} }
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{IntoValueStream, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Where; pub struct Where;
impl Command for Where { impl Command for Where {
@ -22,8 +23,8 @@ impl Command for Where {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = call.positional[0].clone(); let cond = call.positional[0].clone();
let context = context.enter_scope(); let context = context.enter_scope();
@ -37,54 +38,40 @@ impl Command for Where {
}; };
match input { match input {
Value::Stream { stream, span } => { PipelineData::Stream(stream) => Ok(stream
let output_stream = stream .filter(move |value| {
.filter(move |value| { context.add_var(var_id, value.clone());
context.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond); let result = eval_expression(&context, &cond);
match result { match result {
Ok(result) => result.is_true(), Ok(result) => result.is_true(),
_ => false, _ => false,
} }
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
}) })
} .into_pipeline_data()),
Value::List { vals, span } => { PipelineData::Value(Value::List { vals, span }) => Ok(vals
let output_stream = vals .into_iter()
.into_iter() .filter(move |value| {
.filter(move |value| { context.add_var(var_id, value.clone());
context.add_var(var_id, value.clone());
let result = eval_expression(&context, &cond); let result = eval_expression(&context, &cond);
match result { match result {
Ok(result) => result.is_true(), Ok(result) => result.is_true(),
_ => false, _ => false,
} }
})
.into_value_stream();
Ok(Value::Stream {
stream: output_stream,
span,
}) })
} .into_pipeline_data()),
x => { PipelineData::Value(x) => {
context.add_var(var_id, x.clone()); context.add_var(var_id, x.clone());
let result = eval_expression(&context, &cond)?; let result = eval_expression(&context, &cond)?;
if result.is_true() { if result.is_true() {
Ok(x) Ok(x.into_pipeline_data())
} else { } else {
Ok(Value::Nothing { span: call.head }) Ok(PipelineData::new())
} }
} }
} }

View File

@ -1,8 +1,9 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Wrap;
impl Command for Wrap { impl Command for Wrap {
@ -22,38 +23,33 @@ impl Command for Wrap {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head; let span = call.head;
let name: String = call.req(context, 0)?; let name: String = call.req(context, 0)?;
match input { match input {
Value::List { vals, .. } => Ok(Value::List { PipelineData::Value(Value::List { vals, .. }) => Ok(vals
vals: vals .into_iter()
.into_iter() .map(move |x| Value::Record {
.map(move |x| Value::Record { cols: vec![name.clone()],
cols: vec![name.clone()], vals: vec![x],
vals: vec![x], span,
span, })
}) .into_pipeline_data()),
.collect(), PipelineData::Stream(stream) => Ok(stream
span, .map(move |x| Value::Record {
}), cols: vec![name.clone()],
Value::Stream { stream, .. } => Ok(Value::Stream { vals: vec![x],
stream: stream span,
.map(move |x| Value::Record { })
cols: vec![name.clone()], .into_pipeline_data()),
vals: vec![x], PipelineData::Value(input) => Ok(Value::Record {
span,
})
.into_value_stream(),
span,
}),
_ => Ok(Value::Record {
cols: vec![name], cols: vec![name],
vals: vec![input], vals: vec![input],
span, span,
}), }
.into_pipeline_data()),
} }
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{ShellError, Signature, Value}; use nu_protocol::{PipelineData, ShellError, Signature, Value};
#[derive(Clone)]
pub struct From; pub struct From;
impl Command for From { impl Command for From {
@ -21,8 +22,8 @@ impl Command for From {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
_call: &Call, _call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, ShellError> { ) -> Result<nu_protocol::PipelineData, ShellError> {
Ok(Value::nothing()) Ok(PipelineData::new())
} }
} }

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct FromJson;
impl Command for FromJson { impl Command for FromJson {
@ -69,8 +70,8 @@ impl Command for FromJson {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, ShellError> { ) -> Result<nu_protocol::PipelineData, ShellError> {
let span = input.span()?; let span = input.span()?;
let mut string_input = input.collect_string(); let mut string_input = input.collect_string();
string_input.push('\n'); string_input.push('\n');
@ -79,21 +80,18 @@ impl Command for FromJson {
if call.has_flag("objects") { if call.has_flag("objects") {
#[allow(clippy::needless_collect)] #[allow(clippy::needless_collect)]
let lines: Vec<String> = string_input.lines().map(|x| x.to_string()).collect(); let lines: Vec<String> = string_input.lines().map(|x| x.to_string()).collect();
Ok(Value::Stream { Ok(lines
stream: lines .into_iter()
.into_iter() .map(move |mut x| {
.map(move |mut x| { x.push('\n');
x.push('\n'); match convert_string_to_value(x, span) {
match convert_string_to_value(x, span) { Ok(v) => v,
Ok(v) => v, Err(error) => Value::Error { error },
Err(error) => Value::Error { error }, }
} })
}) .into_pipeline_data())
.into_value_stream(),
span,
})
} else { } else {
convert_string_to_value(string_input, span) Ok(convert_string_to_value(string_input, span)?.into_pipeline_data())
} }
} }
} }

View File

@ -1,8 +1,11 @@
use nu_engine::eval_expression; use nu_engine::eval_expression;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct BuildString;
impl Command for BuildString { impl Command for BuildString {
@ -43,8 +46,8 @@ impl Command for BuildString {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let output = call let output = call
.positional .positional
.iter() .iter()
@ -54,7 +57,8 @@ impl Command for BuildString {
Ok(Value::String { Ok(Value::String {
val: output.join(""), val: output.join(""),
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} }
} }

View File

@ -4,8 +4,11 @@ use unicode_segmentation::UnicodeSegmentation;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; 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; pub struct Size;
impl Command for Size { impl Command for Size {
@ -25,8 +28,8 @@ impl Command for Size {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
size(context, call, input) size(context, call, input)
} }
@ -98,18 +101,24 @@ impl Command for Size {
} }
} }
fn size(_context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> { fn size(
_context: &EvaluationContext,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
input.map(span, move |v| match v.as_string() { Ok(input
Ok(s) => count(&s, span), .map(move |v| match v.as_string() {
Err(_) => Value::Error { Ok(s) => count(&s, span),
error: ShellError::PipelineMismatch { Err(_) => Value::Error {
expected: Type::String, error: ShellError::PipelineMismatch {
expected_span: span, expected: Type::String,
origin: span, expected_span: span,
origin: span,
},
}, },
}, })
}) .into_pipeline_data())
} }
fn count(contents: &str, span: Span) -> Value { fn count(contents: &str, span: Span) -> Value {

View File

@ -1,9 +1,10 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, Type, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -40,16 +41,21 @@ impl Command for SubCommand {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_chars(call, input) split_chars(call, input)
} }
} }
fn split_chars(call: &Call, input: Value) -> Result<nu_protocol::Value, nu_protocol::ShellError> { fn split_chars(
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let span = call.head; 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<Value> { fn split_chars_helper(v: &Value, name: Span) -> Vec<Value> {

View File

@ -2,9 +2,10 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -35,8 +36,8 @@ impl Command for SubCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_column(context, call, input) split_column(context, call, input)
} }
} }
@ -44,16 +45,16 @@ impl Command for SubCommand {
fn split_column( fn split_column(
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let name_span = call.head; let name_span = call.head;
let separator: Spanned<String> = call.req(context, 0)?; let separator: Spanned<String> = call.req(context, 0)?;
let rest: Vec<Spanned<String>> = call.rest(context, 1)?; let rest: Vec<Spanned<String>> = call.rest(context, 1)?;
let collapse_empty = call.has_flag("collapse-empty"); let collapse_empty = call.has_flag("collapse-empty");
input.map(name_span, move |x| { Ok(input
split_column_helper(&x, &separator, &rest, collapse_empty, name_span) .map(move |x| split_column_helper(&x, &separator, &rest, collapse_empty, name_span))
}) .into_pipeline_data())
} }
fn split_column_helper( fn split_column_helper(

View File

@ -2,7 +2,7 @@ use nu_engine::get_full_help;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Signature, Value, IntoPipelineData, PipelineData, Signature, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -25,12 +25,13 @@ impl Command for SplitCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(Value::String { Ok(Value::String {
val: get_full_help(&SplitCommand.signature(), &SplitCommand.examples(), context), val: get_full_help(&SplitCommand.signature(), &SplitCommand.examples(), context),
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} }
} }

View File

@ -2,9 +2,10 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
impl Command for SubCommand { impl Command for SubCommand {
@ -28,8 +29,8 @@ impl Command for SubCommand {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
split_row(context, call, input) split_row(context, call, input)
} }
} }
@ -37,14 +38,14 @@ impl Command for SubCommand {
fn split_row( fn split_row(
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let name_span = call.head; let name_span = call.head;
let separator: Spanned<String> = call.req(context, 0)?; let separator: Spanned<String> = call.req(context, 0)?;
Ok(input.flat_map(name_span, move |x| { Ok(input
split_row_helper(&x, &separator, name_span) .flat_map(move |x| split_row_helper(&x, &separator, name_span))
})) .into_pipeline_data())
} }
fn split_row_helper(v: &Value, separator: &Spanned<String>, name: Span) -> Vec<Value> { fn split_row_helper(v: &Value, separator: &Spanned<String>, name: Span) -> Vec<Value> {

View File

@ -3,8 +3,9 @@ use std::time::Instant;
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext}; use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
pub struct Benchmark; pub struct Benchmark;
impl Command for Benchmark { impl Command for Benchmark {
@ -28,21 +29,18 @@ impl Command for Benchmark {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block = call.positional[0] let block = call.positional[0]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
let engine_state = context.engine_state.borrow(); let block = context.engine_state.get_block(block);
let block = engine_state.get_block(block);
let state = context.enter_scope(); let state = context.enter_scope();
let start_time = Instant::now(); let start_time = Instant::now();
eval_block(&state, block, Value::nothing())?; eval_block(&state, block, PipelineData::new())?;
let end_time = Instant::now(); let end_time = Instant::now();
println!("{} ms", (end_time - start_time).as_millis()); println!("{} ms", (end_time - start_time).as_millis());
Ok(Value::Nothing { Ok(PipelineData::new())
span: call.positional[0].span,
})
} }
} }

View File

@ -1,10 +1,11 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, ShellError, Signature, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
}; };
use sysinfo::{ProcessExt, System, SystemExt}; use sysinfo::{ProcessExt, System, SystemExt};
#[derive(Clone)]
pub struct Ps; pub struct Ps;
impl Command for Ps { impl Command for Ps {
@ -31,8 +32,8 @@ impl Command for Ps {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_ps(call) run_ps(call)
} }
@ -45,7 +46,7 @@ impl Command for Ps {
} }
} }
fn run_ps(call: &Call) -> Result<Value, ShellError> { fn run_ps(call: &Call) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let long = call.has_flag("long"); let long = call.has_flag("long");
let mut sys = System::new_all(); let mut sys = System::new_all();
@ -124,5 +125,5 @@ fn run_ps(call: &Call) -> Result<Value, ShellError> {
} }
} }
Ok(Value::List { vals: output, span }) Ok(output.into_iter().into_pipeline_data())
} }

View File

@ -11,12 +11,13 @@ use nu_protocol::{
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
ShellError, Signature, SyntaxShape, Value, ShellError, Signature, SyntaxShape, Value,
}; };
use nu_protocol::{Span, ValueStream}; use nu_protocol::{IntoPipelineData, PipelineData, Span, ValueStream};
use nu_engine::eval_expression; use nu_engine::eval_expression;
const OUTPUT_BUFFER_SIZE: usize = 8192; const OUTPUT_BUFFER_SIZE: usize = 8192;
#[derive(Clone)]
pub struct External; pub struct External;
impl Command for External { impl Command for External {
@ -38,8 +39,8 @@ impl Command for External {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
let command = ExternalCommand::try_new(call, context)?; let command = ExternalCommand::try_new(call, context)?;
command.run_with_input(input) command.run_with_input(input)
} }
@ -82,7 +83,7 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
.collect() .collect()
} }
pub fn run_with_input(&self, input: Value) -> Result<Value, ShellError> { pub fn run_with_input(&self, input: PipelineData) -> Result<PipelineData, ShellError> {
let mut process = self.create_command(); let mut process = self.create_command();
// TODO. We don't have a way to know the current directory // 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 // 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 // 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()); process.stdin(Stdio::piped());
} }
if let Value::Stream { .. } = input { if let PipelineData::Stream { .. } = input {
process.stdin(Stdio::piped()); process.stdin(Stdio::piped());
} }
@ -116,33 +117,18 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> {
)), )),
Ok(mut child) => { Ok(mut child) => {
// if there is a string or a stream, that is sent to the pipe std // if there is a string or a stream, that is sent to the pipe std
match input { if let Some(mut stdin_write) = child.stdin.take() {
Value::String { val, span: _ } => { for value in input {
if let Some(mut stdin_write) = child.stdin.take() { match value {
self.write_to_stdin(&mut stdin_write, val.as_bytes())? Value::String { val, span: _ } => {
} 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,
}
} }
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 // 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 // The ValueStream is consumed by the next expression in the pipeline
Value::Stream { ChannelReceiver::new(rx).into_pipeline_data()
stream: ValueStream(Rc::new(RefCell::new(ChannelReceiver::new(rx)))),
span: Span::unknown(),
}
} else { } else {
Value::nothing() PipelineData::new()
}; };
match child.wait() { match child.wait() {

View File

@ -1,10 +1,11 @@
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EvaluationContext}, engine::{Command, EvaluationContext},
Example, ShellError, Signature, Span, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
}; };
use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt}; use sysinfo::{ComponentExt, DiskExt, NetworkExt, ProcessorExt, System, SystemExt, UserExt};
#[derive(Clone)]
pub struct Sys; pub struct Sys;
impl Command for Sys { impl Command for Sys {
@ -26,8 +27,8 @@ impl Command for Sys {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
call: &Call, call: &Call,
_input: Value, _input: PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
run_sys(call) run_sys(call)
} }
@ -40,7 +41,7 @@ impl Command for Sys {
} }
} }
fn run_sys(call: &Call) -> Result<Value, ShellError> { fn run_sys(call: &Call) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let mut sys = System::new(); let mut sys = System::new();
@ -76,7 +77,8 @@ fn run_sys(call: &Call) -> Result<Value, ShellError> {
cols: headers, cols: headers,
vals: values, vals: values,
span, span,
}) }
.into_pipeline_data())
} }
pub fn trim_cstyle_null(s: String) -> String { pub fn trim_cstyle_null(s: String) -> String {

View File

@ -8,6 +8,7 @@ use nu_protocol::{
use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions}; use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
use terminal_size::{Height, Width}; use terminal_size::{Height, Width};
#[derive(Clone)]
pub struct Griddle; pub struct Griddle;
impl Command for Griddle { impl Command for Griddle {

View File

@ -5,6 +5,7 @@ use nu_table::StyledString;
use std::collections::HashMap; use std::collections::HashMap;
use terminal_size::{Height, Width}; use terminal_size::{Height, Width};
#[derive(Clone)]
pub struct Table; 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. //NOTE: this is not a real implementation :D. It's just a simple one to test with until we port the real one.

View File

@ -26,11 +26,10 @@ fn generate_doc(name: &str, context: &EvaluationContext) -> (Vec<String>, Vec<Va
let mut cols = vec![]; let mut cols = vec![];
let mut vals = vec![]; let mut vals = vec![];
let engine_state = context.engine_state.borrow(); let command = context
.engine_state
let command = engine_state
.find_decl(name.as_bytes()) .find_decl(name.as_bytes())
.map(|decl_id| engine_state.get_decl(decl_id)) .map(|decl_id| context.engine_state.get_decl(decl_id))
.unwrap_or_else(|| panic!("Expected command '{}' from names to be in registry", name)); .unwrap_or_else(|| panic!("Expected command '{}' from names to be in registry", name));
cols.push("name".to_string()); cols.push("name".to_string());

View File

@ -1,6 +1,8 @@
use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement}; use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement};
use nu_protocol::engine::EvaluationContext; use nu_protocol::engine::EvaluationContext;
use nu_protocol::{Range, ShellError, Span, Spanned, Type, Unit, Value}; use nu_protocol::{
IntoPipelineData, PipelineData, Range, ShellError, Span, Spanned, Type, Unit, Value,
};
use crate::get_full_help; use crate::get_full_help;
@ -16,17 +18,21 @@ pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
} }
} }
fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result<Value, ShellError> { fn eval_call(
let engine_state = context.engine_state.borrow(); context: &EvaluationContext,
let decl = engine_state.get_decl(call.decl_id); call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let decl = context.engine_state.get_decl(call.decl_id);
if call.named.iter().any(|(flag, _)| flag.item == "help") { if call.named.iter().any(|(flag, _)| flag.item == "help") {
let full_help = get_full_help(&decl.signature(), &decl.examples(), context); let full_help = get_full_help(&decl.signature(), &decl.examples(), context);
Ok(Value::String { Ok(Value::String {
val: full_help, val: full_help,
span: call.head, span: call.head,
}) }
.into_pipeline_data())
} else if let Some(block_id) = decl.get_block_id() { } 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( for (arg, param) in call.positional.iter().zip(
decl.signature() decl.signature()
.required_positional .required_positional
@ -102,8 +108,7 @@ fn eval_call(context: &EvaluationContext, call: &Call, input: Value) -> Result<V
} }
} }
} }
let engine_state = state.engine_state.borrow(); let block = context.engine_state.get_block(block_id);
let block = engine_state.get_block(block_id);
eval_block(&state, block, input) eval_block(&state, block, input)
} else { } else {
decl.run(context, call, input) decl.run(context, call, input)
@ -115,16 +120,15 @@ fn eval_external(
name: &str, name: &str,
name_span: &Span, name_span: &Span,
args: &[Expression], args: &[Expression],
input: Value, input: PipelineData,
last_expression: bool, last_expression: bool,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
let engine_state = context.engine_state.borrow(); let decl_id = context
.engine_state
let decl_id = engine_state
.find_decl("run_external".as_bytes()) .find_decl("run_external".as_bytes())
.ok_or_else(|| ShellError::ExternalNotSupported(*name_span))?; .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(); let mut call = Call::new();
@ -216,9 +220,20 @@ pub fn eval_expression(
value.follow_cell_path(&cell_path.tail) value.follow_cell_path(&cell_path.tail)
} }
Expr::RowCondition(_, expr) => eval_expression(context, expr), 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) => { 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::Operator(_) => Ok(Value::Nothing { span: expr.span }),
Expr::BinaryOp(lhs, op, rhs) => { Expr::BinaryOp(lhs, op, rhs) => {
@ -249,11 +264,15 @@ pub fn eval_expression(
} }
} }
Expr::Subexpression(block_id) => { Expr::Subexpression(block_id) => {
let engine_state = context.engine_state.borrow(); let block = context.engine_state.get_block(*block_id);
let block = engine_state.get_block(*block_id);
let state = context.enter_scope(); 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 { Expr::Block(block_id) => Ok(Value::Block {
val: *block_id, val: *block_id,
@ -313,8 +332,8 @@ pub fn eval_expression(
pub fn eval_block( pub fn eval_block(
context: &EvaluationContext, context: &EvaluationContext,
block: &Block, block: &Block,
mut input: Value, mut input: PipelineData,
) -> Result<Value, ShellError> { ) -> Result<PipelineData, ShellError> {
for stmt in block.stmts.iter() { for stmt in block.stmts.iter() {
if let Statement::Pipeline(pipeline) = stmt { if let Statement::Pipeline(pipeline) = stmt {
for (i, elem) in pipeline.expressions.iter().enumerate() { for (i, elem) in pipeline.expressions.iter().enumerate() {
@ -340,7 +359,7 @@ pub fn eval_block(
} }
elem => { elem => {
input = eval_expression(context, elem)?; input = eval_expression(context, elem)?.into_pipeline_data();
} }
} }
} }

View File

@ -7,6 +7,7 @@ use nu_protocol::{
}; };
#[cfg(test)] #[cfg(test)]
#[derive(Clone)]
pub struct Let; pub struct Let;
#[cfg(test)] #[cfg(test)]
@ -33,8 +34,8 @@ impl Command for Let {
&self, &self,
_context: &nu_protocol::engine::EvaluationContext, _context: &nu_protocol::engine::EvaluationContext,
_call: &nu_protocol::ast::Call, _call: &nu_protocol::ast::Call,
_input: nu_protocol::Value, _input: nu_protocol::PipelineData,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
todo!() todo!()
} }
} }

View File

@ -11,4 +11,5 @@ miette = "3.0.0"
serde = {version = "1.0.130", features = ["derive"]} serde = {version = "1.0.130", features = ["derive"]}
chrono = { version="0.4.19", features=["serde"] } chrono = { version="0.4.19", features=["serde"] }
chrono-humanize = "0.2.1" chrono-humanize = "0.2.1"
byte-unit = "4.0.9" byte-unit = "4.0.9"
im = "15.0.0"

View File

@ -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; use super::EvaluationContext;
pub trait Command: Send + Sync { pub trait Command: Send + Sync + CommandClone {
fn name(&self) -> &str; fn name(&self) -> &str;
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
@ -19,8 +19,8 @@ pub trait Command: Send + Sync {
&self, &self,
context: &EvaluationContext, context: &EvaluationContext,
call: &Call, call: &Call,
input: Value, input: PipelineData,
) -> Result<Value, ShellError>; ) -> Result<PipelineData, ShellError>;
fn is_binary(&self) -> bool { fn is_binary(&self) -> bool {
false false
@ -55,3 +55,22 @@ pub trait Command: Send + Sync {
None None
} }
} }
pub trait CommandClone {
fn clone_box(&self) -> Box<dyn Command>;
}
impl<T> CommandClone for T
where
T: 'static + Command + Clone,
{
fn clone_box(&self) -> Box<dyn Command> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Command> {
fn clone(&self) -> Box<dyn Command> {
self.clone_box()
}
}

View File

@ -3,13 +3,14 @@ use crate::{ast::Block, BlockId, DeclId, Example, Signature, Span, Type, VarId};
use core::panic; use core::panic;
use std::{collections::HashMap, slice::Iter}; use std::{collections::HashMap, slice::Iter};
#[derive(Clone)]
pub struct EngineState { pub struct EngineState {
files: Vec<(String, usize, usize)>, files: im::Vector<(String, usize, usize)>,
file_contents: Vec<u8>, file_contents: im::Vector<(Vec<u8>, usize, usize)>,
vars: Vec<Type>, vars: im::Vector<Type>,
decls: Vec<Box<dyn Command>>, decls: im::Vector<Box<dyn Command + 'static>>,
blocks: Vec<Block>, blocks: im::Vector<Block>,
pub scope: Vec<ScopeFrame>, pub scope: im::Vector<ScopeFrame>,
} }
// Tells whether a decl etc. is visible or not // Tells whether a decl etc. is visible or not
@ -53,7 +54,7 @@ impl Visibility {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ScopeFrame { pub struct ScopeFrame {
pub vars: HashMap<Vec<u8>, VarId>, pub vars: HashMap<Vec<u8>, VarId>,
predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
@ -95,12 +96,12 @@ impl Default for EngineState {
impl EngineState { impl EngineState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
files: vec![], files: im::vector![],
file_contents: vec![], file_contents: im::vector![],
vars: vec![], vars: im::vector![],
decls: vec![], decls: im::vector![],
blocks: vec![], blocks: im::vector![],
scope: vec![ScopeFrame::new()], scope: im::vector![ScopeFrame::new()],
} }
} }
@ -112,7 +113,7 @@ impl EngineState {
this.vars.extend(delta.vars); this.vars.extend(delta.vars);
this.blocks.extend(delta.blocks); 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); let first = delta.scope.remove(0);
for item in first.decls.into_iter() { for item in first.decls.into_iter() {
last.decls.insert(item.0, item.1); last.decls.insert(item.0, item.1);
@ -165,8 +166,10 @@ impl EngineState {
} }
pub fn print_contents(&self) { pub fn print_contents(&self) {
let string = String::from_utf8_lossy(&self.file_contents); for (contents, _, _) in self.file_contents.iter() {
println!("{}", string); let string = String::from_utf8_lossy(&contents);
println!("{}", string);
}
} }
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> { pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
@ -200,7 +203,13 @@ impl EngineState {
} }
pub fn get_span_contents(&self, span: &Span) -> &[u8] { 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 { pub fn get_var(&self, var_id: VarId) -> &Type {
@ -256,7 +265,7 @@ impl EngineState {
self.file_contents.len() self.file_contents.len()
} }
pub fn files(&self) -> Iter<(String, usize, usize)> { pub fn files(&self) -> impl Iterator<Item = &(String, usize, usize)> {
self.files.iter() self.files.iter()
} }
@ -273,8 +282,11 @@ impl EngineState {
pub fn get_file_source(&self, file_id: usize) -> String { pub fn get_file_source(&self, file_id: usize) -> String {
for file in self.files.iter().enumerate() { for file in self.files.iter().enumerate() {
if file.0 == file_id { if file.0 == file_id {
let output = let contents = self.get_span_contents(&Span {
String::from_utf8_lossy(&self.file_contents[file.1 .1..file.1 .2]).to_string(); start: file.1 .1,
end: file.1 .2,
});
let output = String::from_utf8_lossy(contents).to_string();
return output; return output;
} }
@ -286,12 +298,13 @@ impl EngineState {
#[allow(unused)] #[allow(unused)]
pub(crate) fn add_file(&mut self, filename: String, contents: Vec<u8>) -> usize { pub(crate) fn add_file(&mut self, filename: String, contents: Vec<u8>) -> usize {
let next_span_start = self.next_span_start(); 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_back((filename, next_span_start, next_span_end));
self.files.push((filename, next_span_start, next_span_end));
self.num_files() - 1 self.num_files() - 1
} }
@ -304,7 +317,7 @@ pub struct StateWorkingSet<'a> {
pub struct StateDelta { pub struct StateDelta {
files: Vec<(String, usize, usize)>, files: Vec<(String, usize, usize)>,
pub(crate) file_contents: Vec<u8>, pub(crate) file_contents: Vec<(Vec<u8>, usize, usize)>,
vars: Vec<Type>, // indexed by VarId vars: Vec<Type>, // indexed by VarId
decls: Vec<Box<dyn Command>>, // indexed by DeclId decls: Vec<Box<dyn Command>>, // indexed by DeclId
blocks: Vec<Block>, // indexed by BlockId blocks: Vec<Block>, // indexed by BlockId
@ -520,10 +533,11 @@ impl<'a> StateWorkingSet<'a> {
pub fn add_file(&mut self, filename: String, contents: &[u8]) -> usize { pub fn add_file(&mut self, filename: String, contents: &[u8]) -> usize {
let next_span_start = self.next_span_start(); let next_span_start = self.next_span_start();
let next_span_end = next_span_start + contents.len();
self.delta.file_contents.extend(contents); self.delta
.file_contents
let next_span_end = self.next_span_start(); .push((contents.to_vec(), next_span_start, next_span_end));
self.delta self.delta
.files .files
@ -535,10 +549,16 @@ impl<'a> StateWorkingSet<'a> {
pub fn get_span_contents(&self, span: Span) -> &[u8] { pub fn get_span_contents(&self, span: Span) -> &[u8] {
let permanent_end = self.permanent_state.next_span_start(); let permanent_end = self.permanent_state.next_span_start();
if permanent_end <= 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 { } 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) { pub fn enter_scope(&mut self) {

View File

@ -5,7 +5,7 @@ use crate::{Example, ShellError, Signature, Value, VarId};
#[derive(Clone)] #[derive(Clone)]
pub struct EvaluationContext { pub struct EvaluationContext {
pub engine_state: Rc<RefCell<EngineState>>, pub engine_state: Box<EngineState>,
pub stack: Stack, pub stack: Stack,
} }
@ -21,25 +21,11 @@ impl EvaluationContext {
} }
} }
pub fn add_var(&self, var_id: VarId, value: Value) { pub fn add_var(&mut 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,
};
self.stack.add_var(var_id, 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); self.stack.add_env_var(var, value);
} }
@ -48,23 +34,22 @@ impl EvaluationContext {
} }
pub fn get_signatures(&self) -> Vec<Signature> { pub fn get_signatures(&self) -> Vec<Signature> {
self.engine_state.borrow().get_signatures() self.engine_state.get_signatures()
} }
pub fn get_signatures_with_examples(&self) -> Vec<(Signature, Vec<Example>)> { pub fn get_signatures_with_examples(&self) -> Vec<(Signature, Vec<Example>)> {
self.engine_state.borrow().get_signatures_with_examples() self.engine_state.get_signatures_with_examples()
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct StackFrame { pub struct StackFrame {
pub vars: HashMap<VarId, Value>, pub vars: HashMap<VarId, Value>,
pub env_vars: HashMap<String, String>, pub env_vars: HashMap<String, String>,
pub parent: Option<Stack>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Stack(Rc<RefCell<StackFrame>>); pub struct Stack(Vec<StackFrame>);
impl Default for Stack { impl Default for Stack {
fn default() -> Self { fn default() -> Self {
@ -74,64 +59,77 @@ impl Default for Stack {
impl Stack { impl Stack {
pub fn new() -> Stack { pub fn new() -> Stack {
Stack(Rc::new(RefCell::new(StackFrame { Stack(vec![StackFrame {
vars: HashMap::new(), vars: HashMap::new(),
env_vars: HashMap::new(), env_vars: HashMap::new(),
parent: None, }])
})))
} }
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> { pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
let this = self.0.borrow(); for frame in self.0.iter().rev() {
match this.vars.get(&var_id) { if let Some(v) = frame.vars.get(&var_id) {
Some(v) => Ok(v.clone()), return Ok(v.clone());
_ => {
if let Some(parent) = &this.parent {
parent.get_var(var_id)
} else {
Err(ShellError::InternalError("variable not found".into()))
}
} }
} }
Err(ShellError::InternalError("variable not found".into()))
} }
pub fn add_var(&self, var_id: VarId, value: Value) { pub fn add_var(&mut self, var_id: VarId, value: Value) {
let mut this = self.0.borrow_mut(); let frame = self
this.vars.insert(var_id, value); .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) { pub fn add_env_var(&mut self, var: String, value: String) {
let mut this = self.0.borrow_mut(); let frame = self
this.env_vars.insert(var, value); .0
.last_mut()
.expect("internal error: can't access stack frame");
frame.env_vars.insert(var, value);
} }
pub fn enter_scope(self) -> Stack { pub fn enter_scope(&self) -> Stack {
Stack(Rc::new(RefCell::new(StackFrame { // FIXME: VERY EXPENSIVE to clone entire stack
let mut output = self.clone();
output.0.push(StackFrame {
vars: HashMap::new(), vars: HashMap::new(),
env_vars: HashMap::new(), env_vars: HashMap::new(),
parent: Some(self), });
})))
output
} }
pub fn get_env_vars(&self) -> HashMap<String, String> { pub fn get_env_vars(&self) -> HashMap<String, String> {
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<String> { pub fn get_env_var(&self, name: &str) -> Option<String> {
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) { pub fn print_stack(&self) {
println!("===frame==="); for frame in self.0.iter().rev() {
println!("vars:"); println!("===frame===");
for (var, val) in &self.0.borrow().vars { println!("vars:");
println!(" {}: {:?}", var, val); for (var, val) in &frame.vars {
} println!(" {}: {:?}", var, val);
println!("env vars:"); }
for (var, val) in &self.0.borrow().env_vars { println!("env vars:");
println!(" {}: {:?}", var, val); for (var, val) in &frame.env_vars {
} println!(" {}: {:?}", var, val);
if let Some(parent) = &self.0.borrow().parent { }
parent.print_stack()
} }
} }
} }

View File

@ -2,6 +2,7 @@ pub mod ast;
pub mod engine; pub mod engine;
mod example; mod example;
mod id; mod id;
mod pipeline_data;
mod shell_error; mod shell_error;
mod signature; mod signature;
mod span; mod span;
@ -12,6 +13,7 @@ pub use value::Value;
pub use example::*; pub use example::*;
pub use id::*; pub use id::*;
pub use pipeline_data::*;
pub use shell_error::*; pub use shell_error::*;
pub use signature::*; pub use signature::*;
pub use span::*; pub use span::*;

View File

@ -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<Self::Item> {
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<T> IntoPipelineData for T
where
T: Iterator<Item = Value> + Send + 'static,
{
fn into_pipeline_data(self) -> PipelineData {
PipelineData::Stream(ValueStream(Box::new(self)))
}
}

View File

@ -1,7 +1,9 @@
use crate::ast::Call; use crate::ast::Call;
use crate::engine::Command; use crate::engine::Command;
use crate::engine::CommandClone;
use crate::engine::EvaluationContext; use crate::engine::EvaluationContext;
use crate::BlockId; use crate::BlockId;
use crate::PipelineData;
use crate::SyntaxShape; use crate::SyntaxShape;
use crate::Value; use crate::Value;
use crate::VarId; use crate::VarId;
@ -335,6 +337,7 @@ impl Signature {
} }
} }
#[derive(Clone)]
struct Predeclaration { struct Predeclaration {
signature: Signature, signature: Signature,
} }
@ -356,12 +359,13 @@ impl Command for Predeclaration {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
_call: &Call, _call: &Call,
_input: Value, _input: PipelineData,
) -> Result<crate::Value, crate::ShellError> { ) -> Result<PipelineData, crate::ShellError> {
panic!("Internal error: can't run a predeclaration without a body") panic!("Internal error: can't run a predeclaration without a body")
} }
} }
#[derive(Clone)]
struct BlockCommand { struct BlockCommand {
signature: Signature, signature: Signature,
block_id: BlockId, block_id: BlockId,
@ -384,8 +388,8 @@ impl Command for BlockCommand {
&self, &self,
_context: &EvaluationContext, _context: &EvaluationContext,
_call: &Call, _call: &Call,
_input: Value, _input: PipelineData,
) -> Result<crate::Value, crate::ShellError> { ) -> Result<crate::PipelineData, crate::ShellError> {
panic!("Internal error: can't run custom command with 'run', use block_id"); panic!("Internal error: can't run custom command with 'run', use block_id");
} }

View File

@ -59,10 +59,6 @@ pub enum Value {
vals: Vec<Value>, vals: Vec<Value>,
span: Span, span: Span,
}, },
Stream {
stream: ValueStream,
span: Span,
},
List { List {
vals: Vec<Value>, vals: Vec<Value>,
span: Span, span: Span,
@ -110,7 +106,6 @@ impl Value {
Value::Record { span, .. } => Ok(*span), Value::Record { span, .. } => Ok(*span),
Value::List { span, .. } => Ok(*span), Value::List { span, .. } => Ok(*span),
Value::Block { span, .. } => Ok(*span), Value::Block { span, .. } => Ok(*span),
Value::Stream { span, .. } => Ok(*span),
Value::Nothing { span, .. } => Ok(*span), Value::Nothing { span, .. } => Ok(*span),
Value::Binary { span, .. } => Ok(*span), Value::Binary { span, .. } => Ok(*span),
Value::CellPath { span, .. } => Ok(*span), Value::CellPath { span, .. } => Ok(*span),
@ -129,7 +124,6 @@ impl Value {
Value::Range { span, .. } => *span = new_span, Value::Range { span, .. } => *span = new_span,
Value::String { span, .. } => *span = new_span, Value::String { span, .. } => *span = new_span,
Value::Record { span, .. } => *span = new_span, Value::Record { span, .. } => *span = new_span,
Value::Stream { span, .. } => *span = new_span,
Value::List { span, .. } => *span = new_span, Value::List { span, .. } => *span = new_span,
Value::Block { span, .. } => *span = new_span, Value::Block { span, .. } => *span = new_span,
Value::Nothing { 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::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME
Value::Nothing { .. } => Type::Nothing, Value::Nothing { .. } => Type::Nothing,
Value::Block { .. } => Type::Block, Value::Block { .. } => Type::Block,
Value::Stream { .. } => Type::ValueStream,
Value::Error { .. } => Type::Error, Value::Error { .. } => Type::Error,
Value::Binary { .. } => Type::Binary, Value::Binary { .. } => Type::Binary,
Value::CellPath { .. } => Type::CellPath, Value::CellPath { .. } => Type::CellPath,
@ -186,7 +179,6 @@ impl Value {
Err(error) => format!("{:?}", error), Err(error) => format!("{:?}", error),
}, },
Value::String { val, .. } => val, Value::String { val, .. } => val,
Value::Stream { stream, .. } => stream.into_string(),
Value::List { vals: val, .. } => format!( Value::List { vals: val, .. } => format!(
"[{}]", "[{}]",
val.into_iter() val.into_iter()
@ -228,7 +220,6 @@ impl Value {
} }
}, },
Value::String { val, .. } => val, Value::String { val, .. } => val,
Value::Stream { stream, .. } => stream.collect_string(),
Value::List { vals: val, .. } => val Value::List { vals: val, .. } => val
.into_iter() .into_iter()
.map(|x| x.collect_string()) .map(|x| x.collect_string())
@ -274,13 +265,6 @@ impl Value {
return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span)); 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 => { x => {
return Err(ShellError::IncompatiblePathAccess( return Err(ShellError::IncompatiblePathAccess(
format!("{}", x.get_type()), format!("{}", x.get_type()),
@ -329,27 +313,6 @@ impl Value {
span: *span, 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 => { x => {
return Err(ShellError::IncompatiblePathAccess( return Err(ShellError::IncompatiblePathAccess(
format!("{}", x.get_type()), format!("{}", x.get_type()),
@ -374,64 +337,6 @@ impl Value {
} }
} }
pub fn map<F>(self, span: Span, mut f: F) -> Result<Value, ShellError>
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<U, F>(self, span: Span, mut f: F) -> Value
where
Self: Sized,
U: IntoIterator<Item = Value>,
<U as 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<String>, span: Span) -> Value { pub fn string(val: impl Into<String>, span: Span) -> Value {
Value::String { Value::String {
val: val.into(), val: val.into(),
@ -460,6 +365,12 @@ impl Value {
} }
} }
impl Default for Value {
fn default() -> Self {
Value::nothing()
}
}
impl PartialOrd for Value { impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
// Compare two floating point numbers. The decision interval for equality is dynamically // 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), ) 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::<Vec<Value>>().partial_cmp(rhs)
}
(Value::List { vals: lhs, .. }, Value::Stream { stream: rhs, .. }) => {
lhs.partial_cmp(&rhs.clone().collect::<Vec<Value>>())
}
(Value::Binary { val: lhs, .. }, Value::Binary { val: rhs, .. }) => { (Value::Binary { val: lhs, .. }, Value::Binary { val: rhs, .. }) => {
lhs.partial_cmp(rhs) lhs.partial_cmp(rhs)
} }
@ -852,10 +745,6 @@ impl Value {
val: rhs.contains(lhs), val: rhs.contains(lhs),
span, span,
}), }),
(lhs, Value::Stream { stream: rhs, .. }) => Ok(Value::Bool {
val: rhs.clone().any(|x| lhs == &x),
span,
}),
_ => Err(ShellError::OperatorMismatch { _ => Err(ShellError::OperatorMismatch {
op_span: op, op_span: op,
lhs_ty: self.get_type(), lhs_ty: self.get_type(),
@ -886,10 +775,6 @@ impl Value {
val: !rhs.contains(lhs), val: !rhs.contains(lhs),
span, span,
}), }),
(lhs, Value::Stream { stream: rhs, .. }) => Ok(Value::Bool {
val: rhs.clone().all(|x| lhs != &x),
span,
}),
_ => Err(ShellError::OperatorMismatch { _ => Err(ShellError::OperatorMismatch {
op_span: op, op_span: op,
lhs_ty: self.get_type(), lhs_ty: self.get_type(),

View File

@ -1,10 +1,7 @@
use crate::*; use crate::*;
use std::{cell::RefCell, fmt::Debug, rc::Rc}; use std::fmt::Debug;
use serde::{ser::SerializeSeq, Deserialize, Serialize}; pub struct ValueStream(pub Box<dyn Iterator<Item = Value> + Send + 'static>);
#[derive(Clone)]
pub struct ValueStream(pub Rc<RefCell<dyn Iterator<Item = Value>>>);
impl ValueStream { impl ValueStream {
pub fn into_string(self) -> String { pub fn into_string(self) -> String {
@ -22,8 +19,8 @@ impl ValueStream {
.join("\n") .join("\n")
} }
pub fn from_stream(input: impl Iterator<Item = Value> + 'static) -> ValueStream { pub fn from_stream(input: impl Iterator<Item = Value> + Send + 'static) -> ValueStream {
ValueStream(Rc::new(RefCell::new(input))) ValueStream(Box::new(input))
} }
} }
@ -38,66 +35,66 @@ impl Iterator for ValueStream {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
{ {
self.0.borrow_mut().next() self.0.next()
} }
} }
} }
impl Serialize for ValueStream { // impl Serialize for ValueStream {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> // fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where // where
S: serde::Serializer, // S: serde::Serializer,
{ // {
let mut seq = serializer.serialize_seq(None)?; // let mut seq = serializer.serialize_seq(None)?;
for element in self.0.borrow_mut().into_iter() { // for element in self.0.borrow_mut().into_iter() {
seq.serialize_element(&element)?; // seq.serialize_element(&element)?;
} // }
seq.end() // seq.end()
} // }
} // }
impl<'de> Deserialize<'de> for ValueStream { // impl<'de> Deserialize<'de> for ValueStream {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> // fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where // where
D: serde::Deserializer<'de>, // D: serde::Deserializer<'de>,
{ // {
deserializer.deserialize_seq(MySeqVisitor) // deserializer.deserialize_seq(MySeqVisitor)
} // }
} // }
struct MySeqVisitor; // struct MySeqVisitor;
impl<'a> serde::de::Visitor<'a> for MySeqVisitor { // impl<'a> serde::de::Visitor<'a> for MySeqVisitor {
type Value = ValueStream; // type Value = ValueStream;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { // fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a value stream") // formatter.write_str("a value stream")
} // }
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> // fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where // where
A: serde::de::SeqAccess<'a>, // A: serde::de::SeqAccess<'a>,
{ // {
let mut output: Vec<Value> = vec![]; // let mut output: Vec<Value> = vec![];
while let Some(value) = seq.next_element()? { // while let Some(value) = seq.next_element()? {
output.push(value); // output.push(value);
} // }
Ok(ValueStream(Rc::new(RefCell::new(output.into_iter())))) // Ok(ValueStream(Rc::new(RefCell::new(output.into_iter()))))
} // }
} // }
pub trait IntoValueStream { // pub trait IntoValueStream {
fn into_value_stream(self) -> ValueStream; // fn into_value_stream(self) -> ValueStream;
} // }
impl<T> IntoValueStream for T // impl<T> IntoValueStream for T
where // where
T: Iterator<Item = Value> + 'static, // T: Iterator<Item = Value> + 'static,
{ // {
fn into_value_stream(self) -> ValueStream { // fn into_value_stream(self) -> ValueStream {
ValueStream::from_stream(self) // ValueStream::from_stream(self)
} // }
} // }