WIP
This commit is contained in:
parent
dfd68d4cb8
commit
6c69e40e5c
5 changed files with 158 additions and 94 deletions
|
@ -910,7 +910,6 @@ impl SearchableItem for Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_matches(&mut self, matches: Vec<Range<Anchor>>, cx: &mut ViewContext<Self>) {
|
fn update_matches(&mut self, matches: Vec<Range<Anchor>>, cx: &mut ViewContext<Self>) {
|
||||||
dbg!(&matches);
|
|
||||||
self.highlight_background::<BufferSearchHighlights>(
|
self.highlight_background::<BufferSearchHighlights>(
|
||||||
matches,
|
matches,
|
||||||
|theme| theme.title_bar_background, // todo: update theme
|
|theme| theme.title_bar_background, // todo: update theme
|
||||||
|
|
|
@ -10,16 +10,16 @@ use collections::HashMap;
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
action, actions, div, Action, AnyElement, AnyView, AppContext, Component, Div, Entity,
|
action, actions, blue, div, red, white, Action, AnyElement, AnyView, AppContext, Component,
|
||||||
EventEmitter, ParentElement as _, Render, Subscription, Svg, Task, View, ViewContext,
|
Div, Entity, EventEmitter, Hsla, ParentElement as _, Render, Styled, Subscription, Svg, Task,
|
||||||
VisualContext as _, WindowContext,
|
View, ViewContext, VisualContext as _, WindowContext,
|
||||||
};
|
};
|
||||||
use project::search::SearchQuery;
|
use project::search::SearchQuery;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{any::Any, sync::Arc};
|
use std::{any::Any, sync::Arc};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
|
|
||||||
use ui::{IconButton, Label};
|
use ui::{h_stack, Icon, IconButton, IconElement, Label, StyledExt};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::ItemHandle,
|
item::ItemHandle,
|
||||||
|
@ -66,31 +66,8 @@ pub struct BufferSearchBar {
|
||||||
impl EventEmitter<Event> for BufferSearchBar {}
|
impl EventEmitter<Event> for BufferSearchBar {}
|
||||||
impl EventEmitter<workspace::ToolbarItemEvent> for BufferSearchBar {}
|
impl EventEmitter<workspace::ToolbarItemEvent> for BufferSearchBar {}
|
||||||
impl Render 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>;
|
type Element = Div<Self>;
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
let theme = cx.theme().clone();
|
|
||||||
// let query_container_style = if self.query_contains_error {
|
// let query_container_style = if self.query_contains_error {
|
||||||
// theme.search.invalid_editor
|
// theme.search.invalid_editor
|
||||||
// } else {
|
// } else {
|
||||||
|
@ -147,61 +124,104 @@ impl Render for BufferSearchBar {
|
||||||
self.replacement_editor.update(cx, |editor, cx| {
|
self.replacement_editor.update(cx, |editor, cx| {
|
||||||
editor.set_placeholder_text("Replace with...", 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()
|
div()
|
||||||
.child(self.query_editor.clone())
|
.w_full()
|
||||||
.child(self.replacement_editor.clone())
|
.border()
|
||||||
// let search_button_for_mode = |mode, side, cx: &mut ViewContext<BufferSearchBar>| {
|
.border_color(blue())
|
||||||
// let is_active = self.current_mode == mode;
|
.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()
|
||||||
|
|
||||||
// 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,
|
|
||||||
// )
|
|
||||||
// };
|
|
||||||
// let query_column = Flex::row()
|
// let query_column = Flex::row()
|
||||||
// .with_child(
|
// .with_child(
|
||||||
// Svg::for_style(theme.search.editor_icon.clone().icon)
|
// Svg::for_style(theme.search.editor_icon.clone().icon)
|
||||||
|
@ -351,7 +371,6 @@ impl ToolbarItemView for BufferSearchBar {
|
||||||
impl BufferSearchBar {
|
impl BufferSearchBar {
|
||||||
pub fn register(workspace: &mut Workspace) {
|
pub fn register(workspace: &mut Workspace) {
|
||||||
workspace.register_action(|workspace, a: &Deploy, cx| {
|
workspace.register_action(|workspace, a: &Deploy, cx| {
|
||||||
dbg!("Setting");
|
|
||||||
workspace.active_pane().update(cx, |this, cx| {
|
workspace.active_pane().update(cx, |this, cx| {
|
||||||
this.toolbar().update(cx, |this, cx| {
|
this.toolbar().update(cx, |this, cx| {
|
||||||
let view = cx.build_view(|cx| BufferSearchBar::new(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 {
|
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
dbg!("New");
|
dbg!("New");
|
||||||
|
|
|
@ -100,6 +100,7 @@ fn toggle_replace_button<V: 'static>(active: bool) -> impl Component<V> {
|
||||||
ui::IconButton::new(0, ui::Icon::Replace)
|
ui::IconButton::new(0, ui::Icon::Replace)
|
||||||
.on_click(|_: &mut V, cx| {
|
.on_click(|_: &mut V, cx| {
|
||||||
cx.dispatch_action(Box::new(ToggleReplace));
|
cx.dispatch_action(Box::new(ToggleReplace));
|
||||||
|
cx.notify();
|
||||||
})
|
})
|
||||||
.variant(ui::ButtonVariant::Ghost)
|
.variant(ui::ButtonVariant::Ghost)
|
||||||
.when(active, |button| button.variant(ButtonVariant::Filled))
|
.when(active, |button| button.variant(ButtonVariant::Filled))
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, sync::Arc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, Action, AnyElement, Component, CursorStyle, Element, MouseButton, MouseDownEvent, Svg,
|
div, Action, AnyElement, Component, CursorStyle, Element, MouseButton, MouseDownEvent,
|
||||||
View, ViewContext,
|
ParentElement as _, StatelessInteractive, Styled, Svg, View, ViewContext,
|
||||||
};
|
};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::Label;
|
use ui::{Button, Label};
|
||||||
use workspace::searchable::Direction;
|
use workspace::searchable::Direction;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -17,19 +17,16 @@ pub(super) fn render_nav_button<V: 'static>(
|
||||||
icon: &'static str,
|
icon: &'static str,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
active: bool,
|
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>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> impl Component<V> {
|
) -> impl Component<V> {
|
||||||
let action: Box<dyn Action>;
|
|
||||||
let tooltip;
|
let tooltip;
|
||||||
|
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Prev => {
|
Direction::Prev => {
|
||||||
action = Box::new(SelectPrevMatch);
|
|
||||||
tooltip = "Select Previous Match";
|
tooltip = "Select Previous Match";
|
||||||
}
|
}
|
||||||
Direction::Next => {
|
Direction::Next => {
|
||||||
action = Box::new(SelectNextMatch);
|
|
||||||
tooltip = "Select Next Match";
|
tooltip = "Select Next Match";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -40,7 +37,7 @@ pub(super) fn render_nav_button<V: 'static>(
|
||||||
// CursorStyle::default()
|
// CursorStyle::default()
|
||||||
// };
|
// };
|
||||||
// enum NavButton {}
|
// enum NavButton {}
|
||||||
div()
|
Button::new(icon).on_click(Arc::new(on_click))
|
||||||
// MouseEventHandler::new::<NavButton, _>(direction as usize, cx, |state, cx| {
|
// MouseEventHandler::new::<NavButton, _>(direction as usize, cx, |state, cx| {
|
||||||
// let theme = cx.theme();
|
// let theme = cx.theme();
|
||||||
// let style = theme
|
// let style = theme
|
||||||
|
@ -86,12 +83,23 @@ pub(crate) fn render_search_mode_button<V: 'static>(
|
||||||
mode: SearchMode,
|
mode: SearchMode,
|
||||||
side: Option<Side>,
|
side: Option<Side>,
|
||||||
is_active: bool,
|
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>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> impl Component<V> {
|
) -> impl Component<V> {
|
||||||
//let tooltip_style = cx.theme().tooltip.clone();
|
//let tooltip_style = cx.theme().tooltip.clone();
|
||||||
enum SearchModeButton {}
|
enum SearchModeButton {}
|
||||||
|
|
||||||
div()
|
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| {
|
// MouseEventHandler::new::<SearchModeButton, _>(mode.region_id(), cx, |state, cx| {
|
||||||
// let theme = cx.theme();
|
// let theme = cx.theme();
|
||||||
// let style = theme
|
// let style = theme
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::ItemHandle;
|
use crate::ItemHandle;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, AnyView, Div, Entity, EntityId, EventEmitter, ParentElement, Render, View, ViewContext,
|
div, AnyView, Div, Entity, EntityId, EventEmitter, ParentElement, Render, Styled, View,
|
||||||
WindowContext,
|
ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum ToolbarItemEvent {
|
pub enum ToolbarItemEvent {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue