From ec7a8e86fb7607a5bf17f032558c6714cc531d51 Mon Sep 17 00:00:00 2001 From: KyleBarton Date: Wed, 17 Dec 2025 16:55:21 -0800 Subject: [PATCH] First pass at solving search positioning. Good except for buffer search in project search. Co-authored-by: Danilo Leal --- crates/breadcrumbs/src/breadcrumbs.rs | 1 + crates/editor/src/items.rs | 4 +- crates/search/src/buffer_search.rs | 83 ++++++++++++++++++++++++--- crates/workspace/src/toolbar.rs | 5 +- 4 files changed, 82 insertions(+), 11 deletions(-) diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index 33ccb981e222ff21e3cbc69a45581a66c4c8097c..9590e3f01e30e044d9b46c1c6b65869d99a17293 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -42,6 +42,7 @@ impl EventEmitter for Breadcrumbs {} // - Create a wrapping "Breadcrumb" struct for Vec // - Implement render for _that_ breadcrumb struct. // - Call that from here to eliminate much of the logic. +// - This will change the Item interface, so do it only after you're happy with the features thus far impl Render for Breadcrumbs { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { const MAX_SEGMENTS: usize = 12; diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 738a4cff119d847f2828cf4f75e0f4a334679a1f..be426ccc0982d07fd9433244256132a0a203f0c4 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -997,7 +997,9 @@ impl Item for Editor { if self.buffer.read(cx).is_singleton() { self.breadcrumbs_inner(variant, cx) } else { - Some(vec![]) + // Should say: If you're searching, None, else, vec![] -> What that really means is if you're searching, don't render the chevron (search bar will do it for you), otherwise _do_ render the chevron (which is defined as a breadcrumb prefix) + // Some(vec![]) + None } } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 686d385aa07accac168062fa598790b36e80199f..0c488ec6505633ae70f2c9ac144aa877d7711d64 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -1,9 +1,10 @@ mod registrar; use crate::{ - FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOption, - SearchOptions, SearchSource, SelectAllMatches, SelectNextMatch, SelectPreviousMatch, - ToggleCaseSensitive, ToggleRegex, ToggleReplace, ToggleSelection, ToggleWholeWord, + FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ProjectSearchView, ReplaceAll, + ReplaceNext, SearchOption, SearchOptions, SearchSource, SelectAllMatches, SelectNextMatch, + SelectPreviousMatch, ToggleCaseSensitive, ToggleRegex, ToggleReplace, ToggleSelection, + ToggleWholeWord, search_bar::{ActionButtonState, input_base_styles, render_action_button, render_text_input}, }; use any_vec::AnyVec; @@ -27,7 +28,7 @@ use project::{ use schemars::JsonSchema; use serde::Deserialize; use settings::Settings; -use std::sync::Arc; +use std::{any::TypeId, sync::Arc}; use zed_actions::{outline::ToggleOutline, workspace::CopyPath, workspace::CopyRelativePath}; use ui::{ @@ -37,7 +38,7 @@ use ui::{ use util::{ResultExt, paths::PathMatcher}; use workspace::{ ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, - item::ItemHandle, + item::{ItemBufferKind, ItemHandle}, searchable::{ Direction, FilteredSearchRange, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle, }, @@ -401,6 +402,38 @@ impl Render for BufferSearchBar { ))) .w_full() }); + + // let is_collapsed = self.is_multibuffer_collapsed; + // This shouldn't show on a singleton or on a project search + let button = if self.active_item_is_multibuffer(cx) { + let is_collapsed = false; + + let (icon, tooltip_label) = if is_collapsed { + (IconName::ChevronUpDown, "Expand All Search Results") + } else { + (IconName::ChevronDownUp, "Collapse All Search Results") + }; + + let tooltip_focus_handle = focus_handle.clone(); + + // emit_action!(ToggleFoldAll, focus_handle.clone()); + + Some( + IconButton::new("multibuffer-collapse-expand", icon) + .icon_size(IconSize::Small) + // .tooltip(move |_, cx| { + // Tooltip::for_action_in(tooltip_label, &ToggleFoldAll, &tooltip_focus_handle, cx) + // }) + // .on_click(cx.listener(|this, _, window, cx| { + // this.is_multibuffer_collapsed = !this.is_multibuffer_collapsed; + // this.toggle_fold_all(&ToggleFoldAll, window, cx); + // })) + .into_any_element(), + ) + } else { + None + }; + v_flex() .id("buffer_search") .gap_2() @@ -447,9 +480,15 @@ impl Render for BufferSearchBar { .when(selection, |this| { this.on_action(cx.listener(Self::toggle_selection)) }) - .child(search_line) + .child( + h_flex() + .gap_1() + .when_some(button, |then, button| then.child(button)) + .child(search_line), + ) .children(query_error_line) .children(replace_line) + .into_any_element() } } @@ -503,7 +542,11 @@ impl ToolbarItemView for BufferSearchBar { if is_project_search { self.dismiss(&Default::default(), window, cx); } else { - return ToolbarItemLocation::Secondary; + if self.active_item_is_multibuffer(cx) { + return ToolbarItemLocation::PrimaryLeft; + } else { + return ToolbarItemLocation::Secondary; + } } } } @@ -789,7 +832,11 @@ impl BufferSearchBar { cx.notify(); cx.emit(Event::UpdateLocation); cx.emit(ToolbarItemEvent::ChangeLocation( - ToolbarItemLocation::Secondary, + if self.active_item_is_multibuffer(cx) { + ToolbarItemLocation::PrimaryLeft + } else { + ToolbarItemLocation::Secondary + }, )); true } @@ -801,6 +848,26 @@ impl BufferSearchBar { .unwrap_or_default() } + fn active_item_is_multibuffer(&self, cx: &App) -> bool { + if let Some(item) = &self.active_searchable_item { + dbg!("Calling"); + let buffer_kind = item.buffer_kind(cx); + + if item + .act_as_type(TypeId::of::(), cx) + .is_some() + { + dbg!("Called success"); + return false; + } + dbg!("Called fail"); + + buffer_kind == ItemBufferKind::Multibuffer + } else { + false + } + } + pub fn search_suggested(&mut self, window: &mut Window, cx: &mut Context) { let search = self.query_suggestion(window, cx).map(|suggestion| { self.search(&suggestion, Some(self.default_options), true, window, cx) diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 6e26be6dc7a09dd1ed8963579ae27d8f6cc8c50c..e74c0a98268a9957f59e052744d600e5cd115d4d 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -119,12 +119,13 @@ impl Render for Toolbar { .when(has_left_items || has_right_items, |this| { this.child( h_flex() - .min_h_6() + .items_start() .justify_between() .gap(DynamicSpacing::Base08.rems(cx)) .when(has_left_items, |this| { this.child( h_flex() + .min_h_6() .flex_auto() .justify_start() .overflow_x_hidden() @@ -134,7 +135,7 @@ impl Render for Toolbar { .when(has_right_items, |this| { this.child( h_flex() - .h_full() + .h_6() .flex_row_reverse() .map(|el| { if has_left_items {