From a0eb63d1affb6e7b7991e477c7e05824d0250255 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 14 Feb 2026 01:20:13 +0200 Subject: [PATCH] Fix search on input behavior (#49150) Follow-up of https://github.com/zed-industries/zed/pull/42889 * disable by default * add a configurable debounce, 200ms default Release Notes: - N/A --- assets/settings/default.json | 7 +++++-- crates/editor/src/editor_settings.rs | 6 +++++- crates/search/src/buffer_search.rs | 8 ++++++++ crates/search/src/project_search.rs | 26 ++++++++++++++++++++------ crates/settings_content/src/editor.rs | 8 +++++++- crates/settings_ui/src/page_data.rs | 27 +++++++++++++++++++++++++-- docs/src/reference/all-settings.md | 12 +++++++++--- 7 files changed, 79 insertions(+), 15 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 111b42cdcc561a046254305662c5bfc2f0916e6e..c3ffa8c0410b4872443dad8c5da261eb2edd3455 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -667,8 +667,11 @@ "regex": false, // Whether to center the cursor on each search match when navigating. "center_on_match": false, - // Whether to search on input. - "search_on_input": true, + // Whether to search on input in project search. + "search_on_input": false, + // Debounce time in milliseconds for search on input in project search. + // Set to 0 to disable debouncing. + "search_on_input_debounce_ms": 200, }, // When to populate a new search's query based on the text under the cursor. // This setting can take the following three values: diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 654a541a699b62fc7fb9d88859ac8845a1dbff61..97df9fdfcd5c7740751131240265fa9e9a2e6cb5 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -175,8 +175,11 @@ pub struct SearchSettings { pub regex: bool, /// Whether to center the cursor on each search match when navigating. pub center_on_match: bool, - /// Whether to search on input. + /// Whether to search on input in project search. pub search_on_input: bool, + /// Debounce time in milliseconds for search on input in project search. + /// Set to 0 to disable debouncing. + pub search_on_input_debounce_ms: u64, } impl EditorSettings { @@ -274,6 +277,7 @@ impl Settings for EditorSettings { regex: search.regex.unwrap(), center_on_match: search.center_on_match.unwrap(), search_on_input: search.search_on_input.unwrap(), + search_on_input_debounce_ms: search.search_on_input_debounce_ms.unwrap(), }, auto_signature_help: editor.auto_signature_help.unwrap(), show_signature_help_after_edits: editor.show_signature_help_after_edits.unwrap(), diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index a8639b70cd75ca38bcafd81e6d4aee9acf6dbc98..e9c9725b53e29a3336c10f57889ed90310f7fa6d 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -3422,6 +3422,7 @@ mod tests { regex: false, center_on_match: false, search_on_input: false, + search_on_input_debounce_ms: 0, }, cx, ); @@ -3486,6 +3487,7 @@ mod tests { regex: false, center_on_match: false, search_on_input: false, + search_on_input_debounce_ms: 0, }, cx, ); @@ -3525,6 +3527,7 @@ mod tests { regex: false, center_on_match: false, search_on_input: false, + search_on_input_debounce_ms: 0, }, cx, ); @@ -3608,6 +3611,9 @@ mod tests { regex: Some(search_settings.regex), center_on_match: Some(search_settings.center_on_match), search_on_input: Some(search_settings.search_on_input), + search_on_input_debounce_ms: Some( + search_settings.search_on_input_debounce_ms, + ), }); }); }); @@ -3626,6 +3632,7 @@ mod tests { regex: false, center_on_match: false, search_on_input: false, + search_on_input_debounce_ms: 0, }, cx, ); @@ -3662,6 +3669,7 @@ mod tests { regex: false, center_on_match: false, search_on_input: true, + search_on_input_debounce_ms: 0, }, cx, ); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index acd6576ce298ef86282cd0e6a6f98cde1d62bfba..81ad9ac3b41baeaef291252be7bde2dd4695b6f2 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -39,6 +39,7 @@ use std::{ ops::{Not, Range}, pin::pin, sync::Arc, + time::Duration, }; use ui::{ CommonAnimationExt, IconButtonShape, KeyBinding, Toggleable, Tooltip, prelude::*, @@ -270,6 +271,7 @@ pub struct ProjectSearchView { included_opened_only: bool, regex_language: Option>, results_collapsed: bool, + current_search_on_input: Task<()>, _subscriptions: Vec, } @@ -879,11 +881,11 @@ impl ProjectSearchView { this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx); } } - // Trigger search on input: - if EditorSettings::get_global(cx).search.search_on_input { - let query = this.search_query_text(cx); - if query.is_empty() { - // Clear results immediately when query is empty and abort ongoing search + + let search_settings = &EditorSettings::get_global(cx).search; + if search_settings.search_on_input { + if this.query_editor.read(cx).is_empty(cx) { + this.current_search_on_input = Task::ready(()); this.entity.update(cx, |model, cx| { model.pending_search = None; model.match_ranges.clear(); @@ -893,7 +895,18 @@ impl ProjectSearchView { cx.notify(); }); } else { - this.search(cx); + let debounce = search_settings.search_on_input_debounce_ms; + this.current_search_on_input = cx.spawn(async move |this, cx| { + if debounce > 0 { + cx.background_executor() + .timer(Duration::from_millis(debounce)) + .await; + } + this.update(cx, |this, cx| { + this.search(cx); + }) + .ok(); + }); } } } @@ -1015,6 +1028,7 @@ impl ProjectSearchView { included_opened_only: false, regex_language: None, results_collapsed: false, + current_search_on_input: Task::ready(()), _subscriptions: subscriptions, }; diff --git a/crates/settings_content/src/editor.rs b/crates/settings_content/src/editor.rs index a2f53e1b9e309e5b07eaef7f7730773abfac70a9..88616e065e31be916b05e81ebef7cb005c0eac13 100644 --- a/crates/settings_content/src/editor.rs +++ b/crates/settings_content/src/editor.rs @@ -828,8 +828,14 @@ pub struct SearchSettingsContent { pub regex: Option, /// Whether to center the cursor on each search match when navigating. pub center_on_match: Option, - /// Whether to search on input. + /// Whether to search on input in project search. pub search_on_input: Option, + /// Debounce time in milliseconds for search on input in project search. + /// + /// Set to 0 to disable debouncing. + /// + /// Default: 200 + pub search_on_input_debounce_ms: Option, } #[with_fallible_options] diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index 0725917fa3d46695f90f7d989e83e9b21052c597..b594c21cfc59e653724475693c1f81676f449747 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -2999,7 +2999,7 @@ fn languages_and_tools_page(cx: &App) -> SettingsPage { } fn search_and_files_page() -> SettingsPage { - fn search_section() -> [SettingsPageItem; 10] { + fn search_section() -> [SettingsPageItem; 11] { [ SettingsPageItem::SectionHeader("Search"), SettingsPageItem::SettingItem(SettingItem { @@ -3135,7 +3135,7 @@ fn search_and_files_page() -> SettingsPage { }), SettingsPageItem::SettingItem(SettingItem { title: "Search on Input", - description: "Whether to search on input.", + description: "Whether to search on input in project search.", field: Box::new(SettingField { json_path: Some("editor.search.search_on_input"), pick: |settings_content| { @@ -3156,6 +3156,29 @@ fn search_and_files_page() -> SettingsPage { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Search on Input Debounce", + description: "Debounce time in milliseconds for search on input (set to 0 to disable debouncing).", + field: Box::new(SettingField { + json_path: Some("editor.search.search_on_input_debounce_ms"), + pick: |settings_content| { + settings_content + .editor + .search + .as_ref() + .and_then(|search| search.search_on_input_debounce_ms.as_ref()) + }, + write: |settings_content, value| { + settings_content + .editor + .search + .get_or_insert_default() + .search_on_input_debounce_ms = value; + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SettingItem(SettingItem { title: "Seed Search Query From Cursor", description: "When to populate a new search's query based on the text under the cursor.", diff --git a/docs/src/reference/all-settings.md b/docs/src/reference/all-settings.md index 56f5b234aef463304874efc16177727196a320fb..f47006a5b904b5999f29c6657d63dc2b4c47a76a 100644 --- a/docs/src/reference/all-settings.md +++ b/docs/src/reference/all-settings.md @@ -3272,9 +3272,15 @@ Non-negative `integer` values ### Search On Input -- Description: Whether to search on input. -- Setting: `search_on_input -- Default: `true` +- Description: Whether to search on input in project search. +- Setting: `search_on_input` +- Default: `false` + +### Search On Input Debounce Ms + +- Description: Debounce time in milliseconds for search on input in project search. Set to 0 to disable debouncing. +- Setting: `search_on_input_debounce_ms` +- Default: `200` ### Center On Match