diff --git a/crates/nu-command/src/generators/seq_char.rs b/crates/nu-command/src/generators/seq_char.rs index c0f16593d7..0f51815067 100644 --- a/crates/nu-command/src/generators/seq_char.rs +++ b/crates/nu-command/src/generators/seq_char.rs @@ -45,9 +45,10 @@ impl Command for SeqChar { )), }, Example { - description: "sequence a to e, and put the characters in a pipe-separated string", + description: "Sequence a to e, and join the characters with a pipe", example: "seq char a e | str join '|'", // TODO: it would be nice to test this example, but it currently breaks the input/output type tests + // result: Some(Value::test_string("a|b|c|d|e")), result: None, }, ] @@ -65,7 +66,7 @@ impl Command for SeqChar { } fn is_single_character(ch: &str) -> bool { - ch.is_ascii() && ch.len() == 1 && ch.chars().all(char::is_alphabetic) + ch.is_ascii() && (ch.len() == 1) } fn seq_char( @@ -79,7 +80,7 @@ fn seq_char( if !is_single_character(&start.item) { return Err(ShellError::GenericError { error: "seq char only accepts individual ASCII characters as parameters".into(), - msg: "should be 1 character long".into(), + msg: "input should be a single ASCII character".into(), span: Some(start.span), help: None, inner: vec![], @@ -89,7 +90,7 @@ fn seq_char( if !is_single_character(&end.item) { return Err(ShellError::GenericError { error: "seq char only accepts individual ASCII characters as parameters".into(), - msg: "should be 1 character long".into(), + msg: "input should be a single ASCII character".into(), span: Some(end.span), help: None, inner: vec![], @@ -115,18 +116,27 @@ fn seq_char( } fn run_seq_char(start_ch: char, end_ch: char, span: Span) -> Result { - let mut result_vec = vec![]; - for current_ch in start_ch as u8..end_ch as u8 + 1 { - result_vec.push((current_ch as char).to_string()) - } - + let start = start_ch as u8; + let end = end_ch as u8; + let range = if start <= end { + start..=end + } else { + end..=start + }; + let result_vec = if start <= end { + range.map(|c| (c as char).to_string()).collect::>() + } else { + range + .rev() + .map(|c| (c as char).to_string()) + .collect::>() + }; let result = result_vec .into_iter() .map(|x| Value::string(x, span)) .collect::>(); Ok(Value::list(result, span).into_pipeline_data()) } - #[cfg(test)] mod tests { use super::*; diff --git a/crates/nu-command/tests/commands/seq_char.rs b/crates/nu-command/tests/commands/seq_char.rs index 6c78084b80..b59f45d39d 100644 --- a/crates/nu-command/tests/commands/seq_char.rs +++ b/crates/nu-command/tests/commands/seq_char.rs @@ -4,12 +4,55 @@ use nu_test_support::nu; fn fails_when_first_arg_is_multiple_chars() { let actual = nu!("seq char aa z"); - assert!(actual.err.contains("should be 1 character long")); + assert!(actual + .err + .contains("input should be a single ASCII character")); } #[test] fn fails_when_second_arg_is_multiple_chars() { let actual = nu!("seq char a zz"); - assert!(actual.err.contains("should be 1 character long")); + assert!(actual + .err + .contains("input should be a single ASCII character")); +} + +#[test] +fn generates_sequence_from_a_to_e() { + let actual = nu!("seq char a e | str join ''"); + + assert_eq!(actual.out, "abcde"); +} + +#[test] +fn generates_sequence_from_e_to_a() { + let actual = nu!("seq char e a | str join ''"); + + assert_eq!(actual.out, "edcba"); +} + +#[test] +fn fails_when_non_ascii_character_is_used_in_first_arg() { + let actual = nu!("seq char ñ z"); + + assert!(actual + .err + .contains("input should be a single ASCII character")); +} + +#[test] +fn fails_when_non_ascii_character_is_used_in_second_arg() { + let actual = nu!("seq char a ñ"); + + assert!(actual + .err + .contains("input should be a single ASCII character")); +} + +#[test] +fn joins_sequence_with_pipe() { + let actual = nu!("seq char a e | str join '|'"); + + assert_eq!(actual.out, "a|b|c|d|e"); }