@@ -10,16 +10,16 @@ use collections::HashMap;
use editor::Editor;
use futures::channel::oneshot;
use gpui::{
- action, actions, div, Action, AnyElement, AnyView, AppContext, Component, Div, Entity,
- EventEmitter, ParentElement as _, Render, Subscription, Svg, Task, View, ViewContext,
- VisualContext as _, WindowContext,
+ action, actions, blue, div, red, white, Action, AnyElement, AnyView, AppContext, Component,
+ Div, Entity, EventEmitter, Hsla, ParentElement as _, Render, Styled, Subscription, Svg, Task,
+ View, ViewContext, VisualContext as _, WindowContext,
};
use project::search::SearchQuery;
use serde::Deserialize;
use std::{any::Any, sync::Arc};
use theme::ActiveTheme;
-use ui::{IconButton, Label};
+use ui::{h_stack, Icon, IconButton, IconElement, Label, StyledExt};
use util::ResultExt;
use workspace::{
item::ItemHandle,
@@ -66,31 +66,8 @@ pub struct BufferSearchBar {
impl EventEmitter<Event> for BufferSearchBar {}
impl EventEmitter<workspace::ToolbarItemEvent> for BufferSearchBar {}
impl Render for BufferSearchBar {
- // fn ui_name() -> &'static str {
- // "BufferSearchBar"
- // }
-
- // fn update_keymap_context(
- // &self,
- // keymap: &mut gpui::keymap_matcher::KeymapContext,
- // cx: &AppContext,
- // ) {
- // Self::reset_to_default_keymap_context(keymap);
- // let in_replace = self
- // .replacement_editor
- // .read_with(cx, |_, cx| cx.is_self_focused())
- // .unwrap_or(false);
- // if in_replace {
- // keymap.add_identifier("in_replace");
- // }
- // }
-
- // fn focus_in(&mut self, _: View, cx: &mut ViewContext<Self>) {
- // cx.focus(&self.query_editor);
- // }
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
- let theme = cx.theme().clone();
// let query_container_style = if self.query_contains_error {
// theme.search.invalid_editor
// } else {
@@ -147,61 +124,104 @@ impl Render for BufferSearchBar {
self.replacement_editor.update(cx, |editor, cx| {
editor.set_placeholder_text("Replace with...", cx);
});
+
+ let search_button_for_mode = |mode, side, cx: &mut ViewContext<BufferSearchBar>| {
+ let is_active = self.current_mode == mode;
+
+ render_search_mode_button(
+ mode,
+ side,
+ is_active,
+ move |this, cx| {
+ this.activate_search_mode(mode, cx);
+ },
+ cx,
+ )
+ };
+ let search_option_button = |option| {
+ let is_active = self.search_options.contains(option);
+ option.as_button(is_active)
+ };
+ let match_count = self
+ .active_searchable_item
+ .as_ref()
+ .and_then(|searchable_item| {
+ if self.query(cx).is_empty() {
+ return None;
+ }
+ let matches = self
+ .searchable_items_with_matches
+ .get(&searchable_item.downgrade())?;
+ let message = if let Some(match_ix) = self.active_match_index {
+ format!("{}/{}", match_ix + 1, matches.len())
+ } else {
+ "No matches".to_string()
+ };
+
+ Some(ui::Label::new(message))
+ });
+ let nav_button_for_direction = |label, direction, cx: &mut ViewContext<Self>| {
+ render_nav_button(
+ label,
+ direction,
+ self.active_match_index.is_some(),
+ move |this, cx| match direction {
+ Direction::Prev => this.select_prev_match(&Default::default(), cx),
+ Direction::Next => this.select_next_match(&Default::default(), cx),
+ },
+ cx,
+ )
+ };
div()
- .child(self.query_editor.clone())
- .child(self.replacement_editor.clone())
- // let search_button_for_mode = |mode, side, cx: &mut ViewContext<BufferSearchBar>| {
- // let is_active = self.current_mode == mode;
-
- // render_search_mode_button(
- // mode,
- // side,
- // is_active,
- // move |_, this, cx| {
- // this.activate_search_mode(mode, cx);
- // },
- // cx,
- // )
- // };
- // let search_option_button = |option| {
- // let is_active = self.search_options.contains(option);
- // option.as_button(is_active)
- // };
- // let match_count = self
- // .active_searchable_item
- // .as_ref()
- // .and_then(|searchable_item| {
- // if self.query(cx).is_empty() {
- // return None;
- // }
- // let matches = self
- // .searchable_items_with_matches
- // .get(&searchable_item.downgrade())?;
- // let message = if let Some(match_ix) = self.active_match_index {
- // format!("{}/{}", match_ix + 1, matches.len())
- // } else {
- // "No matches".to_string()
- // };
-
- // Some(
- // Label::new(message)
- // .contained()
- // .with_style(theme.search.match_index.container)
- // .aligned(),
- // )
- // });
- // let nav_button_for_direction = |label, direction, cx: &mut ViewContext<Self>| {
- // render_nav_button(
- // label,
- // direction,
- // self.active_match_index.is_some(),
- // move |_, this, cx| match direction {
- // Direction::Prev => this.select_prev_match(&Default::default(), cx),
- // Direction::Next => this.select_next_match(&Default::default(), cx),
- // },
- // cx,
- // )
- // };
+ .w_full()
+ .border()
+ .border_color(blue())
+ .flex() // Make this div a flex container
+ .justify_between()
+ .child(
+ div()
+ .flex()
+ .border_1()
+ .border_color(red())
+ .rounded_md()
+ .w_96()
+ .items_center()
+ .child(IconElement::new(Icon::MagnifyingGlass))
+ .child(self.query_editor.clone())
+ .children(
+ supported_options
+ .case
+ .then(|| search_option_button(SearchOptions::CASE_SENSITIVE)),
+ )
+ .children(
+ supported_options
+ .word
+ .then(|| search_option_button(SearchOptions::WHOLE_WORD)),
+ ),
+ )
+ .child(div().w_auto().flex_row())
+ .child(search_button_for_mode(
+ SearchMode::Text,
+ Some(Side::Left),
+ cx,
+ ))
+ .child(search_button_for_mode(
+ SearchMode::Regex,
+ Some(Side::Right),
+ cx,
+ ))
+ .when(supported_options.replacement, |this| {
+ this.child(super::toggle_replace_button(self.replace_enabled))
+ })
+ .when(self.replace_enabled, |this| {
+ this.child(div().w_80().child(self.replacement_editor.clone()))
+ })
+ .children(match_count)
+ .child(nav_button_for_direction("<", Direction::Prev, cx))
+ .child(nav_button_for_direction(">", Direction::Next, cx))
+ .flex()
+ .justify_between()
+
// let query_column = Flex::row()
// .with_child(
// Svg::for_style(theme.search.editor_icon.clone().icon)
@@ -351,7 +371,6 @@ impl ToolbarItemView for BufferSearchBar {
impl BufferSearchBar {
pub fn register(workspace: &mut Workspace) {
workspace.register_action(|workspace, a: &Deploy, cx| {
- dbg!("Setting");
workspace.active_pane().update(cx, |this, cx| {
this.toolbar().update(cx, |this, cx| {
let view = cx.build_view(|cx| BufferSearchBar::new(cx));
@@ -361,6 +380,43 @@ impl BufferSearchBar {
})
});
});
+ fn register_action<A: Action>(
+ workspace: &mut Workspace,
+ update: fn(&mut BufferSearchBar, &mut ViewContext<'_, BufferSearchBar>),
+ ) {
+ workspace.register_action(move |workspace, _: &A, cx| {
+ workspace.active_pane().update(cx, move |this, cx| {
+ this.toolbar().update(cx, move |toolbar, cx| {
+ let Some(search_bar) = toolbar.item_of_type::<BufferSearchBar>() else {
+ return;
+ };
+ search_bar.update(cx, |this, cx| update(this, cx))
+ })
+ });
+ });
+ }
+ register_action::<ToggleCaseSensitive>(workspace, |this, cx| {
+ this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx)
+ });
+ register_action::<ToggleWholeWord>(workspace, |this: &mut BufferSearchBar, cx| {
+ this.toggle_search_option(SearchOptions::WHOLE_WORD, cx)
+ });
+ register_action::<ToggleReplace>(workspace, |this: &mut BufferSearchBar, cx| {
+ dbg!("Toggling");
+ this.toggle_replace(&ToggleReplace, cx)
+ });
+ // workspace.register_action(|workspace, _: &ToggleCaseSensitive, cx| {
+ // workspace.active_pane().update(cx, |this, cx| {
+ // this.toolbar().update(cx, |toolbar, cx| {
+ // let Some(search_bar) = toolbar.item_of_type::<BufferSearchBar>() else {
+ // return;
+ // };
+ // search_bar.update(cx, |this, cx| {
+ // this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
+ // })
+ // })
+ // });
+ // });
}
pub fn new(cx: &mut ViewContext<Self>) -> Self {
dbg!("New");
@@ -1,11 +1,11 @@
-use std::borrow::Cow;
+use std::{borrow::Cow, sync::Arc};
use gpui::{
- div, Action, AnyElement, Component, CursorStyle, Element, MouseButton, MouseDownEvent, Svg,
- View, ViewContext,
+ div, Action, AnyElement, Component, CursorStyle, Element, MouseButton, MouseDownEvent,
+ ParentElement as _, StatelessInteractive, Styled, Svg, View, ViewContext,
};
use theme::ActiveTheme;
-use ui::Label;
+use ui::{Button, Label};
use workspace::searchable::Direction;
use crate::{
@@ -17,19 +17,16 @@ pub(super) fn render_nav_button<V: 'static>(
icon: &'static str,
direction: Direction,
active: bool,
- on_click: impl Fn(MouseDownEvent, &mut V, &mut ViewContext<V>) + 'static,
+ on_click: impl Fn(&mut V, &mut ViewContext<V>) + 'static + Send + Sync,
cx: &mut ViewContext<V>,
) -> impl Component<V> {
- let action: Box<dyn Action>;
let tooltip;
match direction {
Direction::Prev => {
- action = Box::new(SelectPrevMatch);
tooltip = "Select Previous Match";
}
Direction::Next => {
- action = Box::new(SelectNextMatch);
tooltip = "Select Next Match";
}
};
@@ -40,7 +37,7 @@ pub(super) fn render_nav_button<V: 'static>(
// CursorStyle::default()
// };
// enum NavButton {}
- div()
+ Button::new(icon).on_click(Arc::new(on_click))
// MouseEventHandler::new::<NavButton, _>(direction as usize, cx, |state, cx| {
// let theme = cx.theme();
// let style = theme
@@ -86,12 +83,23 @@ pub(crate) fn render_search_mode_button<V: 'static>(
mode: SearchMode,
side: Option<Side>,
is_active: bool,
- //on_click: impl Fn(MouseClick, &mut V, &mut ViewContext<V>) + 'static,
+ on_click: impl Fn(&mut V, &mut ViewContext<V>) + 'static,
cx: &mut ViewContext<V>,
) -> impl Component<V> {
//let tooltip_style = cx.theme().tooltip.clone();
enum SearchModeButton {}
+
div()
+ .border_2()
+ .rounded_md()
+ .when(side == Some(Side::Left), |this| {
+ this.border_r_0().rounded_tr_none().rounded_br_none()
+ })
+ .when(side == Some(Side::Right), |this| {
+ this.border_l_0().rounded_bl_none().rounded_tl_none()
+ })
+ .on_key_down(move |v, _, _, cx| on_click(v, cx))
+ .child(Label::new(mode.label()))
// MouseEventHandler::new::<SearchModeButton, _>(mode.region_id(), cx, |state, cx| {
// let theme = cx.theme();
// let style = theme