vim: Fix some problems with visual mode testing (#8461)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/vim/src/mode_indicator.rs                  | 11 ++------
crates/vim/src/object.rs                          | 17 ++++++++----
crates/vim/src/state.rs                           | 14 ++++++++++
crates/vim/src/test/neovim_backed_test_context.rs | 22 +++++++++++-----
crates/vim/src/test/neovim_connection.rs          |  2 
crates/vim/src/visual.rs                          |  2 -
6 files changed, 43 insertions(+), 25 deletions(-)

Detailed changes

crates/vim/src/mode_indicator.rs 🔗

@@ -41,14 +41,9 @@ impl Render for ModeIndicator {
             return div().into_any();
         };
 
-        let text = match mode {
-            Mode::Normal => "-- NORMAL --",
-            Mode::Insert => "-- INSERT --",
-            Mode::Visual => "-- VISUAL --",
-            Mode::VisualLine => "-- VISUAL LINE --",
-            Mode::VisualBlock => "-- VISUAL BLOCK --",
-        };
-        Label::new(text).size(LabelSize::Small).into_any_element()
+        Label::new(format!("-- {} --", mode))
+            .size(LabelSize::Small)
+            .into_any_element()
     }
 }
 

crates/vim/src/object.rs 🔗

@@ -131,17 +131,22 @@ impl Object {
 
     pub fn target_visual_mode(self, current_mode: Mode) -> Mode {
         match self {
-            Object::Word { .. } if current_mode == Mode::VisualLine => Mode::Visual,
-            Object::Word { .. } => current_mode,
-            Object::Sentence
+            Object::Word { .. }
+            | Object::Sentence
             | Object::Quotes
             | Object::BackQuotes
-            | Object::DoubleQuotes
-            | Object::VerticalBars
-            | Object::Parentheses
+            | Object::DoubleQuotes => {
+                if current_mode == Mode::VisualBlock {
+                    Mode::VisualBlock
+                } else {
+                    Mode::Visual
+                }
+            }
+            Object::Parentheses
             | Object::SquareBrackets
             | Object::CurlyBrackets
             | Object::AngleBrackets
+            | Object::VerticalBars
             | Object::Argument => Mode::Visual,
         }
     }

crates/vim/src/state.rs 🔗

@@ -1,4 +1,4 @@
-use std::{ops::Range, sync::Arc};
+use std::{fmt::Display, ops::Range, sync::Arc};
 
 use collections::HashMap;
 use gpui::{Action, KeyContext};
@@ -17,6 +17,18 @@ pub enum Mode {
     VisualBlock,
 }
 
+impl Display for Mode {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Mode::Normal => write!(f, "NORMAL"),
+            Mode::Insert => write!(f, "INSERT"),
+            Mode::Visual => write!(f, "VISUAL"),
+            Mode::VisualLine => write!(f, "VISUAL LINE"),
+            Mode::VisualBlock => write!(f, "VISUAL BLOCK"),
+        }
+    }
+}
+
 impl Mode {
     pub fn is_visual(&self) -> bool {
         match self {

crates/vim/src/test/neovim_backed_test_context.rs 🔗

@@ -190,8 +190,10 @@ impl NeovimBackedTestContext {
         self.is_dirty = false;
         let marked_text = marked_text.replace("•", " ");
         let neovim = self.neovim_state().await;
+        let neovim_mode = self.neovim_mode().await;
         let editor = self.editor_state();
-        if neovim == marked_text && neovim == editor {
+        let editor_mode = self.mode();
+        if neovim == marked_text && neovim == editor && neovim_mode == editor_mode {
             return;
         }
         let initial_state = self
@@ -213,16 +215,18 @@ impl NeovimBackedTestContext {
                 {}
                 # currently expected:
                 {}
-                # neovim state:
+                # neovim ({}):
                 {}
-                # zed state:
+                # zed ({}):
                 {}"},
             message,
             initial_state,
             self.recent_keystrokes.join(" "),
             marked_text.replace(" \n", "•\n"),
+            neovim_mode,
             neovim.replace(" \n", "•\n"),
-            editor.replace(" \n", "•\n")
+            editor_mode,
+            editor.replace(" \n", "•\n"),
         )
     }
 
@@ -296,27 +300,31 @@ impl NeovimBackedTestContext {
     pub async fn assert_state_matches(&mut self) {
         self.is_dirty = false;
         let neovim = self.neovim_state().await;
+        let neovim_mode = self.neovim_mode().await;
         let editor = self.editor_state();
+        let editor_mode = self.mode();
         let initial_state = self
             .last_set_state
             .as_ref()
             .unwrap_or(&"N/A".to_string())
             .clone();
 
-        if neovim != editor {
+        if neovim != editor || neovim_mode != editor_mode {
             panic!(
                 indoc! {"Test failed (zed does not match nvim behaviour)
                     # initial state:
                     {}
                     # keystrokes:
                     {}
-                    # neovim state:
+                    # neovim ({}):
                     {}
-                    # zed state:
+                    # zed ({}):
                     {}"},
                 initial_state,
                 self.recent_keystrokes.join(" "),
+                neovim_mode,
                 neovim,
+                editor_mode,
                 editor,
             )
         }

crates/vim/src/test/neovim_connection.rs 🔗

@@ -419,7 +419,7 @@ impl NeovimConnection {
                 }
             }
             Some(Mode::Visual) | Some(Mode::VisualLine) | Some(Mode::VisualBlock) => {
-                if selection_col > cursor_col {
+                if (selection_row, selection_col) > (cursor_row, cursor_col) {
                     let selection_line_length =
                         self.read_position("echo strlen(getline(line('v')))").await;
                     if selection_line_length > selection_col {

crates/vim/src/visual.rs 🔗

@@ -1005,7 +1005,6 @@ mod test {
         cx.simulate_shared_keystrokes(["ctrl-v", "l"]).await;
         cx.simulate_shared_keystrokes(["a", "]"]).await;
         cx.assert_shared_state("hello (in «[parens]ˇ» o)").await;
-        assert_eq!(cx.mode(), Mode::Visual);
         cx.simulate_shared_keystrokes(["i", "("]).await;
         cx.assert_shared_state("hello («in [parens] oˇ»)").await;
 
@@ -1016,7 +1015,6 @@ mod test {
         assert_eq!(cx.mode(), Mode::VisualBlock);
         cx.simulate_shared_keystrokes(["o", "a", "s"]).await;
         cx.assert_shared_state("«ˇhello in a word» again.").await;
-        assert_eq!(cx.mode(), Mode::Visual);
     }
 
     #[gpui::test]