nu_command/strings/str_/case/
downcase.rs1use 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}