vim: Fix n/N and */# selecting text after cmd+f search (#54027)

The cmd_f_search flag introduced in #51073 was never cleared when
switching to vim-style search commands, causing collapse_matches to
remain false and match ranges to appear as visual selections.

Reset cmd_f_search when n/N or */# are used, restore Normal mode if
Visual was entered due to the non-collapsed selection, and fix an early
return in visual select_match that leaked collapse_matches.

Fixes #53896

Self-Review Checklist:

- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable

Closes #ISSUE

Release Notes:

- N/A or Added/Fixed/Improved ...

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
LiberandConrad Irwin authored and GitHub committed 2026-05-20 03:39:36 +00:00
1 parent e2c38b5358
commit 068d64edd6
2 files changed
+61

No files matched your search

+58
View File
@@ -389,6 +389,15 @@ impl Vim {
};
let count = Vim::take_count(cx).unwrap_or(1);
Vim::take_forced_motion(cx);
if self.search.cmd_f_search {
self.search.cmd_f_search = false;
if self.mode.is_visual() {
self.switch_mode(Mode::Normal, false, window, cx);
}
self.sync_vim_settings(window, cx);
}
let prior_selections = self.editor_selections(window, cx);
let success = pane.update(cx, |pane, cx| {
@@ -433,6 +442,15 @@ impl Vim {
};
let count = Vim::take_count(cx).unwrap_or(1);
Vim::take_forced_motion(cx);
if self.search.cmd_f_search {
self.search.cmd_f_search = false;
if self.mode.is_visual() {
self.switch_mode(Mode::Normal, false, window, cx);
}
self.sync_vim_settings(window, cx);
}
let prior_selections = self.editor_selections(window, cx);
let vim = cx.entity();
@@ -1017,6 +1035,46 @@ mod test {
cx.assert_state("one «oneˇ» one one", Mode::Insert);
}
#[gpui::test]
async fn test_n_after_cmd_f_search(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇone two one two one", Mode::Normal);
cx.run_until_parked();
// Use cmd+f to search (non-vim style)
cx.simulate_keystrokes("cmd-f");
cx.run_until_parked();
cx.simulate_keystrokes("escape");
cx.run_until_parked();
// Now use n to go to next match — should move cursor, not create selection
cx.simulate_keystrokes("n");
cx.run_until_parked();
cx.assert_state("one two ˇone two one", Mode::Normal);
cx.simulate_keystrokes("n");
cx.run_until_parked();
cx.assert_state("one two one two ˇone", Mode::Normal);
}
#[gpui::test]
async fn test_star_after_cmd_f_search(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇone two one two one", Mode::Normal);
cx.run_until_parked();
// Use cmd+f to search (non-vim style)
cx.simulate_keystrokes("cmd-f");
cx.run_until_parked();
cx.simulate_keystrokes("escape");
cx.run_until_parked();
// Now use * to search under cursor — should move cursor, not create selection
cx.simulate_keystrokes("*");
cx.run_until_parked();
cx.assert_state("one two ˇone two one", Mode::Normal);
}
#[gpui::test]
async fn test_visual_star_hash(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
+3
View File
@@ -897,6 +897,9 @@ impl Vim {
}
});
if !match_exists {
self.update_editor(cx, |_, editor, _| {
editor.set_collapse_matches(true);
});
self.clear_operator(window, cx);
self.stop_replaying(cx);
return;