nu_command/strings/split/
chars.rs1use crate::{grapheme_flags, grapheme_flags_const};
2use nu_engine::command_prelude::*;
3
4use unicode_segmentation::UnicodeSegmentation;
5
6#[derive(Clone)]
7pub struct SplitChars;
8
9impl Command for SplitChars {
10 fn name(&self) -> &str {
11 "split chars"
12 }
13
14 fn signature(&self) -> Signature {
15 Signature::build("split chars")
16 .input_output_types(vec![
17 (Type::String, Type::List(Box::new(Type::String))),
18 (
19 Type::List(Box::new(Type::String)),
20 Type::List(Box::new(Type::List(Box::new(Type::String)))),
21 ),
22 ])
23 .allow_variants_without_examples(true)
24 .switch(
25 "grapheme-clusters",
26 "Split on grapheme clusters.",
27 Some('g'),
28 )
29 .switch(
30 "code-points",
31 "Split on code points (default; splits combined characters).",
32 Some('c'),
33 )
34 .category(Category::Strings)
35 }
36
37 fn description(&self) -> &str {
38 "Split a string into a list of characters."
39 }
40
41 fn search_terms(&self) -> Vec<&str> {
42 vec!["character", "separate", "divide"]
43 }
44
45 fn examples(&self) -> Vec<Example<'_>> {
46 vec![
47 Example {
48 description: "Split the string into a list of characters.",
49 example: "'hello' | split chars",
50 result: Some(Value::list(
51 vec![
52 Value::test_string("h"),
53 Value::test_string("e"),
54 Value::test_string("l"),
55 Value::test_string("l"),
56 Value::test_string("o"),
57 ],
58 Span::test_data(),
59 )),
60 },
61 Example {
62 description: "Split on grapheme clusters.",
63 example: "'🇯🇵ほげ' | split chars --grapheme-clusters",
64 result: Some(Value::list(
65 vec![
66 Value::test_string("🇯🇵"),
67 Value::test_string("ほ"),
68 Value::test_string("げ"),
69 ],
70 Span::test_data(),
71 )),
72 },
73 Example {
74 description: "Split multiple strings into lists of characters.",
75 example: "['hello', 'world'] | split chars",
76 result: Some(Value::test_list(vec![
77 Value::test_list(vec![
78 Value::test_string("h"),
79 Value::test_string("e"),
80 Value::test_string("l"),
81 Value::test_string("l"),
82 Value::test_string("o"),
83 ]),
84 Value::test_list(vec![
85 Value::test_string("w"),
86 Value::test_string("o"),
87 Value::test_string("r"),
88 Value::test_string("l"),
89 Value::test_string("d"),
90 ]),
91 ])),
92 },
93 ]
94 }
95
96 fn is_const(&self) -> bool {
97 true
98 }
99
100 fn run(
101 &self,
102 engine_state: &EngineState,
103 stack: &mut Stack,
104 call: &Call,
105 input: PipelineData,
106 ) -> Result<PipelineData, ShellError> {
107 let graphemes = grapheme_flags(engine_state, stack, call)?;
108 split_chars(engine_state, call, input, graphemes)
109 }
110
111 fn run_const(
112 &self,
113 working_set: &StateWorkingSet,
114 call: &Call,
115 input: PipelineData,
116 ) -> Result<PipelineData, ShellError> {
117 let graphemes = grapheme_flags_const(working_set, call)?;
118 split_chars(working_set.permanent(), call, input, graphemes)
119 }
120}
121
122fn split_chars(
123 engine_state: &EngineState,
124 call: &Call,
125 input: PipelineData,
126 graphemes: bool,
127) -> Result<PipelineData, ShellError> {
128 let span = call.head;
129 input.map(
130 move |x| split_chars_helper(&x, span, graphemes),
131 engine_state.signals(),
132 )
133}
134
135fn split_chars_helper(v: &Value, name: Span, graphemes: bool) -> Value {
136 let span = v.span();
137 match v {
138 Value::Error { error, .. } => Value::error(*error.clone(), span),
139 v => {
140 let v_span = v.span();
141 if let Ok(s) = v.as_str() {
142 Value::list(
143 if graphemes {
144 s.graphemes(true)
145 .collect::<Vec<_>>()
146 .into_iter()
147 .map(move |x| Value::string(x, v_span))
148 .collect()
149 } else {
150 s.chars()
151 .collect::<Vec<_>>()
152 .into_iter()
153 .map(move |x| Value::string(x, v_span))
154 .collect()
155 },
156 v_span,
157 )
158 } else {
159 Value::error(
160 ShellError::OnlySupportsThisInputType {
161 exp_input_type: "string".into(),
162 wrong_type: v.get_type().to_string(),
163 dst_span: name,
164 src_span: v_span,
165 },
166 name,
167 )
168 }
169 }
170 }
171}
172
173#[cfg(test)]
174mod test {
175 use super::*;
176
177 #[test]
178 fn test_examples() {
179 use crate::test_examples;
180
181 test_examples(SplitChars {})
182 }
183}