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