From aafecf043a78530825a7524f7c7cacdd0c173cc6 Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Sun, 1 Feb 2026 23:17:19 +0800 Subject: [PATCH] vim: Respect search settings in buffer search (#48127) Closes https://github.com/zed-industries/zed/issues/48007 Release Notes: - Fixed Vim search not respecting `"search"` default settings --------- Signed-off-by: Xiaobo Liu --- crates/vim/src/normal/search.rs | 119 +++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 9 deletions(-) diff --git a/crates/vim/src/normal/search.rs b/crates/vim/src/normal/search.rs index c11784d163e18451129656aa92d23dba568bd723..75043703ed7497db0d042b8c268d351b51d11ea2 100644 --- a/crates/vim/src/normal/search.rs +++ b/crates/vim/src/normal/search.rs @@ -75,8 +75,8 @@ pub(crate) struct SearchUnderCursorPrevious { pub(crate) struct Search { #[serde(default)] backwards: bool, - #[serde(default = "default_true")] - regex: bool, + #[serde(default)] + regex: Option, } /// Executes a find command to search for patterns in the buffer. @@ -244,16 +244,13 @@ impl Vim { cx.focus_self(window); search_bar.set_replacement(None, cx); - let mut options = SearchOptions::NONE; - if action.regex { - options |= SearchOptions::REGEX; + let mut options = SearchOptions::from_settings(&EditorSettings::get_global(cx).search); + if let Some(regex) = action.regex { + options.set(SearchOptions::REGEX, regex); } if action.backwards { options |= SearchOptions::BACKWARDS; } - if EditorSettings::get_global(cx).search.case_sensitive { - options |= SearchOptions::CASE_SENSITIVE; - } search_bar.set_search_options(options, cx); true }); @@ -756,7 +753,7 @@ mod test { use editor::{DisplayPoint, display_map::DisplayRow}; use indoc::indoc; - use search::BufferSearchBar; + use search::{self, BufferSearchBar}; use settings::SettingsStore; #[gpui::test] @@ -1405,4 +1402,108 @@ mod test { // The cursor should be at the match location on line 3 (row 2). cx.assert_state("hello world\nfoo bar\nhello ˇagain\n", Mode::Normal); } + + #[gpui::test] + async fn test_vim_search_respects_search_settings(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + // Test 1: Verify that search settings are respected when opening vim search + // Set search settings: regex=false, whole_word=true, case_sensitive=true + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings(cx, |settings| { + settings.editor.search = Some(settings::SearchSettingsContent { + button: Some(true), + whole_word: Some(true), + case_sensitive: Some(true), + include_ignored: Some(false), + regex: Some(false), + center_on_match: Some(false), + }); + }); + }); + + cx.set_state("ˇhello Hello HELLO helloworld", Mode::Normal); + cx.simulate_keystrokes("/"); + cx.run_until_parked(); + + // Verify search options are set from settings + let search_bar = cx.workspace(|workspace, _, cx| { + workspace + .active_pane() + .read(cx) + .toolbar() + .read(cx) + .item_of_type::() + .expect("Buffer search bar should be deployed") + }); + + cx.update_entity(search_bar, |bar, _window, _cx| { + // Should have WHOLE_WORD and CASE_SENSITIVE from settings + assert!( + bar.has_search_option(search::SearchOptions::WHOLE_WORD), + "whole_word setting should be respected" + ); + assert!( + bar.has_search_option(search::SearchOptions::CASE_SENSITIVE), + "case_sensitive setting should be respected" + ); + // Should NOT have REGEX since we set regex=false + assert!( + !bar.has_search_option(search::SearchOptions::REGEX), + "regex=false setting should be respected" + ); + }); + + // Dismiss and test with different settings + cx.simulate_keystrokes("escape"); + cx.run_until_parked(); + + // Test 2: Change settings to regex=true, whole_word=false + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings(cx, |settings| { + settings.editor.search = Some(settings::SearchSettingsContent { + button: Some(true), + whole_word: Some(false), + case_sensitive: Some(false), + include_ignored: Some(true), + regex: Some(true), + center_on_match: Some(false), + }); + }); + }); + + cx.simulate_keystrokes("/"); + cx.run_until_parked(); + + let search_bar = cx.workspace(|workspace, _, cx| { + workspace + .active_pane() + .read(cx) + .toolbar() + .read(cx) + .item_of_type::() + .expect("Buffer search bar should be deployed") + }); + + cx.update_entity(search_bar, |bar, _window, _cx| { + // Should have REGEX and INCLUDE_IGNORED from settings + assert!( + bar.has_search_option(search::SearchOptions::REGEX), + "regex=true setting should be respected" + ); + assert!( + bar.has_search_option(search::SearchOptions::INCLUDE_IGNORED), + "include_ignored=true setting should be respected" + ); + // Should NOT have WHOLE_WORD or CASE_SENSITIVE + assert!( + !bar.has_search_option(search::SearchOptions::WHOLE_WORD), + "whole_word=false setting should be respected" + ); + assert!( + !bar.has_search_option(search::SearchOptions::CASE_SENSITIVE), + "case_sensitive=false setting should be respected" + ); + }); + } }