1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

expand: allow specifier only with last value

This commit is contained in:
Daniel Hofstetter 2022-06-05 15:16:48 +02:00
parent fc5aedfbb7
commit 804240164b
2 changed files with 39 additions and 0 deletions

View file

@ -41,6 +41,7 @@ static DEFAULT_TABSTOP: usize = 8;
/// The mode to use when replacing tabs beyond the last one specified in /// The mode to use when replacing tabs beyond the last one specified in
/// the `--tabs` argument. /// the `--tabs` argument.
#[derive(PartialEq)]
enum RemainingMode { enum RemainingMode {
None, None,
Slash, Slash,
@ -65,6 +66,7 @@ fn is_space_or_comma(c: char) -> bool {
enum ParseError { enum ParseError {
InvalidCharacter(String), InvalidCharacter(String),
SpecifierNotAtStartOfNumber(String, String), SpecifierNotAtStartOfNumber(String, String),
SpecifierOnlyAllowedWithLastValue(String),
TabSizeCannotBeZero, TabSizeCannotBeZero,
TabSizeTooLarge(String), TabSizeTooLarge(String),
TabSizesMustBeAscending, TabSizesMustBeAscending,
@ -85,6 +87,11 @@ impl fmt::Display for ParseError {
specifier.quote(), specifier.quote(),
s.quote(), s.quote(),
), ),
Self::SpecifierOnlyAllowedWithLastValue(specifier) => write!(
f,
"{} specifier only allowed with the last value",
specifier.quote()
),
Self::TabSizeCannotBeZero => write!(f, "tab size cannot be 0"), Self::TabSizeCannotBeZero => write!(f, "tab size cannot be 0"),
Self::TabSizeTooLarge(s) => write!(f, "tab stop is too large {}", s.quote()), Self::TabSizeTooLarge(s) => write!(f, "tab stop is too large {}", s.quote()),
Self::TabSizesMustBeAscending => write!(f, "tab sizes must be ascending"), Self::TabSizesMustBeAscending => write!(f, "tab sizes must be ascending"),
@ -112,6 +119,7 @@ fn tabstops_parse(s: &str) -> Result<(RemainingMode, Vec<usize>), ParseError> {
let mut nums = vec![]; let mut nums = vec![];
let mut remaining_mode = RemainingMode::None; let mut remaining_mode = RemainingMode::None;
let mut is_specifier_already_used = false;
for word in s.split(is_space_or_comma) { for word in s.split(is_space_or_comma) {
let bytes = word.as_bytes(); let bytes = word.as_bytes();
for i in 0..bytes.len() { for i in 0..bytes.len() {
@ -139,6 +147,19 @@ fn tabstops_parse(s: &str) -> Result<(RemainingMode, Vec<usize>), ParseError> {
} }
} }
if is_specifier_already_used {
let specifier = if remaining_mode == RemainingMode::Slash {
"/".to_string()
} else {
"+".to_string()
};
return Err(ParseError::SpecifierOnlyAllowedWithLastValue(
specifier,
));
} else if remaining_mode != RemainingMode::None {
is_specifier_already_used = true;
}
// Append this tab stop to the list of all tabstops. // Append this tab stop to the list of all tabstops.
nums.push(num); nums.push(num);
break; break;

View file

@ -226,6 +226,24 @@ fn test_tabs_with_specifier_not_at_start() {
run_cmd("--tabs=1+2", "+", "+2"); run_cmd("--tabs=1+2", "+", "+2");
} }
#[test]
fn test_tabs_with_specifier_only_allowed_with_last_value() {
fn run_cmd(arg: &str, specifier: &str) {
let expected_msg = format!(
"{} specifier only allowed with the last value",
specifier.quote()
);
new_ucmd!().arg(arg).fails().stderr_contains(expected_msg);
}
run_cmd("--tabs=/1,2,3", "/");
run_cmd("--tabs=1,/2,3", "/");
new_ucmd!().arg("--tabs=1,2,/3").succeeds();
run_cmd("--tabs=+1,2,3", "+");
run_cmd("--tabs=1,+2,3", "+");
new_ucmd!().arg("--tabs=1,2,+3").succeeds();
}
#[test] #[test]
fn test_tabs_with_invalid_chars() { fn test_tabs_with_invalid_chars() {
new_ucmd!() new_ucmd!()