diff --git a/crates/nu-command/src/commands.rs b/crates/nu-command/src/commands.rs index 2331ad81c5..738d1d72af 100644 --- a/crates/nu-command/src/commands.rs +++ b/crates/nu-command/src/commands.rs @@ -307,7 +307,7 @@ mod tests { whole_stream_command(StrUpcase), whole_stream_command(StrCapitalize), whole_stream_command(StrFindReplace), - // whole_stream_command(StrFrom), + whole_stream_command(StrFrom), whole_stream_command(StrSubstring), whole_stream_command(StrToDatetime), whole_stream_command(StrContains), @@ -318,9 +318,9 @@ mod tests { whole_stream_command(StrStartsWith), whole_stream_command(StrEndsWith), //whole_stream_command(StrCollect), - //whole_stream_command(StrLength), + whole_stream_command(StrLength), whole_stream_command(StrLPad), - //whole_stream_command(StrReverse), + whole_stream_command(StrReverse), whole_stream_command(StrRPad), whole_stream_command(StrCamelCase), whole_stream_command(StrPascalCase), diff --git a/crates/nu-command/src/commands/str_/from.rs b/crates/nu-command/src/commands/str_/from.rs index 32731db74a..5eb402150a 100644 --- a/crates/nu-command/src/commands/str_/from.rs +++ b/crates/nu-command/src/commands/str_/from.rs @@ -63,7 +63,7 @@ impl WholeStreamCommand for SubCommand { vec![ Example { description: "round to nearest integer", - example: "= 1.7 | str from -d 0", + example: "echo 1.7 | str from -d 0", result: Some(vec![UntaggedValue::string("2").into_untagged_value()]), }, /* diff --git a/crates/nu-command/src/commands/str_/length.rs b/crates/nu-command/src/commands/str_/length.rs index 6dec270242..a173337450 100644 --- a/crates/nu-command/src/commands/str_/length.rs +++ b/crates/nu-command/src/commands/str_/length.rs @@ -1,10 +1,18 @@ use crate::prelude::*; use nu_engine::WholeStreamCommand; use nu_errors::ShellError; -use nu_protocol::{ReturnSuccess, Signature, UntaggedValue}; +use nu_protocol::ShellTypeName; +use nu_protocol::{ + ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, +}; pub struct SubCommand; +#[derive(Deserialize)] +struct Arguments { + rest: Vec, +} + #[async_trait] impl WholeStreamCommand for SubCommand { fn name(&self) -> &str { @@ -12,7 +20,10 @@ impl WholeStreamCommand for SubCommand { } fn signature(&self) -> Signature { - Signature::build("str length") + Signature::build("str length").rest( + SyntaxShape::ColumnPath, + "optionally find length of text by column paths", + ) } fn usage(&self) -> &str { @@ -20,13 +31,7 @@ impl WholeStreamCommand for SubCommand { } async fn run(&self, args: CommandArgs) -> Result { - Ok(args - .input - .map(move |x| match x.as_string() { - Ok(s) => ReturnSuccess::value(UntaggedValue::int(s.len()).into_untagged_value()), - Err(err) => Err(err), - }) - .to_output_stream()) + operate(args).await } fn examples(&self) -> Vec { @@ -48,6 +53,47 @@ impl WholeStreamCommand for SubCommand { } } +async fn operate(args: CommandArgs) -> Result { + let (Arguments { rest }, input) = args.process().await?; + let column_paths: Vec<_> = rest; + + Ok(input + .map(move |v| { + if column_paths.is_empty() { + ReturnSuccess::value(action(&v, v.tag())?) + } else { + let mut ret = v; + + for path in &column_paths { + ret = ret.swap_data_by_column_path( + path, + Box::new(move |old| action(old, old.tag())), + )?; + } + + ReturnSuccess::value(ret) + } + }) + .to_output_stream()) +} + +fn action(input: &Value, tag: impl Into) -> Result { + match &input.value { + UntaggedValue::Primitive(Primitive::String(s)) => { + Ok(UntaggedValue::int(s.len()).into_value(tag)) + } + other => { + let got = format!("got {}", other.type_name()); + + Err(ShellError::labeled_error( + "value is not string", + got, + tag.into().span, + )) + } + } +} + #[cfg(test)] mod tests { use super::ShellError; diff --git a/crates/nu-command/src/commands/str_/reverse.rs b/crates/nu-command/src/commands/str_/reverse.rs index 3605958d74..c8b5d87068 100644 --- a/crates/nu-command/src/commands/str_/reverse.rs +++ b/crates/nu-command/src/commands/str_/reverse.rs @@ -1,10 +1,18 @@ use crate::prelude::*; use nu_engine::WholeStreamCommand; use nu_errors::ShellError; -use nu_protocol::{ReturnSuccess, Signature, UntaggedValue}; +use nu_protocol::ShellTypeName; +use nu_protocol::{ + ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, +}; pub struct SubCommand; +#[derive(Deserialize)] +struct Arguments { + rest: Vec, +} + #[async_trait] impl WholeStreamCommand for SubCommand { fn name(&self) -> &str { @@ -12,7 +20,10 @@ impl WholeStreamCommand for SubCommand { } fn signature(&self) -> Signature { - Signature::build("str reverse") + Signature::build("str reverse").rest( + SyntaxShape::ColumnPath, + "optionally reverse text by column paths", + ) } fn usage(&self) -> &str { @@ -20,16 +31,7 @@ impl WholeStreamCommand for SubCommand { } async fn run(&self, args: CommandArgs) -> Result { - Ok(args - .input - .map(move |x| match x.as_string() { - Ok(s) => ReturnSuccess::value( - UntaggedValue::string(s.chars().rev().collect::()) - .into_untagged_value(), - ), - Err(err) => Err(err), - }) - .to_output_stream()) + operate(args).await } fn examples(&self) -> Vec { @@ -41,6 +43,46 @@ impl WholeStreamCommand for SubCommand { } } +async fn operate(args: CommandArgs) -> Result { + let (Arguments { rest }, input) = args.process().await?; + let column_paths: Vec<_> = rest; + + Ok(input + .map(move |v| { + if column_paths.is_empty() { + ReturnSuccess::value(action(&v, v.tag())?) + } else { + let mut ret = v; + + for path in &column_paths { + ret = ret.swap_data_by_column_path( + path, + Box::new(move |old| action(old, old.tag())), + )?; + } + + ReturnSuccess::value(ret) + } + }) + .to_output_stream()) +} + +fn action(input: &Value, tag: impl Into) -> Result { + match &input.value { + UntaggedValue::Primitive(Primitive::String(s)) => { + Ok(UntaggedValue::string(s.chars().rev().collect::()).into_value(tag)) + } + other => { + let got = format!("got {}", other.type_name()); + Err(ShellError::labeled_error( + "value is not string", + got, + tag.into().span, + )) + } + } +} + #[cfg(test)] mod tests { use super::ShellError;