From 7b8bd97652dd22b8b6c6dc32b58953528ab6d3a8 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Tue, 30 Jan 2024 10:47:39 +0100 Subject: [PATCH] vim: implement in normal mode (#7011) This fixes #6815 by implementing `` in normal mode in Vim. Turns out that `` behaves like a reverse `` (which we already had): it goes to the right and, if at end of line, to the next line. That means I had to touch `movement::right`, which is used in a few places, but it's documentation said that it would go to the next line, which it did *not*. So I changed the behaviour. But I would love another pair of eyes on this, because I don't want to break non-Vim behaviour. Release Notes: - Added support for `` in Vim normal mode: `` goes to the right and to next line if at end of line. ([#6815](https://github.com/zed-industries/zed/issues/6815)). --- assets/keymaps/vim.json | 1 + crates/editor/src/movement.rs | 7 +++---- crates/vim/src/motion.rs | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 2b0ad672b0d1953f185eccc15bd28cac051d0c17..bbf132232f2842c73a17684d002314ab62424c08 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -31,6 +31,7 @@ "up": "vim::Up", "l": "vim::Right", "right": "vim::Right", + "space": "vim::Space", "$": "vim::EndOfLine", "^": "vim::FirstNonWhitespace", "_": "vim::StartOfLineDownward", diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index f268e926c79474006adedf43cfffae48024c7833..fa5e5f1655c6d5da687432596474d2bf2d9e450c 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -50,11 +50,10 @@ pub fn saturating_left(map: &DisplaySnapshot, mut point: DisplayPoint) -> Displa map.clip_point(point, Bias::Left) } -/// Returns a column to the right of the current point, wrapping -/// to the next line if that point is at the end of line. +/// Returns a column to the right of the current point, doing nothing +// if that point is at the end of the line. pub fn right(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { - let max_column = map.line_len(point.row()); - if point.column() < max_column { + if point.column() < map.line_len(point.row()) { *point.column_mut() += 1; } else if point.row() < map.max_point().row() { *point.row_mut() += 1; diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index e8cd21bba3dc4546f1af640263a43971a23a680b..22800b2e9c1839c13f58a9b7dbddb75cdcf82bec 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -23,6 +23,7 @@ pub enum Motion { Down { display_lines: bool }, Up { display_lines: bool }, Right, + Space, NextWordStart { ignore_punctuation: bool }, NextWordEnd { ignore_punctuation: bool }, PreviousWordStart { ignore_punctuation: bool }, @@ -124,6 +125,7 @@ actions!( Left, Backspace, Right, + Space, CurrentLine, StartOfParagraph, EndOfParagraph, @@ -163,6 +165,7 @@ pub fn register(workspace: &mut Workspace, _: &mut ViewContext) { ) }); workspace.register_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx)); + workspace.register_action(|_: &mut Workspace, _: &Space, cx: _| motion(Motion::Space, cx)); workspace.register_action(|_: &mut Workspace, action: &FirstNonWhitespace, cx: _| { motion( Motion::FirstNonWhitespace { @@ -306,6 +309,7 @@ impl Motion { | Left | Backspace | Right + | Space | StartOfLine { .. } | EndOfLineDownward | GoToColumn @@ -332,6 +336,7 @@ impl Motion { | Left | Backspace | Right + | Space | StartOfLine { .. } | StartOfParagraph | EndOfParagraph @@ -370,6 +375,7 @@ impl Motion { Left | Backspace | Right + | Space | StartOfLine { .. } | StartOfLineDownward | StartOfParagraph @@ -412,6 +418,7 @@ impl Motion { display_lines: true, } => up_display(map, point, goal, times, &text_layout_details), Right => (right(map, point, times), SelectionGoal::None), + Space => (space(map, point, times), SelectionGoal::None), NextWordStart { ignore_punctuation } => ( next_word_start(map, point, *ignore_punctuation, times), SelectionGoal::None, @@ -614,6 +621,24 @@ fn backspace(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> Di point } +fn space(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> DisplayPoint { + for _ in 0..times { + point = wrapping_right(map, point); + } + point +} + +fn wrapping_right(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { + let max_column = map.line_len(point.row()).saturating_sub(1); + if point.column() < max_column { + *point.column_mut() += 1; + } else if point.row() < map.max_point().row() { + *point.row_mut() += 1; + *point.column_mut() = 0; + } + point +} + pub(crate) fn start_of_relative_buffer_row( map: &DisplaySnapshot, point: DisplayPoint,