Prepopulate project search query when deploying it from an editor

Antonio Scandurra created

Change summary

crates/search/src/buffer_search.rs  | 29 +++------------------
crates/search/src/project_search.rs | 41 ++++++++++++++++++++++--------
crates/search/src/search.rs         | 31 +++++++++++++++++++++-
3 files changed, 63 insertions(+), 38 deletions(-)

Detailed changes

crates/search/src/buffer_search.rs 🔗

@@ -1,9 +1,9 @@
 use crate::{
-    active_match_index, match_index_for_direction, Direction, SearchOption, SelectNextMatch,
-    SelectPrevMatch,
+    active_match_index, match_index_for_direction, query_suggestion_for_editor, Direction,
+    SearchOption, SelectNextMatch, SelectPrevMatch,
 };
 use collections::HashMap;
-use editor::{display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor};
+use editor::{Anchor, Autoscroll, Editor};
 use gpui::{
     actions, elements::*, impl_actions, impl_internal_actions, platform::CursorStyle, AppContext,
     Entity, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
@@ -222,28 +222,7 @@ impl BufferSearchBar {
             return false;
         };
 
-        let display_map = editor
-            .update(cx, |editor, cx| editor.snapshot(cx))
-            .display_snapshot;
-        let selection = editor.read(cx).selections.newest::<usize>(cx);
-
-        let mut text: String;
-        if selection.start == selection.end {
-            let point = selection.start.to_display_point(&display_map);
-            let range = editor::movement::surrounding_word(&display_map, point);
-            let range = range.start.to_offset(&display_map, Bias::Left)
-                ..range.end.to_offset(&display_map, Bias::Right);
-            text = display_map.buffer_snapshot.text_for_range(range).collect();
-            if text.trim().is_empty() {
-                text = String::new();
-            }
-        } else {
-            text = display_map
-                .buffer_snapshot
-                .text_for_range(selection.start..selection.end)
-                .collect();
-        }
-
+        let text = query_suggestion_for_editor(&editor, cx);
         if !text.is_empty() {
             self.set_query(&text, cx);
         }

crates/search/src/project_search.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{
-    active_match_index, match_index_for_direction, Direction, SearchOption, SelectNextMatch,
-    SelectPrevMatch, ToggleSearchOption,
+    active_match_index, match_index_for_direction, query_suggestion_for_editor, Direction,
+    SearchOption, SelectNextMatch, SelectPrevMatch, ToggleSearchOption,
 };
 use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll};
@@ -410,18 +410,32 @@ impl ProjectSearchView {
             })
             .or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
 
-        if let Some(existing) = existing {
+        let query = workspace.active_item(cx).and_then(|item| {
+            let editor = item.act_as::<Editor>(cx)?;
+            let query = query_suggestion_for_editor(&editor, cx);
+            if query.is_empty() {
+                None
+            } else {
+                Some(query)
+            }
+        });
+
+        let search = if let Some(existing) = existing {
             workspace.activate_item(&existing, cx);
-            existing.update(cx, |existing, cx| {
-                existing.focus_query_editor(cx);
-            });
+            existing
         } else {
             let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
-            workspace.add_item(
-                Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))),
-                cx,
-            );
-        }
+            let view = cx.add_view(|cx| ProjectSearchView::new(model, cx));
+            workspace.add_item(Box::new(view.clone()), cx);
+            view
+        };
+
+        search.update(cx, |search, cx| {
+            if let Some(query) = query {
+                search.set_query(&query, cx);
+            }
+            search.focus_query_editor(cx)
+        });
     }
 
     fn search(&mut self, cx: &mut ViewContext<Self>) {
@@ -478,6 +492,11 @@ impl ProjectSearchView {
         cx.focus(&self.query_editor);
     }
 
+    fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
+        self.query_editor
+            .update(cx, |query_editor, cx| query_editor.set_text(query, cx));
+    }
+
     fn focus_results_editor(&self, cx: &mut ViewContext<Self>) {
         self.query_editor.update(cx, |query_editor, cx| {
             let cursor = query_editor.selections.newest_anchor().head();

crates/search/src/search.rs 🔗

@@ -1,6 +1,6 @@
 pub use buffer_search::BufferSearchBar;
-use editor::{Anchor, MultiBufferSnapshot};
-use gpui::{actions, impl_internal_actions, MutableAppContext};
+use editor::{display_map::ToDisplayPoint, Anchor, Bias, Editor, MultiBufferSnapshot};
+use gpui::{actions, impl_internal_actions, MutableAppContext, ViewHandle};
 pub use project_search::{ProjectSearchBar, ProjectSearchView};
 use std::{
     cmp::{self, Ordering},
@@ -90,3 +90,30 @@ pub(crate) fn match_index_for_direction(
     };
     index
 }
+
+pub(crate) fn query_suggestion_for_editor(
+    editor: &ViewHandle<Editor>,
+    cx: &mut MutableAppContext,
+) -> String {
+    let display_map = editor
+        .update(cx, |editor, cx| editor.snapshot(cx))
+        .display_snapshot;
+    let selection = editor.read(cx).selections.newest::<usize>(cx);
+    if selection.start == selection.end {
+        let point = selection.start.to_display_point(&display_map);
+        let range = editor::movement::surrounding_word(&display_map, point);
+        let range = range.start.to_offset(&display_map, Bias::Left)
+            ..range.end.to_offset(&display_map, Bias::Right);
+        let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
+        if text.trim().is_empty() {
+            String::new()
+        } else {
+            text
+        }
+    } else {
+        display_map
+            .buffer_snapshot
+            .text_for_range(selection.start..selection.end)
+            .collect()
+    }
+}