Detailed changes
@@ -667,6 +667,8 @@
"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,
},
// When to populate a new search's query based on the text under the cursor.
// This setting can take the following three values:
@@ -175,6 +175,8 @@ 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.
+ pub search_on_input: bool,
}
impl EditorSettings {
@@ -271,6 +273,7 @@ impl Settings for EditorSettings {
include_ignored: search.include_ignored.unwrap(),
regex: search.regex.unwrap(),
center_on_match: search.center_on_match.unwrap(),
+ search_on_input: search.search_on_input.unwrap(),
},
auto_signature_help: editor.auto_signature_help.unwrap(),
show_signature_help_after_edits: editor.show_signature_help_after_edits.unwrap(),
@@ -3421,6 +3421,7 @@ mod tests {
include_ignored: false,
regex: false,
center_on_match: false,
+ search_on_input: false,
},
cx,
);
@@ -3484,6 +3485,7 @@ mod tests {
include_ignored: false,
regex: false,
center_on_match: false,
+ search_on_input: false,
},
cx,
);
@@ -3522,6 +3524,7 @@ mod tests {
include_ignored: false,
regex: false,
center_on_match: false,
+ search_on_input: false,
},
cx,
);
@@ -3604,9 +3607,91 @@ mod tests {
include_ignored: Some(search_settings.include_ignored),
regex: Some(search_settings.regex),
center_on_match: Some(search_settings.center_on_match),
+ search_on_input: Some(search_settings.search_on_input),
});
});
});
});
}
+ #[gpui::test]
+ async fn test_search_on_input_setting(cx: &mut TestAppContext) {
+ let (editor, search_bar, cx) = init_test(cx);
+
+ update_search_settings(
+ SearchSettings {
+ button: true,
+ whole_word: false,
+ case_sensitive: false,
+ include_ignored: false,
+ regex: false,
+ center_on_match: false,
+ search_on_input: false,
+ },
+ cx,
+ );
+
+ search_bar.update_in(cx, |search_bar, window, cx| {
+ search_bar.show(window, cx);
+ search_bar.query_editor.update(cx, |query_editor, cx| {
+ query_editor.buffer().update(cx, |buffer, cx| {
+ buffer.edit(
+ [(MultiBufferOffset(0)..MultiBufferOffset(0), "expression")],
+ None,
+ cx,
+ );
+ });
+ });
+ });
+
+ cx.background_executor.run_until_parked();
+
+ editor.update_in(cx, |editor, window, cx| {
+ let highlights = editor.all_text_background_highlights(window, cx);
+ assert!(
+ highlights.is_empty(),
+ "No highlights should appear when search_on_input is false"
+ );
+ });
+
+ update_search_settings(
+ SearchSettings {
+ button: true,
+ whole_word: false,
+ case_sensitive: false,
+ include_ignored: false,
+ regex: false,
+ center_on_match: false,
+ search_on_input: true,
+ },
+ cx,
+ );
+
+ search_bar.update_in(cx, |search_bar, window, cx| {
+ search_bar.dismiss(&Dismiss, window, cx);
+ search_bar.show(window, cx);
+ });
+
+ search_bar
+ .update_in(cx, |search_bar, window, cx| {
+ search_bar.search("expression", None, true, window, cx)
+ })
+ .await
+ .unwrap();
+
+ editor.update_in(cx, |editor, window, cx| {
+ let highlights = display_points_of(editor.all_text_background_highlights(window, cx));
+ assert_eq!(
+ highlights.len(),
+ 2,
+ "Should find 2 matches for 'expression' when search_on_input is true"
+ );
+ assert_eq!(
+ highlights,
+ &[
+ DisplayPoint::new(DisplayRow(0), 10)..DisplayPoint::new(DisplayRow(0), 20),
+ DisplayPoint::new(DisplayRow(1), 9)..DisplayPoint::new(DisplayRow(1), 19),
+ ]
+ );
+ });
+ }
}
@@ -869,15 +869,32 @@ impl ProjectSearchView {
// Subscribe to query_editor in order to reraise editor events for workspace item activation purposes
subscriptions.push(
cx.subscribe(&query_editor, |this, _, event: &EditorEvent, cx| {
- if let EditorEvent::Edited { .. } = event
- && EditorSettings::get_global(cx).use_smartcase_search
- {
- let query = this.search_query_text(cx);
- if !query.is_empty()
- && this.search_options.contains(SearchOptions::CASE_SENSITIVE)
- != contains_uppercase(&query)
- {
- this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
+ if let EditorEvent::Edited { .. } = event {
+ if EditorSettings::get_global(cx).use_smartcase_search {
+ let query = this.search_query_text(cx);
+ if !query.is_empty()
+ && this.search_options.contains(SearchOptions::CASE_SENSITIVE)
+ != contains_uppercase(&query)
+ {
+ 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
+ this.entity.update(cx, |model, cx| {
+ model.pending_search = None;
+ model.match_ranges.clear();
+ model.excerpts.update(cx, |excerpts, cx| excerpts.clear(cx));
+ model.no_results = None;
+ model.limit_reached = false;
+ cx.notify();
+ });
+ } else {
+ this.search(cx);
+ }
}
}
cx.emit(ViewEvent::EditorEvent(event.clone()))
@@ -1529,7 +1546,11 @@ impl ProjectSearchView {
editor.scroll(Point::default(), Some(Axis::Vertical), window, cx);
}
});
- if is_new_search && self.query_editor.focus_handle(cx).is_focused(window) {
+ let should_auto_focus = !EditorSettings::get_global(cx).search.search_on_input;
+ if is_new_search
+ && self.query_editor.focus_handle(cx).is_focused(window)
+ && should_auto_focus
+ {
self.focus_results_editor(window, cx);
}
}
@@ -1592,9 +1613,13 @@ impl ProjectSearchView {
v_flex()
.gap_1()
.child(
- Label::new("Hit enter to search. For more options:")
- .color(Color::Muted)
- .mb_2(),
+ Label::new(if EditorSettings::get_global(cx).search.search_on_input {
+ "Start typing to search. For more options:"
+ } else {
+ "Hit enter to search. For more options:"
+ })
+ .color(Color::Muted)
+ .mb_2(),
)
.child(
Button::new("filter-paths", "Include/exclude specific paths")
@@ -2537,7 +2562,8 @@ pub mod tests {
use project::FakeFs;
use serde_json::json;
use settings::{
- InlayHintSettingsContent, SettingsStore, ThemeColorsContent, ThemeStyleContent,
+ InlayHintSettingsContent, SearchSettingsContent, SettingsStore, ThemeColorsContent,
+ ThemeStyleContent,
};
use util::{path, paths::PathStyle, rel_path::rel_path};
use util_macros::perf;
@@ -4756,6 +4782,15 @@ pub mod tests {
let settings = SettingsStore::test(cx);
cx.set_global(settings);
+ SettingsStore::update_global(cx, |store, cx| {
+ store.update_user_settings(cx, |settings| {
+ settings.editor.search = Some(SearchSettingsContent {
+ search_on_input: Some(false),
+ ..Default::default()
+ });
+ });
+ });
+
theme::init(theme::LoadThemes::JustBase, cx);
editor::init(cx);
@@ -828,6 +828,8 @@ pub struct SearchSettingsContent {
pub regex: Option<bool>,
/// Whether to center the cursor on each search match when navigating.
pub center_on_match: Option<bool>,
+ /// Whether to search on input.
+ pub search_on_input: Option<bool>,
}
#[with_fallible_options]
@@ -2999,7 +2999,7 @@ fn languages_and_tools_page(cx: &App) -> SettingsPage {
}
fn search_and_files_page() -> SettingsPage {
- fn search_section() -> [SettingsPageItem; 9] {
+ fn search_section() -> [SettingsPageItem; 10] {
[
SettingsPageItem::SectionHeader("Search"),
SettingsPageItem::SettingItem(SettingItem {
@@ -3133,6 +3133,29 @@ fn search_and_files_page() -> SettingsPage {
metadata: None,
files: USER,
}),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Search on Input",
+ description: "Whether to search on input.",
+ field: Box::new(SettingField {
+ json_path: Some("editor.search.search_on_input"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .search
+ .as_ref()
+ .and_then(|search| search.search_on_input.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .search_on_input = 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.",
@@ -3270,6 +3270,12 @@ Non-negative `integer` values
- Setting: `regex`
- Default: `false`
+### Search On Input
+
+- Description: Whether to search on input.
+- Setting: `search_on_input
+- Default: `true`
+
### Center On Match
- Description: Whether to center the cursor on each search match when navigating.
@@ -3282,12 +3288,6 @@ Non-negative `integer` values
- Setting: `search_wrap`
- Default: `true`
-## Center on Match
-
-- Description: If `center_on_match` is enabled, the editor will center the cursor on the current match when searching.
-- Setting: `center_on_match`
-- Default: `false`
-
## Seed Search Query From Cursor
- Description: When to populate a new search's query based on the text under the cursor.