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

Merge pull request #4260 from sbentmar/expand-fix-perl-failures

expand: improve plus specifier handling
This commit is contained in:
Sylvestre Ledru 2023-01-28 18:15:08 +01:00 committed by GitHub
commit efc70ade68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 14 deletions

View file

@ -126,12 +126,8 @@ fn tabstops_parse(s: &str) -> Result<(RemainingMode, Vec<usize>), ParseError> {
let bytes = word.as_bytes(); let bytes = word.as_bytes();
for i in 0..bytes.len() { for i in 0..bytes.len() {
match bytes[i] { match bytes[i] {
b'+' => { b'+' => remaining_mode = RemainingMode::Plus,
remaining_mode = RemainingMode::Plus; b'/' => remaining_mode = RemainingMode::Slash,
}
b'/' => {
remaining_mode = RemainingMode::Slash;
}
_ => { _ => {
// Parse a number from the byte sequence. // Parse a number from the byte sequence.
let s = from_utf8(&bytes[i..]).unwrap(); let s = from_utf8(&bytes[i..]).unwrap();
@ -191,6 +187,10 @@ fn tabstops_parse(s: &str) -> Result<(RemainingMode, Vec<usize>), ParseError> {
if nums.is_empty() { if nums.is_empty() {
nums = vec![DEFAULT_TABSTOP]; nums = vec![DEFAULT_TABSTOP];
} }
if nums.len() < 2 {
remaining_mode = RemainingMode::None;
}
Ok((remaining_mode, nums)) Ok((remaining_mode, nums))
} }
@ -336,17 +336,19 @@ fn open(path: &str) -> BufReader<Box<dyn Read + 'static>> {
/// in the `tabstops` slice is interpreted as a relative number of /// in the `tabstops` slice is interpreted as a relative number of
/// spaces, which this function will return for every input value of /// spaces, which this function will return for every input value of
/// `col` beyond the end of the second-to-last element of `tabstops`. /// `col` beyond the end of the second-to-last element of `tabstops`.
///
/// If `remaining_mode` is [`RemainingMode::Plus`], then the last entry
/// in the `tabstops` slice is interpreted as a relative number of
/// spaces, which this function will return for every input value of
/// `col` beyond the end of the second-to-last element of `tabstops`.
fn next_tabstop(tabstops: &[usize], col: usize, remaining_mode: &RemainingMode) -> usize { fn next_tabstop(tabstops: &[usize], col: usize, remaining_mode: &RemainingMode) -> usize {
let num_tabstops = tabstops.len(); let num_tabstops = tabstops.len();
match remaining_mode { match remaining_mode {
RemainingMode::Plus => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) { RemainingMode::Plus => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) {
Some(t) => t - col, Some(t) => t - col,
None => tabstops[num_tabstops - 1] - 1, None => {
let step_size = tabstops[num_tabstops - 1];
let last_fixed_tabstop = tabstops[num_tabstops - 2];
let characters_since_last_tabstop = col - last_fixed_tabstop;
let steps_required = 1 + characters_since_last_tabstop / step_size;
steps_required * step_size - characters_since_last_tabstop
}
}, },
RemainingMode::Slash => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) { RemainingMode::Slash => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) {
Some(t) => t - col, Some(t) => t - col,
@ -487,8 +489,8 @@ mod tests {
#[test] #[test]
fn test_next_tabstop_remaining_mode_plus() { fn test_next_tabstop_remaining_mode_plus() {
assert_eq!(next_tabstop(&[1, 5], 0, &RemainingMode::Plus), 1); assert_eq!(next_tabstop(&[1, 5], 0, &RemainingMode::Plus), 1);
assert_eq!(next_tabstop(&[1, 5], 3, &RemainingMode::Plus), 4); assert_eq!(next_tabstop(&[1, 5], 3, &RemainingMode::Plus), 3);
assert_eq!(next_tabstop(&[1, 5], 6, &RemainingMode::Plus), 4); assert_eq!(next_tabstop(&[1, 5], 6, &RemainingMode::Plus), 5);
} }
#[test] #[test]

View file

@ -298,3 +298,93 @@ fn test_tabs_and_tabs_shortcut_mixed() {
// 01234567890 // 01234567890
.stdout_is(" a b c"); .stdout_is(" a b c");
} }
#[test]
fn test_ignore_initial_plus() {
new_ucmd!()
.args(&["--tabs=+3"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_ignore_initial_pluses() {
new_ucmd!()
.args(&["--tabs=++3"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_ignore_initial_slash() {
new_ucmd!()
.args(&["--tabs=/3"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_ignore_initial_slashes() {
new_ucmd!()
.args(&["--tabs=//3"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_ignore_initial_plus_slash_combination() {
new_ucmd!()
.args(&["--tabs=+/3"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_comma_with_plus_1() {
new_ucmd!()
.args(&["--tabs=3,+6"])
.pipe_in("\t111\t222\t333")
.succeeds()
// 01234567890
.stdout_is(" 111 222 333");
}
#[test]
fn test_comma_with_plus_2() {
new_ucmd!()
.args(&["--tabs=1,+5"])
.pipe_in("\ta\tb\tc")
.succeeds()
// 01234567890
.stdout_is(" a b c");
}
#[test]
fn test_comma_with_plus_3() {
new_ucmd!()
.args(&["--tabs=2,+5"])
.pipe_in("a\tb\tc")
.succeeds()
// 01234567890
.stdout_is("a b c");
}
#[test]
fn test_comma_with_plus_4() {
new_ucmd!()
.args(&["--tabs=1,3,+5"])
.pipe_in("a\tb\tc")
.succeeds()
// 01234567890
.stdout_is("a b c");
}