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