From ef20b5f1efdc4b5952d6c48873a2d5621ab9da24 Mon Sep 17 00:00:00 2001 From: onthebridgetonowhere <71919805+onthebridgetonowhere@users.noreply.github.com> Date: Tue, 9 Nov 2021 08:40:56 +0100 Subject: [PATCH] Port str capitalize (#317) * Port str capitalize command * Keep consistent naming for str commands Co-authored-by: Stefan Stanciulescu --- crates/nu-command/src/default_context.rs | 1 + .../nu-command/src/strings/str_/capitalize.rs | 142 ++++++++++++++++++ crates/nu-command/src/strings/str_/mod.rs | 2 + 3 files changed, 145 insertions(+) create mode 100644 crates/nu-command/src/strings/str_/capitalize.rs diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 2d65bb5e86..a6c04ac152 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -95,6 +95,7 @@ pub fn create_default_context() -> EngineState { SplitRow, Str, StrCamelCase, + StrCapitalize, StrCollect, StrKebabCase, StrPascalCase, diff --git a/crates/nu-command/src/strings/str_/capitalize.rs b/crates/nu-command/src/strings/str_/capitalize.rs new file mode 100644 index 0000000000..91b3e6d590 --- /dev/null +++ b/crates/nu-command/src/strings/str_/capitalize.rs @@ -0,0 +1,142 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::ast::CellPath; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "str capitalize" + } + + fn signature(&self) -> Signature { + Signature::build("str capitalize").rest( + "rest", + SyntaxShape::CellPath, + "optionally capitalize text by column paths", + ) + } + + fn usage(&self) -> &str { + "capitalizes text" + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + operate(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Capitalize contents", + example: "'good day' | str capitalize", + result: Some(Value::String { + val: "Good day".to_string(), + span: Span::unknown(), + }), + }, + Example { + description: "Capitalize contents", + example: "'anton' | str capitalize", + result: Some(Value::String { + val: "Anton".to_string(), + span: Span::unknown(), + }), + }, + Example { + description: "Capitalize a column in a table", + example: "[[lang, gems]; [nu_test, 100]] | str capitalize lang", + result: Some(Value::List { + vals: vec![Value::Record { + span: Span::unknown(), + cols: vec!["lang".to_string(), "gems".to_string()], + vals: vec![ + Value::String { + val: "Nu_test".to_string(), + span: Span::unknown(), + }, + Value::test_int(100), + ], + }], + span: Span::unknown(), + }), + }, + ] + } +} + +fn operate( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, +) -> Result { + let head = call.head; + let column_paths: Vec = call.rest(engine_state, stack, 0)?; + input.map( + move |v| { + if column_paths.is_empty() { + action(&v, head) + } else { + let mut ret = v; + for path in &column_paths { + let r = + ret.update_cell_path(&path.members, Box::new(move |old| action(old, head))); + if let Err(error) = r { + return Value::Error { error }; + } + } + ret + } + }, + engine_state.ctrlc.clone(), + ) +} + +fn action(input: &Value, head: Span) -> Value { + match input { + Value::String { val, .. } => Value::String { + val: uppercase_helper(val), + span: head, + }, + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Input's type is {}. This command only works with strings.", + other.get_type() + ), + Span::unknown(), + ), + }, + } +} + +fn uppercase_helper(s: &str) -> String { + // apparently more performant https://stackoverflow.com/questions/38406793/why-is-capitalizing-the-first-letter-of-a-string-so-convoluted-in-rust + let mut chars = s.chars(); + match chars.next() { + None => String::new(), + Some(f) => f.to_uppercase().collect::() + chars.as_str(), + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/strings/str_/mod.rs b/crates/nu-command/src/strings/str_/mod.rs index ee1f107861..40506ecf1d 100644 --- a/crates/nu-command/src/strings/str_/mod.rs +++ b/crates/nu-command/src/strings/str_/mod.rs @@ -1,5 +1,7 @@ +mod capitalize; mod case; mod collect; +pub use capitalize::SubCommand as StrCapitalize; pub use case::*; pub use collect::*;