Hide breadcrumbs when project search has no results

Antonio Scandurra created

Change summary

crates/breadcrumbs/src/breadcrumbs.rs | 50 ++++++++++++++++++++++++----
crates/search/src/buffer_search.rs    | 12 +++++-
crates/search/src/project_search.rs   |  4 ++
crates/workspace/src/toolbar.rs       |  9 +++-
4 files changed, 61 insertions(+), 14 deletions(-)

Detailed changes

crates/breadcrumbs/src/breadcrumbs.rs 🔗

@@ -8,16 +8,22 @@ use std::borrow::Cow;
 use theme::SyntaxTheme;
 use workspace::{ItemHandle, Settings, ToolbarItemLocation, ToolbarItemView};
 
+pub enum Event {
+    UpdateLocation,
+}
+
 pub struct Breadcrumbs {
     editor: Option<ViewHandle<Editor>>,
-    editor_subscription: Option<Subscription>,
+    project_search: Option<ViewHandle<ProjectSearchView>>,
+    subscriptions: Vec<Subscription>,
 }
 
 impl Breadcrumbs {
     pub fn new() -> Self {
         Self {
             editor: Default::default(),
-            editor_subscription: Default::default(),
+            subscriptions: Default::default(),
+            project_search: Default::default(),
         }
     }
 
@@ -42,7 +48,7 @@ impl Breadcrumbs {
 }
 
 impl Entity for Breadcrumbs {
-    type Event = ();
+    type Event = Event;
 }
 
 impl View for Breadcrumbs {
@@ -90,19 +96,30 @@ impl ToolbarItemView for Breadcrumbs {
         cx: &mut ViewContext<Self>,
     ) -> ToolbarItemLocation {
         cx.notify();
-        self.editor_subscription = None;
+        self.subscriptions.clear();
         self.editor = None;
+        self.project_search = None;
         if let Some(item) = active_pane_item {
             if let Some(editor) = item.act_as::<Editor>(cx) {
-                self.editor_subscription =
-                    Some(cx.subscribe(&editor, |_, _, event, cx| match event {
+                self.subscriptions
+                    .push(cx.subscribe(&editor, |_, _, event, cx| match event {
                         editor::Event::BufferEdited => cx.notify(),
                         editor::Event::SelectionsChanged { local } if *local => cx.notify(),
                         _ => {}
                     }));
                 self.editor = Some(editor);
-                if item.downcast::<ProjectSearchView>().is_some() {
-                    ToolbarItemLocation::Secondary
+                if let Some(project_search) = item.downcast::<ProjectSearchView>() {
+                    self.subscriptions
+                        .push(cx.subscribe(&project_search, |_, _, _, cx| {
+                            cx.emit(Event::UpdateLocation);
+                        }));
+                    self.project_search = Some(project_search.clone());
+
+                    if project_search.read(cx).has_matches() {
+                        ToolbarItemLocation::Secondary
+                    } else {
+                        ToolbarItemLocation::Hidden
+                    }
                 } else {
                     ToolbarItemLocation::PrimaryLeft
                 }
@@ -113,4 +130,21 @@ impl ToolbarItemView for Breadcrumbs {
             ToolbarItemLocation::Hidden
         }
     }
+
+    fn location_for_event(
+        &self,
+        _: &Event,
+        current_location: ToolbarItemLocation,
+        cx: &AppContext,
+    ) -> ToolbarItemLocation {
+        if let Some(project_search) = self.project_search.as_ref() {
+            if project_search.read(cx).has_matches() {
+                ToolbarItemLocation::Secondary
+            } else {
+                ToolbarItemLocation::Hidden
+            }
+        } else {
+            current_location
+        }
+    }
 }

crates/search/src/buffer_search.rs 🔗

@@ -2,8 +2,9 @@ use crate::{active_match_index, match_index_for_direction, Direction, SearchOpti
 use collections::HashMap;
 use editor::{display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor};
 use gpui::{
-    action, elements::*, keymap::Binding, platform::CursorStyle, Entity, MutableAppContext,
-    RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    action, elements::*, keymap::Binding, platform::CursorStyle, AppContext, Entity,
+    MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use language::OffsetRangeExt;
 use project::search::SearchQuery;
@@ -164,7 +165,12 @@ impl ToolbarItemView for BufferSearchBar {
         ToolbarItemLocation::Hidden
     }
 
-    fn location_for_event(&self, _: &Self::Event, _: ToolbarItemLocation) -> ToolbarItemLocation {
+    fn location_for_event(
+        &self,
+        _: &Self::Event,
+        _: ToolbarItemLocation,
+        _: &AppContext,
+    ) -> ToolbarItemLocation {
         if self.active_editor.is_some() && !self.dismissed {
             ToolbarItemLocation::Secondary
         } else {

crates/search/src/project_search.rs 🔗

@@ -487,6 +487,10 @@ impl ProjectSearchView {
             cx.notify();
         }
     }
+
+    pub fn has_matches(&self) -> bool {
+        self.active_match_index.is_some()
+    }
 }
 
 impl ProjectSearchBar {

crates/workspace/src/toolbar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{ItemHandle, Settings};
 use gpui::{
-    elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, View,
-    ViewContext, ViewHandle,
+    elements::*, AnyViewHandle, AppContext, ElementBox, Entity, MutableAppContext, RenderContext,
+    View, ViewContext, ViewHandle,
 };
 
 pub trait ToolbarItemView: View {
@@ -15,6 +15,7 @@ pub trait ToolbarItemView: View {
         &self,
         _event: &Self::Event,
         current_location: ToolbarItemLocation,
+        _cx: &AppContext,
     ) -> ToolbarItemLocation {
         current_location
     }
@@ -121,7 +122,9 @@ impl Toolbar {
             if let Some((_, current_location)) =
                 this.items.iter_mut().find(|(i, _)| i.id() == item.id())
             {
-                let new_location = item.read(cx).location_for_event(event, *current_location);
+                let new_location = item
+                    .read(cx)
+                    .location_for_event(event, *current_location, cx);
                 if new_location != *current_location {
                     *current_location = new_location;
                     cx.notify();