nu_command/generators/
seq_char.rs1use nu_engine::command_prelude::*;
2use nu_protocol::shell_error::generic::GenericError;
3
4#[derive(Clone)]
5pub struct SeqChar;
6
7impl Command for SeqChar {
8 fn name(&self) -> &str {
9 "seq char"
10 }
11
12 fn description(&self) -> &str {
13 "Print a sequence of ASCII characters."
14 }
15
16 fn signature(&self) -> Signature {
17 Signature::build("seq char")
18 .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::String)))])
19 .required(
20 "start",
21 SyntaxShape::String,
22 "Start of character sequence (inclusive).",
23 )
24 .required(
25 "end",
26 SyntaxShape::String,
27 "End of character sequence (inclusive).",
28 )
29 .category(Category::Generators)
30 }
31
32 fn examples(&self) -> Vec<Example<'_>> {
33 vec![
34 Example {
35 description: "sequence a to e",
36 example: "seq char a e",
37 result: Some(Value::list(
38 vec![
39 Value::test_string('a'),
40 Value::test_string('b'),
41 Value::test_string('c'),
42 Value::test_string('d'),
43 Value::test_string('e'),
44 ],
45 Span::test_data(),
46 )),
47 },
48 Example {
49 description: "Sequence a to e, and join the characters with a pipe",
50 example: "seq char a e | str join '|'",
51 result: None,
54 },
55 ]
56 }
57
58 fn run(
59 &self,
60 engine_state: &EngineState,
61 stack: &mut Stack,
62 call: &Call,
63 _input: PipelineData,
64 ) -> Result<PipelineData, ShellError> {
65 seq_char(engine_state, stack, call)
66 }
67}
68
69fn is_single_character(ch: &str) -> bool {
70 ch.is_ascii() && (ch.len() == 1)
71}
72
73fn seq_char(
74 engine_state: &EngineState,
75 stack: &mut Stack,
76 call: &Call,
77) -> Result<PipelineData, ShellError> {
78 let start: Spanned<String> = call.req(engine_state, stack, 0)?;
79 let end: Spanned<String> = call.req(engine_state, stack, 1)?;
80
81 if !is_single_character(&start.item) {
82 return Err(ShellError::Generic(GenericError::new(
83 "seq char only accepts individual ASCII characters as parameters",
84 "input should be a single ASCII character",
85 start.span,
86 )));
87 }
88
89 if !is_single_character(&end.item) {
90 return Err(ShellError::Generic(GenericError::new(
91 "seq char only accepts individual ASCII characters as parameters",
92 "input should be a single ASCII character",
93 end.span,
94 )));
95 }
96
97 let start = start
98 .item
99 .chars()
100 .next()
101 .expect("seq char input must contains 2 inputs");
103
104 let end = end
105 .item
106 .chars()
107 .next()
108 .expect("seq char input must contains 2 inputs");
110
111 let span = call.head;
112 run_seq_char(start, end, span)
113}
114
115fn run_seq_char(start_ch: char, end_ch: char, span: Span) -> Result<PipelineData, ShellError> {
116 let start = start_ch as u8;
117 let end = end_ch as u8;
118 let range = if start <= end {
119 start..=end
120 } else {
121 end..=start
122 };
123 let result_vec = if start <= end {
124 range.map(|c| (c as char).to_string()).collect::<Vec<_>>()
125 } else {
126 range
127 .rev()
128 .map(|c| (c as char).to_string())
129 .collect::<Vec<_>>()
130 };
131 let result = result_vec
132 .into_iter()
133 .map(|x| Value::string(x, span))
134 .collect::<Vec<Value>>();
135 Ok(Value::list(result, span).into_pipeline_data())
136}
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_examples() -> nu_test_support::Result {
143 nu_test_support::test().examples(SeqChar)
144 }
145}