Skip to main content

nu_command/strings/str_/case/
downcase.rs

1use nu_engine::command_prelude::*;
2use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode};
3
4#[derive(Clone)]
5pub struct StrDowncase;
6
7impl Command for StrDowncase {
8    fn name(&self) -> &str {
9        "str downcase"
10    }
11
12    fn signature(&self) -> Signature {
13        Signature::build("str downcase")
14            .input_output_types(vec![
15                (Type::String, Type::String),
16                (
17                    Type::List(Box::new(Type::String)),
18                    Type::List(Box::new(Type::String)),
19                ),
20                (Type::table(), Type::table()),
21                (Type::record(), Type::record()),
22            ])
23            .allow_variants_without_examples(true)
24            .rest(
25                "rest",
26                SyntaxShape::CellPath,
27                "For a data structure input, convert strings at the given cell paths.",
28            )
29            .category(Category::Strings)
30    }
31
32    fn description(&self) -> &str {
33        "Convert text to lowercase."
34    }
35
36    fn search_terms(&self) -> Vec<&str> {
37        vec!["lowercase", "lower case", "lower-case"]
38    }
39
40    fn is_const(&self) -> bool {
41        true
42    }
43
44    fn run(
45        &self,
46        engine_state: &EngineState,
47        stack: &mut Stack,
48        call: &Call,
49        input: PipelineData,
50    ) -> Result<PipelineData, ShellError> {
51        let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
52        operate(engine_state, call, input, column_paths)
53    }
54
55    fn run_const(
56        &self,
57        working_set: &StateWorkingSet,
58        call: &Call,
59        input: PipelineData,
60    ) -> Result<PipelineData, ShellError> {
61        let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
62        operate(working_set.permanent(), call, input, column_paths)
63    }
64
65    fn examples(&self) -> Vec<Example<'_>> {
66        vec![
67            Example {
68                description: "Downcase contents.",
69                example: "'NU' | str downcase",
70                result: Some(Value::test_string("nu")),
71            },
72            Example {
73                description: "Downcase contents.",
74                example: "'TESTa' | str downcase",
75                result: Some(Value::test_string("testa")),
76            },
77            Example {
78                description: "Downcase contents.",
79                example: "[[ColA ColB]; [Test ABC]] | str downcase ColA",
80                result: Some(Value::test_list(vec![Value::test_record(record! {
81                    "ColA" => Value::test_string("test"),
82                    "ColB" => Value::test_string("ABC"),
83                })])),
84            },
85            Example {
86                description: "Downcase contents.",
87                example: "[[ColA ColB]; [Test ABC]] | str downcase ColA ColB",
88                result: Some(Value::test_list(vec![Value::test_record(record! {
89                    "ColA" => Value::test_string("test"),
90                    "ColB" => Value::test_string("abc"),
91                })])),
92            },
93        ]
94    }
95
96    fn deprecation_info(&self) -> Vec<DeprecationEntry> {
97        vec![DeprecationEntry {
98            ty: DeprecationType::Command,
99            report_mode: ReportMode::FirstUse,
100            since: Some("0.114.0".into()),
101            expected_removal: None,
102            help: Some("Use `str lowercase` instead.".into()),
103        }]
104    }
105}
106
107#[derive(Clone)]
108pub struct StrLowercase;
109
110impl Command for StrLowercase {
111    fn name(&self) -> &str {
112        "str lowercase"
113    }
114
115    fn signature(&self) -> Signature {
116        Signature::build("str lowercase")
117            .input_output_types(vec![
118                (Type::String, Type::String),
119                (
120                    Type::List(Box::new(Type::String)),
121                    Type::List(Box::new(Type::String)),
122                ),
123                (Type::table(), Type::table()),
124                (Type::record(), Type::record()),
125            ])
126            .allow_variants_without_examples(true)
127            .rest(
128                "rest",
129                SyntaxShape::CellPath,
130                "For a data structure input, convert strings at the given cell paths.",
131            )
132            .category(Category::Strings)
133    }
134
135    fn description(&self) -> &str {
136        "Convert text to lowercase."
137    }
138
139    fn search_terms(&self) -> Vec<&str> {
140        vec!["downcase"]
141    }
142
143    fn is_const(&self) -> bool {
144        true
145    }
146
147    fn run(
148        &self,
149        engine_state: &EngineState,
150        stack: &mut Stack,
151        call: &Call,
152        input: PipelineData,
153    ) -> Result<PipelineData, ShellError> {
154        let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
155        operate(engine_state, call, input, column_paths)
156    }
157
158    fn run_const(
159        &self,
160        working_set: &StateWorkingSet,
161        call: &Call,
162        input: PipelineData,
163    ) -> Result<PipelineData, ShellError> {
164        let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
165        operate(working_set.permanent(), call, input, column_paths)
166    }
167
168    fn examples(&self) -> Vec<Example<'_>> {
169        vec![
170            Example {
171                description: "Lowercase contents.",
172                example: "'NU' | str lowercase",
173                result: Some(Value::test_string("nu")),
174            },
175            Example {
176                description: "Lowercase contents.",
177                example: "'TESTa' | str lowercase",
178                result: Some(Value::test_string("testa")),
179            },
180            Example {
181                description: "Lowercase contents.",
182                example: "[[ColA ColB]; [Test ABC]] | str lowercase ColA",
183                result: Some(Value::test_list(vec![Value::test_record(record! {
184                    "ColA" => Value::test_string("test"),
185                    "ColB" => Value::test_string("ABC"),
186                })])),
187            },
188            Example {
189                description: "Lowercase contents.",
190                example: "[[ColA ColB]; [Test ABC]] | str lowercase ColA ColB",
191                result: Some(Value::test_list(vec![Value::test_record(record! {
192                    "ColA" => Value::test_string("test"),
193                    "ColB" => Value::test_string("abc"),
194                })])),
195            },
196        ]
197    }
198}
199
200fn operate(
201    engine_state: &EngineState,
202    call: &Call,
203    input: PipelineData,
204    column_paths: Vec<CellPath>,
205) -> Result<PipelineData, ShellError> {
206    let head = call.head;
207    input.map(
208        move |v| {
209            if column_paths.is_empty() {
210                action(&v, head)
211            } else {
212                let mut ret = v;
213                for path in &column_paths {
214                    let r =
215                        ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
216                    if let Err(error) = r {
217                        return Value::error(error, head);
218                    }
219                }
220                ret
221            }
222        },
223        engine_state.signals(),
224    )
225}
226
227fn action(input: &Value, head: Span) -> Value {
228    match input {
229        Value::String { val, .. } => Value::string(val.to_lowercase(), head),
230        Value::Error { .. } => input.clone(),
231        _ => Value::error(
232            ShellError::OnlySupportsThisInputType {
233                exp_input_type: "string".into(),
234                wrong_type: input.get_type().to_string(),
235                dst_span: head,
236                src_span: input.span(),
237            },
238            head,
239        ),
240    }
241}
242
243#[cfg(test)]
244mod test {
245    use super::*;
246
247    #[test]
248    fn test_downcase_examples() -> nu_test_support::Result {
249        nu_test_support::test().examples(StrDowncase)
250    }
251
252    #[test]
253    fn test_lowercase_examples() -> nu_test_support::Result {
254        nu_test_support::test().examples(StrLowercase)
255    }
256}