nu_command/strings/str_/case/
downcase.rs

1use nu_engine::command_prelude::*;
2
3#[derive(Clone)]
4pub struct StrDowncase;
5
6impl Command for StrDowncase {
7    fn name(&self) -> &str {
8        "str downcase"
9    }
10
11    fn signature(&self) -> Signature {
12        Signature::build("str downcase")
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        "Make text lowercase."
33    }
34
35    fn search_terms(&self) -> Vec<&str> {
36        vec!["lower case", "lowercase"]
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: "Downcase contents",
68                example: "'NU' | str downcase",
69                result: Some(Value::test_string("nu")),
70            },
71            Example {
72                description: "Downcase contents",
73                example: "'TESTa' | str downcase",
74                result: Some(Value::test_string("testa")),
75            },
76            Example {
77                description: "Downcase contents",
78                example: "[[ColA ColB]; [Test ABC]] | str downcase ColA",
79                result: Some(Value::test_list(vec![Value::test_record(record! {
80                    "ColA" => Value::test_string("test"),
81                    "ColB" => Value::test_string("ABC"),
82                })])),
83            },
84            Example {
85                description: "Downcase contents",
86                example: "[[ColA ColB]; [Test ABC]] | str downcase ColA ColB",
87                result: Some(Value::test_list(vec![Value::test_record(record! {
88                    "ColA" => Value::test_string("test"),
89                    "ColB" => Value::test_string("abc"),
90                })])),
91            },
92        ]
93    }
94}
95
96fn operate(
97    engine_state: &EngineState,
98    call: &Call,
99    input: PipelineData,
100    column_paths: Vec<CellPath>,
101) -> Result<PipelineData, ShellError> {
102    let head = call.head;
103    input.map(
104        move |v| {
105            if column_paths.is_empty() {
106                action(&v, head)
107            } else {
108                let mut ret = v;
109                for path in &column_paths {
110                    let r =
111                        ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
112                    if let Err(error) = r {
113                        return Value::error(error, head);
114                    }
115                }
116                ret
117            }
118        },
119        engine_state.signals(),
120    )
121}
122
123fn action(input: &Value, head: Span) -> Value {
124    match input {
125        Value::String { val, .. } => Value::string(val.to_lowercase(), head),
126        Value::Error { .. } => input.clone(),
127        _ => Value::error(
128            ShellError::OnlySupportsThisInputType {
129                exp_input_type: "string".into(),
130                wrong_type: input.get_type().to_string(),
131                dst_span: head,
132                src_span: input.span(),
133            },
134            head,
135        ),
136    }
137}
138
139#[cfg(test)]
140mod test {
141    use super::*;
142    #[test]
143    fn test_examples() {
144        use crate::test_examples;
145
146        test_examples(StrDowncase {})
147    }
148}