aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2024-11-22 01:07:08 +0000
committerGitHub <noreply@github.com>2024-11-22 01:07:08 +0000
commit3ac4904eb5a1cc15cc02b077c118f1ffcb9e6916 (patch)
tree73106c776b9796d4712fa22de356ef9725e2b1c0
parent4f739a7e2b933f6828ebf64654c8a8c573bf0ec1 (diff)
downloadalacritty-3ac4904eb5a1cc15cc02b077c118f1ffcb9e6916.tar.gz
alacritty-3ac4904eb5a1cc15cc02b077c118f1ffcb9e6916.zip
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.
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty_terminal/src/term/mod.rs5
-rw-r--r--alacritty_terminal/src/vi_mode.rs49
3 files changed, 52 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bbe0d2f4..c9faa35c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,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<T> Term<T> {
&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<T: EventListener>(
}
};
- // 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<T: EventListener>(
// 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)));
+ }
}