@@ -38,8 +38,11 @@ use text::{BufferId, Selection};
use theme::{Theme, ThemeSettings};
use ui::{h_flex, prelude::*, IconDecorationKind, Label};
use util::{paths::PathExt, ResultExt, TryFutureExt};
-use workspace::item::{BreadcrumbText, FollowEvent};
use workspace::item::{Dedup, ItemSettings, SerializableItem, TabContentParams};
+use workspace::{
+ item::{BreadcrumbText, FollowEvent},
+ searchable::SearchOptions,
+};
use workspace::{
item::{FollowableItem, Item, ItemEvent, ProjectItem},
searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
@@ -1324,6 +1327,28 @@ impl SearchableItem for Editor {
}
}
+ fn supported_options(&self) -> SearchOptions {
+ if self.in_project_search {
+ SearchOptions {
+ case: true,
+ word: true,
+ regex: true,
+ replacement: false,
+ selection: false,
+ find_in_results: true,
+ }
+ } else {
+ SearchOptions {
+ case: true,
+ word: true,
+ regex: true,
+ replacement: true,
+ selection: true,
+ find_in_results: false,
+ }
+ }
+ }
+
fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context<Self>) -> String {
let setting = EditorSettings::get_global(cx).seed_search_query_from_cursor;
let snapshot = &self.snapshot(window, cx).buffer_snapshot;
@@ -55,7 +55,7 @@ pub struct Deploy {
impl_actions!(buffer_search, [Deploy]);
-actions!(buffer_search, [Dismiss, FocusEditor]);
+actions!(buffer_search, [DeployReplace, Dismiss, FocusEditor]);
impl Deploy {
pub fn find() -> Self {
@@ -65,6 +65,14 @@ impl Deploy {
selection_search_enabled: false,
}
}
+
+ pub fn replace() -> Self {
+ Self {
+ focus: true,
+ replace_enabled: true,
+ selection_search_enabled: false,
+ }
+ }
}
pub enum Event {
@@ -156,7 +164,7 @@ impl Render for BufferSearchBar {
let hide_inline_icons = self.editor_needed_width
> self.editor_scroll_handle.bounds().size.width - window.rem_size() * 6.;
- let supported_options = self.supported_options();
+ let supported_options = self.supported_options(cx);
if self.query_editor.update(cx, |query_editor, _cx| {
query_editor.placeholder_text().is_none()
@@ -223,6 +231,9 @@ impl Render for BufferSearchBar {
let search_line = h_flex()
.gap_2()
+ .when(supported_options.find_in_results, |el| {
+ el.child(Label::new("Find in results").color(Color::Hint))
+ })
.child(
input_base_styles()
.id("editor-scroll")
@@ -328,56 +339,70 @@ impl Render for BufferSearchBar {
}),
)
})
- .child(
- IconButton::new("select-all", ui::IconName::SelectAll)
- .on_click(|_, window, cx| {
- window.dispatch_action(SelectAllMatches.boxed_clone(), cx)
- })
- .shape(IconButtonShape::Square)
- .tooltip({
- let focus_handle = focus_handle.clone();
- move |window, cx| {
- Tooltip::for_action_in(
- "Select All Matches",
- &SelectAllMatches,
- &focus_handle,
- window,
- cx,
- )
- }
- }),
- )
- .child(
- h_flex()
- .pl_2()
- .ml_1()
- .border_l_1()
- .border_color(cx.theme().colors().border_variant)
- .child(render_nav_button(
- ui::IconName::ChevronLeft,
- self.active_match_index.is_some(),
- "Select Previous Match",
- &SelectPrevMatch,
- focus_handle.clone(),
+ .when(!supported_options.find_in_results, |el| {
+ el.child(
+ IconButton::new("select-all", ui::IconName::SelectAll)
+ .on_click(|_, window, cx| {
+ window.dispatch_action(SelectAllMatches.boxed_clone(), cx)
+ })
+ .shape(IconButtonShape::Square)
+ .tooltip({
+ let focus_handle = focus_handle.clone();
+ move |window, cx| {
+ Tooltip::for_action_in(
+ "Select All Matches",
+ &SelectAllMatches,
+ &focus_handle,
+ window,
+ cx,
+ )
+ }
+ }),
+ )
+ .child(
+ h_flex()
+ .pl_2()
+ .ml_1()
+ .border_l_1()
+ .border_color(cx.theme().colors().border_variant)
+ .child(render_nav_button(
+ ui::IconName::ChevronLeft,
+ self.active_match_index.is_some(),
+ "Select Previous Match",
+ &SelectPrevMatch,
+ focus_handle.clone(),
+ ))
+ .child(render_nav_button(
+ ui::IconName::ChevronRight,
+ self.active_match_index.is_some(),
+ "Select Next Match",
+ &SelectNextMatch,
+ focus_handle.clone(),
+ )),
+ )
+ .when(!narrow_mode, |this| {
+ this.child(h_flex().ml_2().min_w(rems_from_px(40.)).child(
+ Label::new(match_text).size(LabelSize::Small).color(
+ if self.active_match_index.is_some() {
+ Color::Default
+ } else {
+ Color::Disabled
+ },
+ ),
))
- .child(render_nav_button(
- ui::IconName::ChevronRight,
- self.active_match_index.is_some(),
- "Select Next Match",
- &SelectNextMatch,
- focus_handle.clone(),
- )),
- )
- .when(!narrow_mode, |this| {
- this.child(h_flex().ml_2().min_w(rems_from_px(40.)).child(
- Label::new(match_text).size(LabelSize::Small).color(
- if self.active_match_index.is_some() {
- Color::Default
- } else {
- Color::Disabled
- },
- ),
- ))
+ })
+ })
+ .when(supported_options.find_in_results, |el| {
+ el.child(
+ IconButton::new(SharedString::from("Close"), IconName::Close)
+ .shape(IconButtonShape::Square)
+ .tooltip(move |window, cx| {
+ Tooltip::for_action("Close Search Bar", &Dismiss, window, cx)
+ })
+ .on_click(cx.listener(|this, _: &ClickEvent, window, cx| {
+ this.dismiss(&Dismiss, window, cx)
+ })),
+ )
}),
);
@@ -447,49 +472,43 @@ impl Render for BufferSearchBar {
.on_action(cx.listener(Self::dismiss))
.on_action(cx.listener(Self::select_next_match))
.on_action(cx.listener(Self::select_prev_match))
- .when(self.supported_options().replacement, |this| {
+ .when(self.supported_options(cx).replacement, |this| {
this.on_action(cx.listener(Self::toggle_replace))
.when(in_replace, |this| {
this.on_action(cx.listener(Self::replace_next))
.on_action(cx.listener(Self::replace_all))
})
})
- .when(self.supported_options().case, |this| {
+ .when(self.supported_options(cx).case, |this| {
this.on_action(cx.listener(Self::toggle_case_sensitive))
})
- .when(self.supported_options().word, |this| {
+ .when(self.supported_options(cx).word, |this| {
this.on_action(cx.listener(Self::toggle_whole_word))
})
- .when(self.supported_options().regex, |this| {
+ .when(self.supported_options(cx).regex, |this| {
this.on_action(cx.listener(Self::toggle_regex))
})
- .when(self.supported_options().selection, |this| {
+ .when(self.supported_options(cx).selection, |this| {
this.on_action(cx.listener(Self::toggle_selection))
})
- .child(
- h_flex()
- .relative()
- .child(search_line.w_full())
- .when(!narrow_mode, |div| {
- div.child(
- h_flex().absolute().right_0().child(
- IconButton::new(SharedString::from("Close"), IconName::Close)
- .shape(IconButtonShape::Square)
- .tooltip(move |window, cx| {
- Tooltip::for_action(
- "Close Search Bar",
- &Dismiss,
- window,
- cx,
- )
- })
- .on_click(cx.listener(|this, _: &ClickEvent, window, cx| {
- this.dismiss(&Dismiss, window, cx)
- })),
- ),
- )
- }),
- )
+ .child(h_flex().relative().child(search_line.w_full()).when(
+ !narrow_mode && !supported_options.find_in_results,
+ |div| {
+ div.child(
+ h_flex().absolute().right_0().child(
+ IconButton::new(SharedString::from("Close"), IconName::Close)
+ .shape(IconButtonShape::Square)
+ .tooltip(move |window, cx| {
+ Tooltip::for_action("Close Search Bar", &Dismiss, window, cx)
+ })
+ .on_click(cx.listener(|this, _: &ClickEvent, window, cx| {
+ this.dismiss(&Dismiss, window, cx)
+ })),
+ ),
+ )
+ .w_full()
+ },
+ ))
.children(replace_line)
}
}
@@ -531,10 +550,15 @@ 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, window, cx));
if !self.dismissed {
- return ToolbarItemLocation::Secondary;
+ if is_project_search {
+ self.dismiss(&Default::default(), window, cx);
+ } else {
+ return ToolbarItemLocation::Secondary;
+ }
}
}
ToolbarItemLocation::Hidden
@@ -549,40 +573,56 @@ impl BufferSearchBar {
}));
registrar.register_handler(ForDeployed(
|this, action: &ToggleCaseSensitive, window, cx| {
- if this.supported_options().case {
+ if this.supported_options(cx).case {
this.toggle_case_sensitive(action, window, cx);
}
},
));
registrar.register_handler(ForDeployed(|this, action: &ToggleWholeWord, window, cx| {
- if this.supported_options().word {
+ if this.supported_options(cx).word {
this.toggle_whole_word(action, window, cx);
}
}));
registrar.register_handler(ForDeployed(|this, action: &ToggleRegex, window, cx| {
- if this.supported_options().regex {
+ if this.supported_options(cx).regex {
this.toggle_regex(action, window, cx);
}
}));
registrar.register_handler(ForDeployed(|this, action: &ToggleSelection, window, cx| {
- if this.supported_options().selection {
+ if this.supported_options(cx).selection {
this.toggle_selection(action, window, cx);
+ } else {
+ cx.propagate();
}
}));
registrar.register_handler(ForDeployed(|this, action: &ToggleReplace, window, cx| {
- if this.supported_options().replacement {
+ if this.supported_options(cx).replacement {
this.toggle_replace(action, window, cx);
+ } else {
+ cx.propagate();
}
}));
registrar.register_handler(WithResults(|this, action: &SelectNextMatch, window, cx| {
- this.select_next_match(action, window, cx);
+ if this.supported_options(cx).find_in_results {
+ cx.propagate();
+ } else {
+ this.select_next_match(action, window, cx);
+ }
}));
registrar.register_handler(WithResults(|this, action: &SelectPrevMatch, window, cx| {
- this.select_prev_match(action, window, cx);
+ if this.supported_options(cx).find_in_results {
+ cx.propagate();
+ } else {
+ this.select_prev_match(action, window, cx);
+ }
}));
registrar.register_handler(WithResults(
|this, action: &SelectAllMatches, window, cx| {
- this.select_all_matches(action, window, cx);
+ if this.supported_options(cx).find_in_results {
+ cx.propagate();
+ } else {
+ this.select_all_matches(action, window, cx);
+ }
},
));
registrar.register_handler(ForDeployed(
@@ -599,6 +639,13 @@ impl BufferSearchBar {
registrar.register_handler(ForDeployed(|this, deploy, window, cx| {
this.deploy(deploy, window, cx);
}));
+ registrar.register_handler(ForDismissed(|this, _: &DeployReplace, window, cx| {
+ if this.supported_options(cx).find_in_results {
+ cx.propagate();
+ } else {
+ this.deploy(&Deploy::replace(), window, cx);
+ }
+ }));
registrar.register_handler(ForDismissed(|this, deploy, window, cx| {
this.deploy(deploy, window, cx);
}))
@@ -735,10 +782,10 @@ impl BufferSearchBar {
true
}
- fn supported_options(&self) -> workspace::searchable::SearchOptions {
+ fn supported_options(&self, cx: &mut Context<Self>) -> workspace::searchable::SearchOptions {
self.active_searchable_item
- .as_deref()
- .map(SearchableItemHandle::supported_options)
+ .as_ref()
+ .map(|item| item.supported_options(cx))
.unwrap_or_default()
}