Add a setting for when to seed the search query from the text under the cursor

Max Brunsfeld created

Change summary

assets/settings/default.json          | 10 ++++++
crates/editor/src/editor_settings.rs  | 12 +++++++
crates/editor/src/items.rs            | 40 ++++++++++++++-------------
crates/editor2/src/editor_settings.rs | 10 ++++++
crates/editor2/src/items.rs           | 42 +++++++++++++++-------------
5 files changed, 75 insertions(+), 39 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -102,6 +102,16 @@
     "selections": true
   },
   "relative_line_numbers": false,
+  // When to populate a new search's query based on the text under the cursor.
+  // This setting can take the following three values:
+  //
+  // 1. Always populate the search query with the word under the cursor (default).
+  //    "always"
+  // 2. Only populate the search query when there is text selected
+  //    "selection"
+  // 3. Never populate the search query
+  //    "never"
+  "seed_search_query_from_cursor": "always",
   // Inlay hint related settings
   "inlay_hints": {
     // Global switch to toggle hints on and off, switched off by default.

crates/editor/src/editor_settings.rs 🔗

@@ -2,7 +2,7 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::Setting;
 
-#[derive(Deserialize)]
+#[derive(Clone, Deserialize)]
 pub struct EditorSettings {
     pub cursor_blink: bool,
     pub hover_popover_enabled: bool,
@@ -11,6 +11,15 @@ pub struct EditorSettings {
     pub use_on_type_format: bool,
     pub scrollbar: Scrollbar,
     pub relative_line_numbers: bool,
+    pub seed_search_query_from_cursor: SeedQuerySetting,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum SeedQuerySetting {
+    Always,
+    Selection,
+    Never,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -38,6 +47,7 @@ pub struct EditorSettingsContent {
     pub use_on_type_format: Option<bool>,
     pub scrollbar: Option<ScrollbarContent>,
     pub relative_line_numbers: Option<bool>,
+    pub seed_search_query_from_selection: Option<SeedQuerySetting>,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]

crates/editor/src/items.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
-    link_go_to_definition::hide_link_definition, persistence::DB, scroll::ScrollAnchor, Anchor,
-    Autoscroll, Editor, Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot,
-    NavigationData, ToPoint as _,
+    editor_settings::SeedQuerySetting, link_go_to_definition::hide_link_definition,
+    persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor, EditorSettings, Event,
+    ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,
 };
 use anyhow::{Context, Result};
 use collections::HashSet;
@@ -937,26 +937,28 @@ impl SearchableItem for Editor {
     }
 
     fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
-        let display_map = self.snapshot(cx).display_snapshot;
+        let setting = settings::get::<EditorSettings>(cx).seed_search_query_from_cursor;
+        let snapshot = &self.snapshot(cx).buffer_snapshot;
         let selection = self.selections.newest::<usize>(cx);
-        if selection.start == selection.end {
-            let (range, kind) = display_map
-                .buffer_snapshot
-                .surrounding_word(selection.start);
-            if kind != Some(CharKind::Word) {
-                return String::new();
+
+        match setting {
+            SeedQuerySetting::Never => String::new(),
+            SeedQuerySetting::Selection | SeedQuerySetting::Always if !selection.is_empty() => {
+                snapshot
+                    .text_for_range(selection.start..selection.end)
+                    .collect()
             }
-            let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
-            if text.trim().is_empty() {
+            SeedQuerySetting::Selection => String::new(),
+            SeedQuerySetting::Always => {
+                let (range, kind) = snapshot.surrounding_word(selection.start);
+                if kind == Some(CharKind::Word) {
+                    let text: String = snapshot.text_for_range(range).collect();
+                    if !text.trim().is_empty() {
+                        return text;
+                    }
+                }
                 String::new()
-            } else {
-                text
             }
-        } else {
-            display_map
-                .buffer_snapshot
-                .text_for_range(selection.start..selection.end)
-                .collect()
         }
     }
 

crates/editor2/src/editor_settings.rs 🔗

@@ -11,6 +11,15 @@ pub struct EditorSettings {
     pub use_on_type_format: bool,
     pub scrollbar: Scrollbar,
     pub relative_line_numbers: bool,
+    pub seed_search_query_from_cursor: SeedQuerySetting,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum SeedQuerySetting {
+    Always,
+    Selection,
+    Never,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -38,6 +47,7 @@ pub struct EditorSettingsContent {
     pub use_on_type_format: Option<bool>,
     pub scrollbar: Option<ScrollbarContent>,
     pub relative_line_numbers: Option<bool>,
+    pub seed_search_query_from_selection: Option<SeedQuerySetting>,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]

crates/editor2/src/items.rs 🔗

@@ -1,7 +1,8 @@
 use crate::{
-    link_go_to_definition::hide_link_definition, movement::surrounding_word, persistence::DB,
-    scroll::ScrollAnchor, Anchor, Autoscroll, Editor, Event, ExcerptId, ExcerptRange, MultiBuffer,
-    MultiBufferSnapshot, NavigationData, ToPoint as _,
+    editor_settings::SeedQuerySetting, link_go_to_definition::hide_link_definition,
+    movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor,
+    EditorSettings, Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot,
+    NavigationData, ToPoint as _,
 };
 use anyhow::{anyhow, Context, Result};
 use collections::HashSet;
@@ -17,6 +18,7 @@ use language::{
 };
 use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
 use rpc::proto::{self, update_view, PeerId};
+use settings::Settings;
 use smallvec::SmallVec;
 use std::{
     borrow::Cow,
@@ -918,26 +920,28 @@ impl SearchableItem for Editor {
     }
 
     fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
-        let display_map = self.snapshot(cx).display_snapshot;
+        let setting = EditorSettings::get_global(cx).seed_search_query_from_cursor;
+        let snapshot = &self.snapshot(cx).buffer_snapshot;
         let selection = self.selections.newest::<usize>(cx);
-        if selection.start == selection.end {
-            let (range, kind) = display_map
-                .buffer_snapshot
-                .surrounding_word(selection.start);
-            if kind != Some(CharKind::Word) {
-                return String::new();
+
+        match setting {
+            SeedQuerySetting::Never => String::new(),
+            SeedQuerySetting::Selection | SeedQuerySetting::Always if !selection.is_empty() => {
+                snapshot
+                    .text_for_range(selection.start..selection.end)
+                    .collect()
             }
-            let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
-            if text.trim().is_empty() {
+            SeedQuerySetting::Selection => String::new(),
+            SeedQuerySetting::Always => {
+                let (range, kind) = snapshot.surrounding_word(selection.start);
+                if kind == Some(CharKind::Word) {
+                    let text: String = snapshot.text_for_range(range).collect();
+                    if !text.trim().is_empty() {
+                        return text;
+                    }
+                }
                 String::new()
-            } else {
-                text
             }
-        } else {
-            display_map
-                .buffer_snapshot
-                .text_for_range(selection.start..selection.end)
-                .collect()
         }
     }