From 86b9b3f81dc7fbeeef37aa8e259dc4498e67f9fc Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Fri, 22 Nov 2024 01:07:08 +0000 Subject: Fix vi motion with wide semantic escape chars This patch fixes an issue where the semantic vi motion commands `SemanticRight` and `SemanticLeft` were not behaving as expected when a fullwidth character was used as a semantic character. Closes #8314. --- CHANGELOG.md | 1 + alacritty_terminal/src/term/mod.rs | 5 ++++ alacritty_terminal/src/vi_mode.rs | 49 +++++++++++++++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd4e7d55..dce7fa97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its - Mouse/Vi cursor hint highlighting broken on the terminal cursor line - Hint launcher opening arbitrary text, when terminal content changed while opening +- `SemanticRight`/`SemanticLeft` vi motions breaking with wide semantic escape characters ## 0.14.0 diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 1f1e52c1..c2d77ec7 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -930,6 +930,11 @@ impl Term { &self.config.semantic_escape_chars } + #[cfg(test)] + pub(crate) fn set_semantic_escape_chars(&mut self, semantic_escape_chars: &str) { + self.config.semantic_escape_chars = semantic_escape_chars.into(); + } + /// Active terminal cursor style. /// /// While vi mode is active, this will automatically return the vi mode cursor style. diff --git a/alacritty_terminal/src/vi_mode.rs b/alacritty_terminal/src/vi_mode.rs index 7065544e..e23e9b80 100644 --- a/alacritty_terminal/src/vi_mode.rs +++ b/alacritty_terminal/src/vi_mode.rs @@ -265,14 +265,14 @@ fn semantic( } }; - // Make sure we jump above wide chars. - point = term.expand_wide(point, direction); - // Move to word boundary. if direction != side && !is_boundary(term, point, direction) { point = expand_semantic(point); } + // Make sure we jump above wide chars. + point = term.expand_wide(point, direction); + // Skip whitespace. let mut next_point = advance(term, point, direction); while !is_boundary(term, point, direction) && is_space(term, next_point) { @@ -283,6 +283,11 @@ fn semantic( // Assure minimum movement of one cell. if !is_boundary(term, point, direction) { point = advance(term, point, direction); + + // Skip over wide cell spacers. + if direction == Direction::Left { + point = term.expand_wide(point, direction); + } } // Move to word boundary. @@ -820,4 +825,42 @@ mod tests { cursor = cursor.scroll(&term, -20); assert_eq!(cursor.point, Point::new(Line(19), Column(0))); } + + #[test] + fn wide_semantic_char() { + let mut term = term(); + term.set_semantic_escape_chars("-"); + term.grid_mut()[Line(0)][Column(0)].c = 'x'; + term.grid_mut()[Line(0)][Column(1)].c = 'x'; + term.grid_mut()[Line(0)][Column(2)].c = '-'; + term.grid_mut()[Line(0)][Column(2)].flags.insert(Flags::WIDE_CHAR); + term.grid_mut()[Line(0)][Column(3)].c = ' '; + term.grid_mut()[Line(0)][Column(3)].flags.insert(Flags::WIDE_CHAR_SPACER); + term.grid_mut()[Line(0)][Column(4)].c = 'x'; + term.grid_mut()[Line(0)][Column(5)].c = 'x'; + + // Test motion to the right. + + let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(0))); + cursor = cursor.motion(&mut term, ViMotion::SemanticRight); + assert_eq!(cursor.point, Point::new(Line(0), Column(2))); + + let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(2))); + cursor = cursor.motion(&mut term, ViMotion::SemanticRight); + assert_eq!(cursor.point, Point::new(Line(0), Column(4))); + + // Test motion to the left. + + let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(5))); + cursor = cursor.motion(&mut term, ViMotion::SemanticLeft); + assert_eq!(cursor.point, Point::new(Line(0), Column(4))); + + let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(4))); + cursor = cursor.motion(&mut term, ViMotion::SemanticLeft); + assert_eq!(cursor.point, Point::new(Line(0), Column(2))); + + let mut cursor = ViModeCursor::new(Point::new(Line(0), Column(2))); + cursor = cursor.motion(&mut term, ViMotion::SemanticLeft); + assert_eq!(cursor.point, Point::new(Line(0), Column(0))); + } } -- cgit v1.2.3-54-g00ecf