diff --git a/CHANGELOG.md b/CHANGELOG.md index 967fef0a..b76a1e00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Syntax highlighting for Python files using uv as script runner in shebang #3689 (@janlarres) ## Bugfixes +- Use the last occurrence of numbering and plain flags in combined short arguments, see #3897 (@cuishuang) - Avoid a spurious Cargo manifest error during installation from Git, see #3899 (@rootsec1) - Avoid repeated scans of long lines in Log syntax highlighting, see #3876 (@Matei02355) - Fix `--list-languages` respecting `--paging=never`, see #3828 (@cyphercodes) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 7b738c35..642f8c08 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -85,12 +85,12 @@ impl App { return true; } // Handle combined short flags - // Only count -n if it's the LAST flag in the combined form (so -p doesn't override it) - // or if -p is not present in the combined form + // Only count -n if its last occurrence comes after the last -p, + // or if -p is not present in the combined form. if arg_str.starts_with('-') && !arg_str.starts_with("--") && arg_str.len() > 2 { let chars: Vec = arg_str.chars().skip(1).collect(); - let n_pos = chars.iter().position(|&c| c == 'n'); - let p_pos = chars.iter().position(|&c| c == 'p'); + let n_pos = chars.iter().rposition(|&c| c == 'n'); + let p_pos = chars.iter().rposition(|&c| c == 'p'); // -n is in the combined flag and either: // - -p is not present, OR // - -n comes after -p (so -n takes effect) @@ -112,11 +112,11 @@ impl App { if arg_str == "-b" || arg_str == "--number-nonblank" { return true; } - // Handle combined short flags + // Handle combined short flags by comparing the last -b and -p occurrences. if arg_str.starts_with('-') && !arg_str.starts_with("--") && arg_str.len() > 2 { let chars: Vec = arg_str.chars().skip(1).collect(); - let b_pos = chars.iter().position(|&c| c == 'b'); - let p_pos = chars.iter().position(|&c| c == 'p'); + let b_pos = chars.iter().rposition(|&c| c == 'b'); + let p_pos = chars.iter().rposition(|&c| c == 'p'); if let Some(b) = b_pos { if p_pos.is_none() || b > p_pos.unwrap() { return true; diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index ceec7867..260097e9 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -213,6 +213,43 @@ fn numbers_honored_from_cli_when_preceeded_by_plain_in_loop_through_mode() { .stdout(" 1 line 1\n 2 line 2\n 3 line 3\n 4 line 4\n 5 line 5\n 6 line 6\n 7 line 7\n 8 line 8\n 9 line 9\n 10 line 10\n"); } +#[test] +fn repeated_combined_flags_use_last_number_or_plain_flag() { + bat() + .arg("multiline.txt") + .arg("-npn") + .arg("--decorations=auto") + .assert() + .success() + .stdout(" 1 line 1\n 2 line 2\n 3 line 3\n 4 line 4\n 5 line 5\n 6 line 6\n 7 line 7\n 8 line 8\n 9 line 9\n 10 line 10\n"); + + bat() + .arg("multiline.txt") + .arg("-pnp") + .arg("--decorations=auto") + .assert() + .success() + .stdout( + "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\n", + ); + + bat() + .arg("empty_lines.txt") + .arg("-pbp") + .arg("--decorations=auto") + .assert() + .success() + .stdout("line 1\n\n\n\nline 5\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nline 20\nline 21\n\n\nline 24\n\nline 26\n\n\n\nline 30\n"); + + bat() + .arg("empty_lines.txt") + .arg("-bpb") + .arg("--decorations=auto") + .assert() + .success() + .stdout(" 1 line 1\n \n \n \n 2 line 5\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n 3 line 20\n 4 line 21\n \n \n 5 line 24\n \n 6 line 26\n \n \n \n 7 line 30\n"); +} + #[test] fn number_nonblank_style() { bat()