From 00a516abc78f54fe16ec820e58613bd8ac394d44 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 26 May 2025 08:58:59 +0000 Subject: Fix search for fullwidth chars in the last column This fixes an issue for fullwidth characters where the `WRAPLINE` flag would be checked for the cell containing the wide character, ignoring the spacer after it. To work around this, the wrapline character is now always checked based on the cell *after* fullwidth expansion, instead of the original cell. Closes #8586. --- CHANGELOG.md | 1 + alacritty_terminal/src/term/search.rs | 62 +++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0ff67ec..e5f9b215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its - `glyph_offset.y` not applied to strikeout - `Enter`,`Tab`, `Backspace` not disambiguated with `shift` in kitty keyboard's disambiguate mode - Hint bindings not respecting IPC overrides +- Search matching a wrapping fullwidth character in the last column ## 0.15.1 diff --git a/alacritty_terminal/src/term/search.rs b/alacritty_terminal/src/term/search.rs index 20a427b7..d8babd92 100644 --- a/alacritty_terminal/src/term/search.rs +++ b/alacritty_terminal/src/term/search.rs @@ -298,8 +298,8 @@ impl Term { let mut cell = iter.cell(); self.skip_fullwidth(&mut iter, &mut cell, regex.direction); - let mut last_wrapped = cell.flags.contains(Flags::WRAPLINE); let mut c = cell.c; + let mut last_wrapped = iter.cell().flags.contains(Flags::WRAPLINE); let mut point = iter.point(); let mut last_point = point; @@ -401,8 +401,8 @@ impl Term { self.skip_fullwidth(&mut iter, &mut cell, regex.direction); - let wrapped = cell.flags.contains(Flags::WRAPLINE); c = cell.c; + let wrapped = iter.cell().flags.contains(Flags::WRAPLINE); last_point = mem::replace(&mut point, iter.point()); @@ -1190,4 +1190,62 @@ mod tests { assert_eq!(start, Point::new(Line(0), Column(6))); assert_eq!(end, Point::new(Line(0), Column(6))); } + + #[test] + fn fullwidth_across_lines() { + let term = mock_term("a🦇\n🦇b"); + + let mut regex = RegexSearch::new("🦇🦇").unwrap(); + let start = Point::new(Line(0), Column(0)); + let end = Point::new(Line(1), Column(2)); + let match_start = Point::new(Line(0), Column(1)); + let match_end = Point::new(Line(1), Column(1)); + assert_eq!(term.regex_search_right(&mut regex, start, end), Some(match_start..=match_end)); + + let mut regex = RegexSearch::new("🦇🦇").unwrap(); + let start = Point::new(Line(1), Column(2)); + let end = Point::new(Line(0), Column(0)); + let match_start = Point::new(Line(1), Column(1)); + let match_end = Point::new(Line(0), Column(1)); + assert_eq!(term.regex_search_left(&mut regex, start, end), Some(match_end..=match_start)); + } + + #[test] + fn fullwidth_into_halfwidth_across_lines() { + let term = mock_term("a🦇\nxab"); + + let mut regex = RegexSearch::new("🦇x").unwrap(); + let start = Point::new(Line(0), Column(0)); + let end = Point::new(Line(1), Column(2)); + let match_start = Point::new(Line(0), Column(1)); + let match_end = Point::new(Line(1), Column(0)); + assert_eq!(term.regex_search_right(&mut regex, start, end), Some(match_start..=match_end)); + + let mut regex = RegexSearch::new("🦇x").unwrap(); + let start = Point::new(Line(1), Column(2)); + let end = Point::new(Line(0), Column(0)); + let match_start = Point::new(Line(1), Column(0)); + let match_end = Point::new(Line(0), Column(1)); + assert_eq!(term.regex_search_left(&mut regex, start, end), Some(match_end..=match_start)); + } + + #[test] + fn no_spacer_fullwidth_linewrap() { + let mut term = mock_term("abY\nxab"); + term.grid_mut()[Line(0)][Column(2)].c = '🦇'; + + let mut regex = RegexSearch::new("🦇x").unwrap(); + let start = Point::new(Line(0), Column(0)); + let end = Point::new(Line(1), Column(2)); + let match_start = Point::new(Line(0), Column(2)); + let match_end = Point::new(Line(1), Column(0)); + assert_eq!(term.regex_search_right(&mut regex, start, end), Some(match_start..=match_end)); + + let mut regex = RegexSearch::new("🦇x").unwrap(); + let start = Point::new(Line(1), Column(2)); + let end = Point::new(Line(0), Column(0)); + let match_start = Point::new(Line(1), Column(0)); + let match_end = Point::new(Line(0), Column(2)); + assert_eq!(term.regex_search_left(&mut regex, start, end), Some(match_end..=match_start)); + } } -- cgit