nu_command/strings/str_/case/
capitalize.rs1use nu_engine::command_prelude::*;
2
3#[derive(Clone)]
4pub struct StrCapitalize;
5
6impl Command for StrCapitalize {
7 fn name(&self) -> &str {
8 "str capitalize"
9 }
10
11 fn signature(&self) -> Signature {
12 Signature::build("str capitalize")
13 .input_output_types(vec![
14 (Type::String, Type::String),
15 (
16 Type::List(Box::new(Type::String)),
17 Type::List(Box::new(Type::String)),
18 ),
19 (Type::table(), Type::table()),
20 (Type::record(), Type::record()),
21 ])
22 .allow_variants_without_examples(true)
23 .rest(
24 "rest",
25 SyntaxShape::CellPath,
26 "For a data structure input, convert strings at the given cell paths.",
27 )
28 .category(Category::Strings)
29 }
30
31 fn description(&self) -> &str {
32 "Capitalize first letter of text."
33 }
34
35 fn search_terms(&self) -> Vec<&str> {
36 vec!["convert", "style", "caps", "upper"]
37 }
38
39 fn is_const(&self) -> bool {
40 true
41 }
42
43 fn run(
44 &self,
45 engine_state: &EngineState,
46 stack: &mut Stack,
47 call: &Call,
48 input: PipelineData,
49 ) -> Result<PipelineData, ShellError> {
50 let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
51 operate(engine_state, call, input, column_paths)
52 }
53
54 fn run_const(
55 &self,
56 working_set: &StateWorkingSet,
57 call: &Call,
58 input: PipelineData,
59 ) -> Result<PipelineData, ShellError> {
60 let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
61 operate(working_set.permanent(), call, input, column_paths)
62 }
63
64 fn examples(&self) -> Vec<Example<'_>> {
65 vec![
66 Example {
67 description: "Capitalize contents",
68 example: "'good day' | str capitalize",
69 result: Some(Value::test_string("Good day")),
70 },
71 Example {
72 description: "Capitalize contents",
73 example: "'anton' | str capitalize",
74 result: Some(Value::test_string("Anton")),
75 },
76 Example {
77 description: "Capitalize a column in a table",
78 example: "[[lang, gems]; [nu_test, 100]] | str capitalize lang",
79 result: Some(Value::test_list(vec![Value::test_record(record! {
80 "lang" => Value::test_string("Nu_test"),
81 "gems" => Value::test_int(100),
82 })])),
83 },
84 ]
85 }
86}
87
88fn operate(
89 engine_state: &EngineState,
90 call: &Call,
91 input: PipelineData,
92 column_paths: Vec<CellPath>,
93) -> Result<PipelineData, ShellError> {
94 let head = call.head;
95 input.map(
96 move |v| {
97 if column_paths.is_empty() {
98 action(&v, head)
99 } else {
100 let mut ret = v;
101 for path in &column_paths {
102 let r =
103 ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
104 if let Err(error) = r {
105 return Value::error(error, head);
106 }
107 }
108 ret
109 }
110 },
111 engine_state.signals(),
112 )
113}
114
115fn action(input: &Value, head: Span) -> Value {
116 match input {
117 Value::String { val, .. } => Value::string(uppercase_helper(val), head),
118 Value::Error { .. } => input.clone(),
119 _ => Value::error(
120 ShellError::OnlySupportsThisInputType {
121 exp_input_type: "string".into(),
122 wrong_type: input.get_type().to_string(),
123 dst_span: head,
124 src_span: input.span(),
125 },
126 head,
127 ),
128 }
129}
130
131fn uppercase_helper(s: &str) -> String {
132 let mut chars = s.chars();
134 match chars.next() {
135 None => String::new(),
136 Some(f) => f.to_uppercase().collect::<String>() + chars.as_str(),
137 }
138}
139
140#[cfg(test)]
141mod test {
142 use super::*;
143
144 #[test]
145 fn test_examples() {
146 use crate::test_examples;
147
148 test_examples(StrCapitalize {})
149 }
150}