Merge pull request #4015 from mikehasa/fix/track-strikethrough-sgr9

Track strikethrough (SGR 9) so it is not dropped across highlighted tokens
This commit is contained in:
Keith Hall authored and GitHub committed 2026-09-22 21:13:30 +03:00
commit 4987f76709
3 files changed
+49 -3

No files matched your search

+1
View File
@@ -25,6 +25,7 @@
- Syntax highlighting for Python files using uv as script runner in shebang #3689 (@janlarres)
## Bugfixes
- Track strikethrough (SGR 9 / 29) in the ANSI style tracker so it is re-emitted like bold, dim, italic, and underline, and is no longer dropped after the first highlighted token when displaying ANSI input with syntax highlighting, see #4015 (@mikehasa)
- Allow boolean flags to be given more than once, so that a flag set in the config file can also be passed on the command line without erroring, see #3912 (@logarithmone1128)
- Use parsed CLI arguments to detect number flags, see #3908 (@cuishuang)
- Detect binary content beyond the first line, preventing encrypted files with early line breaks from being treated as text. Closes #3554, see #3877 (@Matei02355)
+29 -3
View File
@@ -173,8 +173,10 @@ impl Attributes {
2 => self.dim = "\x1B[2m".to_owned(),
3 => self.italic = "\x1B[3m".to_owned(),
4 => self.underline = "\x1B[4m".to_owned(),
9 => self.strike = "\x1B[9m".to_owned(),
23 => self.italic.clear(),
24 => self.underline.clear(),
29 => self.strike.clear(),
22 => {
self.bold.clear();
self.dim.clear();
@@ -1112,10 +1114,10 @@ mod tests {
fn test_sgr_attributes_do_not_leak_into_wrong_field() {
let mut attrs = crate::vscreen::Attributes::new();
// Bold, Dim, Italic, Underline, Foreground, Background
// Bold, Dim, Italic, Underline, Strike, Foreground, Background
attrs.update(EscapeSequence::CSI {
raw_sequence: "\x1B[1;2;3;4;31;41m",
parameters: "1;2;3;4;31;41",
raw_sequence: "\x1B[1;2;3;4;9;31;41m",
parameters: "1;2;3;4;9;31;41",
intermediates: "",
final_byte: "m",
});
@@ -1124,6 +1126,7 @@ mod tests {
assert_eq!(attrs.dim, "\x1B[2m");
assert_eq!(attrs.italic, "\x1B[3m");
assert_eq!(attrs.underline, "\x1B[4m");
assert_eq!(attrs.strike, "\x1B[9m");
assert_eq!(attrs.foreground, "\x1B[31m");
assert_eq!(attrs.background, "\x1B[41m");
@@ -1140,4 +1143,27 @@ mod tests {
assert_eq!(attrs.foreground, "\x1B[94m");
assert_eq!(attrs.background, "\x1B[103m");
}
#[test]
fn test_sgr_strike_is_tracked_and_cleared() {
let mut attrs = crate::vscreen::Attributes::new();
// Strikethrough on (SGR 9) must be tracked so it can be re-emitted.
attrs.update(EscapeSequence::CSI {
raw_sequence: "\x1B[9m",
parameters: "9",
intermediates: "",
final_byte: "m",
});
assert_eq!(attrs.strike, "\x1B[9m");
// Strikethrough off (SGR 29) must clear it, just like italic (23) and underline (24).
attrs.update(EscapeSequence::CSI {
raw_sequence: "\x1B[29m",
parameters: "29",
intermediates: "",
final_byte: "m",
});
assert_eq!(attrs.strike, "");
}
}
+19
View File
@@ -3355,6 +3355,25 @@ fn ansi_sgr_joins_attributes_when_wrapped() {
.stderr("");
}
// Ensure that strikethrough (SGR 9) is tracked like the other attributes, so it is
// re-emitted (and therefore preserved) across a wrap boundary instead of being dropped.
#[test]
fn ansi_sgr_strike_joins_attributes_when_wrapped() {
bat()
.arg("--paging=never")
.arg("--color=never")
.arg("--terminal-width=20")
.arg("--wrap=character")
.arg("--decorations=always")
.arg("--style=plain")
.write_stdin("\x1B[33mColor. \x1B[9mStrike.......Struck+color.\n")
.assert()
.success()
.stdout("\x1B[33m\x1B[33mColor. \x1B[9m\x1B[33m\x1B[9mStrike.......\n\x1B[33m\x1B[9mStruck+color.\n")
// FIXME: ~~~~~~~~ ~~~~~~~~~~~~~~~ should not be emitted twice.
.stderr("");
}
#[test]
fn ignored_suffix_arg() {
bat()