When searching in visual mode switch to normal mode (#4178)

This matches Neovim behaviour by setting the mode to `Normal` when using
search while in visual mode.

Release Notes:

- Fixed Vim mode not switching to normal mode from visual mode when
using search (`/`) while in visual mode.
This commit is contained in:
Thorsten Ball 2024-01-21 08:42:47 +01:00 committed by GitHub
commit 29e74a648f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 4 deletions

View File

@ -73,9 +73,7 @@ impl KeystrokeMatcher {
if !found_actions.is_empty() { if !found_actions.is_empty() {
self.pending_keystrokes.clear(); self.pending_keystrokes.clear();
return KeyMatch::Some(found_actions); return KeyMatch::Some(found_actions);
} } else if let Some(pending_key) = pending_key {
if let Some(pending_key) = pending_key {
self.pending_keystrokes.push(pending_key); self.pending_keystrokes.push(pending_key);
KeyMatch::Pending KeyMatch::Pending
} else { } else {

View File

@ -3,7 +3,12 @@ use search::{buffer_search, BufferSearchBar, SearchMode, SearchOptions};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use workspace::{searchable::Direction, Workspace}; use workspace::{searchable::Direction, Workspace};
use crate::{motion::Motion, normal::move_cursor, state::SearchState, Vim}; use crate::{
motion::Motion,
normal::move_cursor,
state::{Mode, SearchState},
Vim,
};
#[derive(Clone, Deserialize, PartialEq)] #[derive(Clone, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -145,6 +150,7 @@ pub fn move_to_internal(
Vim::update(cx, |vim, cx| { Vim::update(cx, |vim, cx| {
let pane = workspace.active_pane().clone(); let pane = workspace.active_pane().clone();
let count = vim.take_count(cx).unwrap_or(1); let count = vim.take_count(cx).unwrap_or(1);
pane.update(cx, |pane, cx| { pane.update(cx, |pane, cx| {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() { if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
let search = search_bar.update(cx, |search_bar, cx| { let search = search_bar.update(cx, |search_bar, cx| {
@ -176,6 +182,11 @@ pub fn move_to_internal(
} }
} }
}); });
if vim.state().mode.is_visual() {
vim.switch_mode(Mode::Normal, false, cx)
}
vim.clear_operator(cx); vim.clear_operator(cx);
}); });
} }
@ -465,6 +476,13 @@ mod test {
cx.simulate_keystrokes(["/", "b"]); cx.simulate_keystrokes(["/", "b"]);
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes(["enter"]);
cx.assert_state("aa\nˇbb\ndd\ncc\nbb\n", Mode::Normal); cx.assert_state("aa\nˇbb\ndd\ncc\nbb\n", Mode::Normal);
// check that searching switches to normal mode if in visual mode
cx.set_state("ˇone two one", Mode::Normal);
cx.simulate_keystrokes(["v", "l", "l"]);
cx.assert_editor_state("«oneˇ» two one");
cx.simulate_keystrokes(["*"]);
cx.assert_state("one two ˇone", Mode::Normal);
} }
#[gpui::test] #[gpui::test]
@ -488,5 +506,6 @@ mod test {
cx.set_shared_state("ˇa.c. abcd a.c. abcd").await; cx.set_shared_state("ˇa.c. abcd a.c. abcd").await;
cx.simulate_shared_keystrokes(["v", "3", "l", "*"]).await; cx.simulate_shared_keystrokes(["v", "3", "l", "*"]).await;
cx.assert_shared_state("a.c. abcd ˇa.c. abcd").await; cx.assert_shared_state("a.c. abcd ˇa.c. abcd").await;
cx.assert_shared_mode(Mode::Normal).await;
} }
} }

View File

@ -277,6 +277,24 @@ impl NeovimBackedTestContext {
self.neovim.mode().await.unwrap() self.neovim.mode().await.unwrap()
} }
pub async fn assert_shared_mode(&mut self, mode: Mode) {
let neovim = self.neovim_mode().await;
let editor = self.cx.mode();
if neovim != mode || editor != mode {
panic!(
indoc! {"Test failed (zed does not match nvim behaviour)
# desired mode:
{:?}
# neovim mode:
{:?}
# zed mode:
{:?}"},
mode, neovim, editor,
)
}
}
pub async fn assert_state_matches(&mut self) { pub async fn assert_state_matches(&mut self) {
self.is_dirty = false; self.is_dirty = false;
let neovim = self.neovim_state().await; let neovim = self.neovim_state().await;