vim: Fix cursor shape after deactivation (#42834)

Lennart and dino created

Update the `Vim.deactivate` method to ensure that the cursor shape is
reset to the one available in the user's settings, in the `cursor_shape`
setting, instead of simply defaulting to `CursorShape::Bar`.

In order to test this behavior, the `Editor.cursor_shape` method was
also introduced.

Release Notes:

- Fixed the cursor shape reset in vim mode deactivation, ensuring that
the user's `cursor_shape` setting is used

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>

Change summary

crates/editor/src/editor.rs |  4 ++++
crates/vim/src/test.rs      | 26 +++++++++++++++++++++++++-
crates/vim/src/vim.rs       |  7 ++++++-
3 files changed, 35 insertions(+), 2 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -3025,6 +3025,10 @@ impl Editor {
         cx.notify();
     }
 
+    pub fn cursor_shape(&self) -> CursorShape {
+        self.cursor_shape
+    }
+
     pub fn set_current_line_highlight(
         &mut self,
         current_line_highlight: Option<CurrentLineHighlight>,

crates/vim/src/test.rs 🔗

@@ -16,7 +16,7 @@ use editor::{
 use futures::StreamExt;
 use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext, px};
 use itertools::Itertools;
-use language::{Language, LanguageConfig, Point};
+use language::{CursorShape, Language, LanguageConfig, Point};
 pub use neovim_backed_test_context::*;
 use settings::SettingsStore;
 use ui::Pixels;
@@ -2404,3 +2404,27 @@ async fn test_repeat_grouping_41735(cx: &mut gpui::TestAppContext) {
     cx.simulate_shared_keystrokes("u").await;
     cx.shared_state().await.assert_eq("ˇaaa");
 }
+
+#[gpui::test]
+async fn test_deactivate(cx: &mut gpui::TestAppContext) {
+    let mut cx = VimTestContext::new(cx, true).await;
+
+    cx.update_global(|store: &mut SettingsStore, cx| {
+        store.update_user_settings(cx, |settings| {
+            settings.editor.cursor_shape = Some(settings::CursorShape::Underline);
+        });
+    });
+
+    // Assert that, while in `Normal` mode, the cursor shape is `Block` but,
+    // after deactivating vim mode, it should revert to the one specified in the
+    // user's settings, if set.
+    cx.update_editor(|editor, _window, _cx| {
+        assert_eq!(editor.cursor_shape(), CursorShape::Block);
+    });
+
+    cx.disable_vim();
+
+    cx.update_editor(|editor, _window, _cx| {
+        assert_eq!(editor.cursor_shape(), CursorShape::Underline);
+    });
+}

crates/vim/src/vim.rs 🔗

@@ -954,7 +954,12 @@ impl Vim {
     }
 
     fn deactivate(editor: &mut Editor, cx: &mut Context<Editor>) {
-        editor.set_cursor_shape(CursorShape::Bar, cx);
+        editor.set_cursor_shape(
+            EditorSettings::get_global(cx)
+                .cursor_shape
+                .unwrap_or_default(),
+            cx,
+        );
         editor.set_clip_at_line_ends(false, cx);
         editor.set_collapse_matches(false);
         editor.set_input_enabled(true);