@@ -209,7 +209,7 @@ use workspace::{
ViewId, Workspace, WorkspaceId, WorkspaceSettings,
item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
- searchable::SearchEvent,
+ searchable::{CollapseDirection, SearchEvent},
};
use crate::{
@@ -1183,7 +1183,7 @@ pub struct Editor {
hovered_diff_hunk_row: Option<DisplayRow>,
pull_diagnostics_task: Task<()>,
pull_diagnostics_background_task: Task<()>,
- pub in_project_search: bool,
+ in_project_search: bool,
previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
breadcrumb_header: Option<String>,
focused_block: Option<FocusedBlock>,
@@ -19179,37 +19179,25 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) {
- if self.buffer.read(cx).is_singleton() {
+ let has_folds = if self.buffer.read(cx).is_singleton() {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let has_folds = display_map
.folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
.next()
.is_some();
-
- if has_folds {
- self.unfold_all(&actions::UnfoldAll, window, cx);
- } else {
- self.fold_all(&actions::FoldAll, window, cx);
- }
+ has_folds
} else {
let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
- let should_unfold = buffer_ids
+ let has_folds = buffer_ids
.iter()
.any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
+ has_folds
+ };
- self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
- editor
- .update_in(cx, |editor, _, cx| {
- for buffer_id in buffer_ids {
- if should_unfold {
- editor.unfold_buffer(buffer_id, cx);
- } else {
- editor.fold_buffer(buffer_id, cx);
- }
- }
- })
- .ok();
- });
+ if has_folds {
+ self.unfold_all(&actions::UnfoldAll, window, cx);
+ } else {
+ self.fold_all(&actions::FoldAll, window, cx);
}
}
@@ -19374,6 +19362,9 @@ impl Editor {
.ok();
});
}
+ cx.emit(SearchEvent::ResultsCollapsedChanged(
+ CollapseDirection::Collapsed,
+ ));
}
pub fn fold_function_bodies(
@@ -19562,6 +19553,9 @@ impl Editor {
.ok();
});
}
+ cx.emit(SearchEvent::ResultsCollapsedChanged(
+ CollapseDirection::Expanded,
+ ));
}
pub fn fold_selected_ranges(
@@ -1,10 +1,9 @@
mod registrar;
use crate::{
- FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ProjectSearchView, ReplaceAll,
- ReplaceNext, SearchOption, SearchOptions, SearchSource, SelectAllMatches, SelectNextMatch,
- SelectPreviousMatch, ToggleCaseSensitive, ToggleRegex, ToggleReplace, ToggleSelection,
- ToggleWholeWord,
+ FocusSearch, NextHistoryQuery, PreviousHistoryQuery, 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;
@@ -12,7 +11,7 @@ use anyhow::Context as _;
use collections::HashMap;
use editor::{
DisplayPoint, Editor, EditorSettings, MultiBufferOffset,
- actions::{Backtab, Tab},
+ actions::{Backtab, FoldAll, Tab, ToggleFoldAll, UnfoldAll},
};
use futures::channel::oneshot;
use gpui::{
@@ -37,10 +36,11 @@ use ui::{
};
use util::{ResultExt, paths::PathMatcher};
use workspace::{
- DeploySearch, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
+ ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
item::{ItemBufferKind, ItemHandle},
searchable::{
- Direction, FilteredSearchRange, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle,
+ CollapseDirection, Direction, FilteredSearchRange, SearchEvent, SearchableItemHandle,
+ WeakSearchableItemHandle,
},
};
@@ -125,18 +125,78 @@ pub struct BufferSearchBar {
editor_scroll_handle: ScrollHandle,
editor_needed_width: Pixels,
regex_language: Option<Arc<Language>>,
+ is_collapsed: bool,
}
impl EventEmitter<Event> for BufferSearchBar {}
impl EventEmitter<workspace::ToolbarItemEvent> for BufferSearchBar {}
impl Render for BufferSearchBar {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- if self.dismissed {
- return div().id("search_bar").into_any_element();
- }
-
let focus_handle = self.focus_handle(cx);
+ let collapse_expand_button = if self.needs_expand_collapse_option(cx) {
+ let (icon, label, tooltip_label) = if self.is_collapsed {
+ (
+ IconName::ChevronUpDown,
+ "Expand All",
+ "Expand All Search Results",
+ )
+ } else {
+ (
+ IconName::ChevronDownUp,
+ "Collapse All",
+ "Collapse All Search Results",
+ )
+ };
+
+ let tooltip_focus_handle = focus_handle.clone();
+
+ if self.dismissed {
+ let button = Button::new("multibuffer-collapse-expand-empty", label)
+ .icon_position(IconPosition::Start)
+ .icon(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.toggle_fold_all_in_item(window, cx);
+ }))
+ .into_any_element();
+
+ return h_flex()
+ .id("search_bar_button_only")
+ .py_px()
+ .justify_start()
+ .child(button)
+ .into_any_element();
+ }
+
+ 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.toggle_fold_all_in_item(window, cx);
+ }))
+ .into_any_element(),
+ )
+ } else {
+ None
+ };
+
let narrow_mode =
self.scroll_handle.bounds().size.width / window.rem_size() < 340. / BASE_REM_SIZE_IN_PX;
let hide_inline_icons = self.editor_needed_width
@@ -334,10 +394,13 @@ impl Render for BufferSearchBar {
let search_line = h_flex()
.w_full()
- .gap_2()
+ .gap_1()
.when(find_in_results, |el| {
el.child(Label::new("Find in results").color(Color::Hint))
})
+ .when(!find_in_results && collapse_expand_button.is_some(), |el| {
+ el.child(collapse_expand_button.expect("button"))
+ })
.child(query_column)
.child(mode_column);
@@ -403,41 +466,10 @@ 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()
- .py(px(1.0))
+ .gap_0()
+ .py(px(0.0))
.w_full()
.track_scroll(&self.scroll_handle)
.key_context(key_context)
@@ -480,12 +512,7 @@ impl Render for BufferSearchBar {
.when(selection, |this| {
this.on_action(cx.listener(Self::toggle_selection))
})
- .child(
- h_flex()
- .gap_1()
- .when_some(button, |then, button| then.child(button))
- .child(search_line),
- )
+ .child(search_line)
.children(query_error_line)
.children(replace_line)
.into_any_element()
@@ -538,17 +565,27 @@ impl ToolbarItemView for BufferSearchBar {
let is_project_search = searchable_item_handle.supported_options(cx).find_in_results;
self.active_searchable_item = Some(searchable_item_handle);
drop(self.update_matches(true, false, window, cx));
- if !self.dismissed {
+ // Need to think through this a bit
+ // Copy this over to dismiss
+ if self.needs_expand_collapse_option(cx) {
+ return ToolbarItemLocation::PrimaryLeft;
+ } else if !self.is_dismissed() {
if is_project_search {
self.dismiss(&Default::default(), window, cx);
- } else {
- if self.active_item_is_multibuffer(cx) {
- return ToolbarItemLocation::PrimaryLeft;
- } else {
- return ToolbarItemLocation::Secondary;
- }
}
+ return ToolbarItemLocation::Secondary;
}
+ // if !self.dismissed {
+ // if is_project_search {
+ // self.dismiss(&Default::default(), window, cx);
+ // } else {
+ // if self.needs_expand_collapse_option(cx) {
+ // return ToolbarItemLocation::PrimaryLeft;
+ // } else {
+ // return ToolbarItemLocation::Secondary;
+ // }
+ // }
+ // }
}
ToolbarItemLocation::Hidden
}
@@ -724,6 +761,7 @@ impl BufferSearchBar {
editor_scroll_handle: ScrollHandle::new(),
editor_needed_width: px(0.),
regex_language: None,
+ is_collapsed: false,
}
}
@@ -743,15 +781,28 @@ impl BufferSearchBar {
searchable_item.clear_matches(window, cx);
}
}
+
+ let needs_collapse_expand = self.needs_expand_collapse_option(cx);
+ let mut is_in_project_search = false;
+
if let Some(active_editor) = self.active_searchable_item.as_mut() {
self.selection_search_enabled = None;
self.replace_enabled = false;
active_editor.search_bar_visibility_changed(false, window, cx);
active_editor.toggle_filtered_search_ranges(None, window, cx);
+ is_in_project_search = active_editor.supported_options(cx).find_in_results;
let handle = active_editor.item_focus_handle(cx);
self.focus(&handle, window);
}
+ if needs_collapse_expand && !is_in_project_search {
+ cx.emit(Event::UpdateLocation);
+ cx.emit(ToolbarItemEvent::ChangeLocation(
+ ToolbarItemLocation::PrimaryLeft,
+ ));
+ cx.notify();
+ return;
+ }
cx.emit(Event::UpdateLocation);
cx.emit(ToolbarItemEvent::ChangeLocation(
ToolbarItemLocation::Hidden,
@@ -832,7 +883,7 @@ impl BufferSearchBar {
cx.notify();
cx.emit(Event::UpdateLocation);
cx.emit(ToolbarItemEvent::ChangeLocation(
- if self.active_item_is_multibuffer(cx) {
+ if self.needs_expand_collapse_option(cx) {
ToolbarItemLocation::PrimaryLeft
} else {
ToolbarItemLocation::Secondary
@@ -848,17 +899,19 @@ impl BufferSearchBar {
.unwrap_or_default()
}
- fn active_item_is_multibuffer(&self, cx: &App) -> bool {
+ // TODO we should clean this up
+ // We only provide an expand/collapse button if we are in a multibuffer and
+ // not doing a project search. In a project search, the button is already rendered.
+ // In a singleton buffer, this option doesn't make sense.
+ fn needs_expand_collapse_option(&self, cx: &App) -> bool {
if let Some(item) = &self.active_searchable_item {
let buffer_kind = item.buffer_kind(cx);
if buffer_kind == ItemBufferKind::Multibuffer {
- if let Some(editor) = item.act_as_type(TypeId::of::<Editor>(), cx) {
- let editor = editor.downcast::<Editor>().expect("is an editor");
- return !editor.read(cx).in_project_search;
- } else {
- return false;
- }
+ let workspace::searchable::SearchOptions {
+ find_in_results, ..
+ } = item.supported_options(cx);
+ !find_in_results
} else {
false
}
@@ -867,6 +920,22 @@ impl BufferSearchBar {
}
}
+ fn toggle_fold_all_in_item(&self, window: &mut Window, cx: &mut Context<Self>) {
+ let is_collapsed = self.is_collapsed;
+ if let Some(item) = &self.active_searchable_item {
+ if let Some(item) = item.act_as_type(TypeId::of::<Editor>(), cx) {
+ let editor = item.downcast::<Editor>().expect("Is an editor");
+ editor.update(cx, |editor, cx| {
+ if is_collapsed {
+ editor.unfold_all(&UnfoldAll, window, cx);
+ } else {
+ editor.fold_all(&FoldAll, window, cx);
+ }
+ })
+ }
+ }
+ }
+
pub fn search_suggested(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let search = self.query_suggestion(window, cx).map(|suggestion| {
self.search(&suggestion, Some(self.default_options), true, window, cx)
@@ -1197,6 +1266,15 @@ impl BufferSearchBar {
drop(self.update_matches(false, false, window, cx));
}
SearchEvent::ActiveMatchChanged => self.update_match_index(window, cx),
+ SearchEvent::ResultsCollapsedChanged(collapse_direction) => {
+ if self.needs_expand_collapse_option(cx) {
+ match collapse_direction {
+ CollapseDirection::Collapsed => self.is_collapsed = true,
+ CollapseDirection::Expanded => self.is_collapsed = false,
+ }
+ }
+ cx.notify();
+ }
}
}
@@ -10,7 +10,7 @@ use collections::HashMap;
use editor::{
Anchor, Editor, EditorEvent, EditorSettings, MAX_TAB_TITLE_LEN, MultiBuffer, PathKey,
SelectionEffects,
- actions::{Backtab, SelectAll, Tab},
+ actions::{Backtab, FoldAll, SelectAll, Tab, ToggleFoldAll, UnfoldAll},
items::active_match_index,
multibuffer_context_lines,
scroll::Autoscroll,
@@ -43,7 +43,7 @@ use workspace::{
DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation,
ToolbarItemView, Workspace, WorkspaceId,
item::{BreadcrumbText, Item, ItemEvent, ItemHandle, SaveOptions},
- searchable::{Direction, SearchableItem, SearchableItemHandle},
+ searchable::{CollapseDirection, Direction, SearchEvent, SearchableItem, SearchableItemHandle},
};
actions!(
@@ -763,26 +763,18 @@ impl ProjectSearchView {
fn toggle_all_search_results(
&mut self,
_: &ToggleAllSearchResults,
- _window: &mut Window,
+ window: &mut Window,
cx: &mut Context<Self>,
) {
- self.results_collapsed = !self.results_collapsed;
- self.update_results_visibility(cx);
+ self.update_results_visibility(window, cx);
}
- fn update_results_visibility(&mut self, cx: &mut Context<Self>) {
+ fn update_results_visibility(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.results_editor.update(cx, |editor, cx| {
- let multibuffer = editor.buffer().read(cx);
- let buffer_ids = multibuffer.excerpt_buffer_ids();
-
if self.results_collapsed {
- for buffer_id in buffer_ids {
- editor.fold_buffer(buffer_id, cx);
- }
+ editor.unfold_all(&UnfoldAll, window, cx);
} else {
- for buffer_id in buffer_ids {
- editor.unfold_buffer(buffer_id, cx);
- }
+ editor.fold_all(&FoldAll, window, cx);
}
});
cx.notify();
@@ -872,6 +864,18 @@ impl ProjectSearchView {
cx.emit(ViewEvent::EditorEvent(event.clone()));
}),
);
+ subscriptions.push(cx.subscribe(
+ &results_editor,
+ |this, _editor, event: &SearchEvent, _cx| match event {
+ SearchEvent::ResultsCollapsedChanged(collapsed_direction) => {
+ match collapsed_direction {
+ CollapseDirection::Collapsed => this.results_collapsed = true,
+ CollapseDirection::Expanded => this.results_collapsed = false,
+ }
+ }
+ _ => (),
+ },
+ ));
let included_files_editor = cx.new(|cx| {
let mut editor = Editor::single_line(window, cx);