diff --git a/src/commands/nth.rs b/src/commands/nth.rs index 17eb6dba7f..5651d84123 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -5,7 +5,7 @@ use crate::prelude::*; #[derive(Deserialize)] struct NthArgs { - position: Tagged, + amount: Tagged, } pub struct Nth; @@ -24,12 +24,12 @@ impl WholeStreamCommand for Nth { } fn signature(&self) -> Signature { - Signature::build("nth").optional("amount", SyntaxType::Any) + Signature::build("nth").required("amount", SyntaxType::Any) } } fn nth( - NthArgs { position: amount }: NthArgs, + NthArgs { amount }: NthArgs, RunnableContext { input, .. }: RunnableContext, ) -> Result { Ok(OutputStream::from_input( diff --git a/src/commands/pick.rs b/src/commands/pick.rs index a456aa3722..21a83480f8 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -31,8 +31,16 @@ impl WholeStreamCommand for Pick { fn pick( PickArgs { rest: fields }: PickArgs, - RunnableContext { input, .. }: RunnableContext, + RunnableContext { input, name, .. }: RunnableContext, ) -> Result { + if fields.len() == 0 { + return Err(ShellError::labeled_error( + "Pick requires fields", + "needs parameter", + name, + )); + } + let fields: Vec<_> = fields.iter().map(|f| f.item.clone()).collect(); let objects = input diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 67d8b1d82b..4fc60fecf8 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -30,8 +30,16 @@ impl WholeStreamCommand for Reject { fn reject( RejectArgs { rest: fields }: RejectArgs, - RunnableContext { input, .. }: RunnableContext, + RunnableContext { input, name, .. }: RunnableContext, ) -> Result { + if fields.len() == 0 { + return Err(ShellError::labeled_error( + "Reject requires fields", + "needs parameter", + name, + )); + } + let fields: Vec<_> = fields.iter().map(|f| f.item.clone()).collect(); let stream = input diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index d0351bf1c7..fbccc89c6d 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -6,6 +6,7 @@ use log::trace; #[derive(Deserialize)] struct SplitColumnArgs { + separator: Tagged, rest: Vec>, } @@ -25,32 +26,30 @@ impl WholeStreamCommand for SplitColumn { } fn signature(&self) -> Signature { - // TODO: Improve error. Old error had extra info: - // - // needs parameter (e.g. split-column ",") - Signature::build("split-column").rest() + Signature::build("split-column") + .required("separator", SyntaxType::Any) + .rest() } } fn split_column( - SplitColumnArgs { rest: positional }: SplitColumnArgs, + SplitColumnArgs { separator, rest }: SplitColumnArgs, RunnableContext { input, name, .. }: RunnableContext, ) -> Result { Ok(input .values .map(move |v| match v.item { Value::Primitive(Primitive::String(ref s)) => { - let positional: Vec<_> = positional.iter().map(|f| f.item.clone()).collect(); - - // TODO: Require at least 1 positional argument. - let splitter = positional[0].replace("\\n", "\n"); + let splitter = separator.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); - let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); + let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); trace!("split result = {:?}", split_result); + let positional: Vec<_> = rest.iter().map(|f| f.item.clone()).collect(); + // If they didn't provide column names, make up our own - if (positional.len() - 1) == 0 { + if positional.len() == 0 { let mut gen_columns = vec![]; for i in 0..split_result.len() { gen_columns.push(format!("Column{}", i + 1)); @@ -62,16 +61,16 @@ fn split_column( } ReturnSuccess::value(dict.into_tagged_value()) - } else if split_result.len() == (positional.len() - 1) { + } else if split_result.len() == positional.len() { let mut dict = TaggedDictBuilder::new(v.tag()); - for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { + for (&k, v) in split_result.iter().zip(positional.iter()) { dict.insert(v, Value::Primitive(Primitive::String(k.into()))); } ReturnSuccess::value(dict.into_tagged_value()) } else { let mut dict = TaggedDictBuilder::new(v.tag()); - for k in positional.iter().skip(1) { - dict.insert(k.trim(), Primitive::String("".into())); + for (&k, v) in split_result.iter().zip(positional.iter()) { + dict.insert(v, Value::Primitive(Primitive::String(k.into()))); } ReturnSuccess::value(dict.into_tagged_value()) } diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 71e342b289..592d301bea 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -6,7 +6,7 @@ use log::trace; #[derive(Deserialize)] struct SplitRowArgs { - rest: Vec>, + separator: Tagged, } pub struct SplitRow; @@ -25,22 +25,19 @@ impl WholeStreamCommand for SplitRow { } fn signature(&self) -> Signature { - // TODO: Improve error. Old error had extra info: - // - // needs parameter (e.g. split-row ",") - Signature::build("split-row").rest() + Signature::build("split-row").required("separator", SyntaxType::Any) } } fn split_row( - SplitRowArgs { rest: positional }: SplitRowArgs, + SplitRowArgs { separator }: SplitRowArgs, RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = input .values .map(move |v| match v.item { Value::Primitive(Primitive::String(ref s)) => { - let splitter = positional[0].item.replace("\\n", "\n"); + let splitter = separator.item.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); diff --git a/src/commands/to_array.rs b/src/commands/to_array.rs index 6d044d6d8d..43984ce58b 100644 --- a/src/commands/to_array.rs +++ b/src/commands/to_array.rs @@ -22,11 +22,13 @@ impl WholeStreamCommand for ToArray { } } -fn to_array(args: CommandArgs, _registry: &CommandRegistry) -> Result { +fn to_array(args: CommandArgs, registry: &CommandRegistry) -> Result { + let args = args.evaluate_once(registry)?; + let span = args.call_info.name_span; let out = args.input.values.collect(); Ok(out - .map(|vec: Vec<_>| stream![Value::List(vec).tagged_unknown()]) // TODO: args.input should have a span + .map(move |vec: Vec<_>| stream![Value::List(vec).simple_spanned(span)]) .flatten_stream() .from_input_stream()) } diff --git a/src/errors.rs b/src/errors.rs index ec5cffee94..e4a263d990 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -186,13 +186,14 @@ impl ShellError { ArgumentError::MissingMandatoryPositional(name) => Diagnostic::new( Severity::Error, format!( - "{} requires {}", + "{} requires {} parameter", Color::Cyan.paint(command), - Color::Green.bold().paint(name) + Color::Green.bold().paint(name.clone()) ), ) - .with_label(Label::new_primary(span)), - + .with_label( + Label::new_primary(span).with_message(format!("requires {} parameter", name)), + ), ArgumentError::MissingValueForName(name) => Diagnostic::new( Severity::Error, format!(