From 79d9e3cc38ad19b3085c26df3eee84ddb5692751 Mon Sep 17 00:00:00 2001 From: tidely <43219534+tidely@users.noreply.github.com> Date: Fri, 22 Aug 2025 12:24:02 +0300 Subject: [PATCH 1/3] fix search history --- crates/search/src/buffer_search.rs | 91 ++++++++++++++++++----------- crates/search/src/project_search.rs | 2 +- crates/vim/src/command.rs | 1 + crates/vim/src/normal/search.rs | 10 ++-- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index a38dc8c35b..5318a40134 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -491,7 +491,7 @@ impl ToolbarItemView for BufferSearchBar { let is_project_search = searchable_item_handle.supported_options(cx).find_in_results; self.active_searchable_item = Some(searchable_item_handle); - drop(self.update_matches(true, window, cx)); + drop(self.update_matches(true, false, window, cx)); if !self.dismissed { if is_project_search { self.dismiss(&Default::default(), window, cx); @@ -778,9 +778,9 @@ impl BufferSearchBar { } pub fn search_suggested(&mut self, window: &mut Window, cx: &mut Context) { - let search = self - .query_suggestion(window, cx) - .map(|suggestion| self.search(&suggestion, Some(self.default_options), window, cx)); + let search = self.query_suggestion(window, cx).map(|suggestion| { + self.search(&suggestion, Some(self.default_options), true, window, cx) + }); if let Some(search) = search { cx.spawn_in(window, async move |this, cx| { @@ -855,6 +855,7 @@ impl BufferSearchBar { &mut self, query: &str, options: Option, + add_to_history: bool, window: &mut Window, cx: &mut Context, ) -> oneshot::Receiver<()> { @@ -871,7 +872,7 @@ impl BufferSearchBar { self.clear_matches(window, cx); cx.notify(); } - self.update_matches(!updated, window, cx) + self.update_matches(!updated, add_to_history, window, cx) } pub fn focus_editor(&mut self, _: &FocusEditor, window: &mut Window, cx: &mut Context) { @@ -889,7 +890,7 @@ impl BufferSearchBar { ) { self.search_options.toggle(search_option); self.default_options = self.search_options; - drop(self.update_matches(false, window, cx)); + drop(self.update_matches(false, false, window, cx)); self.adjust_query_regex_language(cx); cx.notify(); } @@ -1033,7 +1034,7 @@ impl BufferSearchBar { editor::EditorEvent::Edited { .. } => { self.smartcase(window, cx); self.clear_matches(window, cx); - let search = self.update_matches(false, window, cx); + let search = self.update_matches(false, true, window, cx); let width = editor.update(cx, |editor, cx| { let text_layout_details = editor.text_layout_details(window); @@ -1078,7 +1079,7 @@ impl BufferSearchBar { ) { match event { SearchEvent::MatchesInvalidated => { - drop(self.update_matches(false, window, cx)); + drop(self.update_matches(false, false, window, cx)); } SearchEvent::ActiveMatchChanged => self.update_match_index(window, cx), } @@ -1111,7 +1112,7 @@ impl BufferSearchBar { if let Some(active_item) = self.active_searchable_item.as_mut() { self.selection_search_enabled = !self.selection_search_enabled; active_item.toggle_filtered_search_ranges(self.selection_search_enabled, window, cx); - drop(self.update_matches(false, window, cx)); + drop(self.update_matches(false, false, window, cx)); cx.notify(); } } @@ -1154,6 +1155,7 @@ impl BufferSearchBar { fn update_matches( &mut self, reuse_existing_query: bool, + add_to_history: bool, window: &mut Window, cx: &mut Context, ) -> oneshot::Receiver<()> { @@ -1234,8 +1236,10 @@ impl BufferSearchBar { .insert(active_searchable_item.downgrade(), matches); this.update_match_index(window, cx); - this.search_history - .add(&mut this.search_history_cursor, query_text); + if add_to_history { + this.search_history + .add(&mut this.search_history_cursor, query_text); + } if !this.dismissed { let matches = this .searchable_items_with_matches @@ -1324,10 +1328,10 @@ impl BufferSearchBar { .next(&mut self.search_history_cursor) .map(str::to_string) { - drop(self.search(&new_query, Some(self.search_options), window, cx)); + drop(self.search(&new_query, Some(self.search_options), false, window, cx)); } else { self.search_history_cursor.reset(); - drop(self.search("", Some(self.search_options), window, cx)); + drop(self.search("", Some(self.search_options), false, window, cx)); } } @@ -1343,7 +1347,7 @@ impl BufferSearchBar { .current(&self.search_history_cursor) .map(str::to_string) { - drop(self.search(&new_query, Some(self.search_options), window, cx)); + drop(self.search(&new_query, Some(self.search_options), false, window, cx)); return; } @@ -1352,7 +1356,7 @@ impl BufferSearchBar { .previous(&mut self.search_history_cursor) .map(str::to_string) { - drop(self.search(&new_query, Some(self.search_options), window, cx)); + drop(self.search(&new_query, Some(self.search_options), false, window, cx)); } } @@ -1541,7 +1545,7 @@ mod tests { // By default, search is case-insensitive. search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("us", None, window, cx) + search_bar.search("us", None, true, window, cx) }) .await .unwrap(); @@ -1572,7 +1576,7 @@ mod tests { // within other words. By default, all results are found. search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("or", None, window, cx) + search_bar.search("or", None, true, window, cx) }) .await .unwrap(); @@ -1816,7 +1820,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { search_bar.show(window, cx); - search_bar.search("us", Some(SearchOptions::CASE_SENSITIVE), window, cx) + search_bar.search("us", Some(SearchOptions::CASE_SENSITIVE), true, window, cx) }) .await .unwrap(); @@ -1836,7 +1840,13 @@ mod tests { // toggling a search option should update the defaults search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("regex", Some(SearchOptions::CASE_SENSITIVE), window, cx) + search_bar.search( + "regex", + Some(SearchOptions::CASE_SENSITIVE), + true, + window, + cx, + ) }) .await .unwrap(); @@ -1897,7 +1907,7 @@ mod tests { window .update(cx, |_, window, cx| { search_bar.update(cx, |search_bar, cx| { - search_bar.search("a", None, window, cx) + search_bar.search("a", None, true, window, cx) }) }) .unwrap() @@ -2039,7 +2049,7 @@ mod tests { search_bar.update(cx, |search_bar, cx| { let handle = search_bar.query_editor.focus_handle(cx); window.focus(&handle); - search_bar.search("abas_nonexistent_match", None, window, cx) + search_bar.search("abas_nonexistent_match", None, true, window, cx) }) }) .unwrap() @@ -2107,6 +2117,7 @@ mod tests { search_bar.search( "edit\\(", Some(SearchOptions::WHOLE_WORD | SearchOptions::REGEX), + true, window, cx, ) @@ -2132,6 +2143,7 @@ mod tests { search_bar.search( "edit(", Some(SearchOptions::WHOLE_WORD | SearchOptions::CASE_SENSITIVE), + true, window, cx, ) @@ -2179,19 +2191,19 @@ mod tests { // Add 3 search items into the history. search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("a", None, window, cx) + search_bar.search("a", None, true, window, cx) }) .await .unwrap(); search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("b", None, window, cx) + search_bar.search("b", None, true, window, cx) }) .await .unwrap(); search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("c", Some(SearchOptions::CASE_SENSITIVE), window, cx) + search_bar.search("c", Some(SearchOptions::CASE_SENSITIVE), true, window, cx) }) .await .unwrap(); @@ -2262,7 +2274,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("ba", None, window, cx) + search_bar.search("ba", None, true, window, cx) }) .await .unwrap(); @@ -2315,7 +2327,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("expression", None, window, cx) + search_bar.search("expression", None, true, window, cx) }) .await .unwrap(); @@ -2341,7 +2353,7 @@ mod tests { // Search for word boundaries and replace just a single one. search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("or", Some(SearchOptions::WHOLE_WORD), window, cx) + search_bar.search("or", Some(SearchOptions::WHOLE_WORD), true, window, cx) }) .await .unwrap(); @@ -2366,7 +2378,13 @@ mod tests { // Let's turn on regex mode. search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("\\[([^\\]]+)\\]", Some(SearchOptions::REGEX), window, cx) + search_bar.search( + "\\[([^\\]]+)\\]", + Some(SearchOptions::REGEX), + true, + window, + cx, + ) }) .await .unwrap(); @@ -2392,6 +2410,7 @@ mod tests { search_bar.search( "a\\w+s", Some(SearchOptions::REGEX | SearchOptions::WHOLE_WORD), + true, window, cx, ) @@ -2436,7 +2455,13 @@ mod tests { if let Some(options) = options.search_options { search_bar.set_search_options(options, cx); } - search_bar.search(options.search_text, options.search_options, window, cx) + search_bar.search( + options.search_text, + options.search_options, + true, + window, + cx, + ) }) .await .unwrap(); @@ -2575,7 +2600,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("aaa", None, window, cx) + search_bar.search("aaa", None, true, window, cx) }) .await .unwrap(); @@ -2661,7 +2686,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("aaa", None, window, cx) + search_bar.search("aaa", None, true, window, cx) }) .await .unwrap(); @@ -2685,7 +2710,7 @@ mod tests { search_bar .update_in(cx, |search_bar, window, cx| { search_bar.enable_search_option(SearchOptions::REGEX, window, cx); - search_bar.search("expression", None, window, cx) + search_bar.search("expression", None, true, window, cx) }) .await .unwrap(); @@ -2702,7 +2727,7 @@ mod tests { // Now, the expression is invalid search_bar .update_in(cx, |search_bar, window, cx| { - search_bar.search("expression (", None, window, cx) + search_bar.search("expression (", None, true, window, cx) }) .await .unwrap_err(); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index c4ba9b5154..9f8cc2b8ed 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -4100,7 +4100,7 @@ pub mod tests { buffer_search_bar .update_in(&mut cx, |buffer_search_bar, window, cx| { buffer_search_bar.focus_handle(cx).focus(window); - buffer_search_bar.search(buffer_search_query, None, window, cx) + buffer_search_bar.search(buffer_search_query, None, true, window, cx) }) .await .unwrap(); diff --git a/crates/vim/src/command.rs b/crates/vim/src/command.rs index b57c916db9..489f1a5633 100644 --- a/crates/vim/src/command.rs +++ b/crates/vim/src/command.rs @@ -1586,6 +1586,7 @@ impl OnMatchingLines { let _ = search_bar.search( &last_pattern, Some(SearchOptions::REGEX | SearchOptions::CASE_SENSITIVE), + true, window, cx, ); diff --git a/crates/vim/src/normal/search.rs b/crates/vim/src/normal/search.rs index 4fbeec7236..c7a60d2971 100644 --- a/crates/vim/src/normal/search.rs +++ b/crates/vim/src/normal/search.rs @@ -357,12 +357,12 @@ impl Vim { .query_suggestion(window, cx) .or_else(|| cursor_word) else { - drop(search_bar.search("", None, window, cx)); + drop(search_bar.search("", None, true, window, cx)); return None; }; let query = regex::escape(&query); - Some(search_bar.search(&query, Some(options), window, cx)) + Some(search_bar.search(&query, Some(options), true, window, cx)) }); let Some(search) = search else { return false }; @@ -422,7 +422,7 @@ impl Vim { ); } - Some(search_bar.search(&query, Some(options), window, cx)) + Some(search_bar.search(&query, Some(options), true, window, cx)) }); let Some(search) = search else { return }; let search_bar = search_bar.downgrade(); @@ -506,7 +506,7 @@ impl Vim { if replacement.flag_c { search_bar.focus_replace(window, cx); } - Some(search_bar.search(&search, Some(options), window, cx)) + Some(search_bar.search(&search, Some(options), true, window, cx)) }); if replacement.flag_n { self.move_cursor( @@ -531,7 +531,7 @@ impl Vim { search_bar.select_last_match(window, cx); search_bar.replace_all(&Default::default(), window, cx); editor.update(cx, |editor, cx| editor.clear_search_within_ranges(cx)); - let _ = search_bar.search(&search_bar.query(cx), None, window, cx); + let _ = search_bar.search(&search_bar.query(cx), None, true, window, cx); vim.update(cx, |vim, cx| { vim.move_cursor( Motion::StartOfLine { From ed5464c9b71853737bb97999d9d5029784b87b3b Mon Sep 17 00:00:00 2001 From: tidely <43219534+tidely@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:26:11 +0300 Subject: [PATCH 2/3] use init_test --- crates/search/src/buffer_search.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 5318a40134..b96106366d 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -2167,26 +2167,7 @@ mod tests { #[gpui::test] async fn test_search_query_history(cx: &mut TestAppContext) { - init_globals(cx); - let buffer_text = r#" - A regular expression (shortened as regex or regexp;[1] also referred to as - rational expression[2][3]) is a sequence of characters that specifies a search - pattern in text. Usually such patterns are used by string-searching algorithms - for "find" or "find and replace" operations on strings, or for input validation. - "# - .unindent(); - let buffer = cx.new(|cx| Buffer::local(buffer_text, cx)); - let cx = cx.add_empty_window(); - - let editor = - cx.new_window_entity(|window, cx| Editor::for_buffer(buffer.clone(), None, window, cx)); - - let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(None, window, cx); - search_bar.set_active_pane_item(Some(&editor), window, cx); - search_bar.show(window, cx); - search_bar - }); + let (_editor, search_bar, cx) = init_test(cx); // Add 3 search items into the history. search_bar From 91e5690ac990f3434c10f4ba2bfa23ad8378eb8e Mon Sep 17 00:00:00 2001 From: tidely <43219534+tidely@users.noreply.github.com> Date: Mon, 25 Aug 2025 07:44:26 +0300 Subject: [PATCH 3/3] fix testing for search history --- crates/search/src/buffer_search.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index b96106366d..2f9a1f30a9 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -2198,6 +2198,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.next_history_query(&NextHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), ""); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2205,6 +2206,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.next_history_query(&NextHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), ""); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2214,6 +2216,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.previous_history_query(&PreviousHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), "c"); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2223,6 +2226,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.previous_history_query(&PreviousHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), "b"); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2232,6 +2236,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.previous_history_query(&PreviousHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), "a"); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2239,6 +2244,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.previous_history_query(&PreviousHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), "a"); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE); @@ -2248,6 +2254,7 @@ mod tests { search_bar.update_in(cx, |search_bar, window, cx| { search_bar.next_history_query(&NextHistoryQuery, window, cx); }); + cx.run_until_parked(); search_bar.update(cx, |search_bar, cx| { assert_eq!(search_bar.query(cx), "b"); assert_eq!(search_bar.search_options, SearchOptions::CASE_SENSITIVE);