diff --git a/Cargo.lock b/Cargo.lock index 49533117c1..cce55da25d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1727,6 +1727,7 @@ dependencies = [ "editor", "gpui", "postage", + "theme", "workspace", ] diff --git a/crates/find/Cargo.toml b/crates/find/Cargo.toml index 16a9b1f827..2984f013ec 100644 --- a/crates/find/Cargo.toml +++ b/crates/find/Cargo.toml @@ -10,5 +10,6 @@ path = "src/find.rs" aho-corasick = "0.7" editor = { path = "../editor" } gpui = { path = "../gpui" } +theme = { path = "../theme" } workspace = { path = "../workspace" } postage = { version = "0.4.1", features = ["futures-traits"] } diff --git a/crates/find/src/find.rs b/crates/find/src/find.rs index 19b105ccf8..41dcbe38b2 100644 --- a/crates/find/src/find.rs +++ b/crates/find/src/find.rs @@ -1,4 +1,4 @@ -use aho_corasick::AhoCorasick; +use aho_corasick::AhoCorasickBuilder; use editor::{Editor, EditorSettings}; use gpui::{ action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View, @@ -10,6 +10,14 @@ use workspace::{ItemViewHandle, Settings, Toolbar, Workspace}; action!(Deploy); action!(Cancel); +action!(ToggleMode, SearchMode); + +#[derive(Clone, Copy)] +pub enum SearchMode { + WholeWord, + CaseSensitive, + Regex, +} pub fn init(cx: &mut MutableAppContext) { cx.add_bindings([ @@ -18,12 +26,16 @@ pub fn init(cx: &mut MutableAppContext) { ]); cx.add_action(FindBar::deploy); cx.add_action(FindBar::cancel); + cx.add_action(FindBar::toggle_mode); } struct FindBar { settings: watch::Receiver, query_editor: ViewHandle, active_editor: Option>, + case_sensitive_mode: bool, + whole_word_mode: bool, + regex_mode: bool, } impl Entity for FindBar { @@ -39,10 +51,25 @@ impl View for FindBar { cx.focus(&self.query_editor); } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { - ChildView::new(&self.query_editor) + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + let theme = &self.settings.borrow().theme.find; + Flex::column() + .with_child( + ChildView::new(&self.query_editor) + .contained() + .with_style(theme.query.container) + .boxed(), + ) + .with_child( + Flex::column() + .with_child(self.render_mode_button("Aa", SearchMode::CaseSensitive, theme, cx)) + .with_child(self.render_mode_button("|ab|", SearchMode::WholeWord, theme, cx)) + .with_child(self.render_mode_button(".*", SearchMode::Regex, theme, cx)) + .contained() + .with_style(theme.mode_button_group) + .boxed(), + ) .contained() - .with_style(self.settings.borrow().theme.selector.input_editor.container) .boxed() } } @@ -67,7 +94,7 @@ impl FindBar { Arc::new(move |_| { let settings = settings.borrow(); EditorSettings { - style: settings.theme.selector.input_editor.as_editor(), + style: settings.theme.find.query.as_editor(), tab_size: settings.tab_size, soft_wrap: editor::SoftWrap::None, } @@ -82,10 +109,37 @@ impl FindBar { Self { query_editor, active_editor: None, + case_sensitive_mode: false, + whole_word_mode: false, + regex_mode: false, settings, } } + fn render_mode_button( + &self, + icon: &str, + mode: SearchMode, + theme: &theme::Find, + cx: &mut RenderContext, + ) -> ElementBox { + let is_active = self.is_mode_enabled(mode); + MouseEventHandler::new::(0, cx, |state, _| { + let style = match (is_active, state.hovered) { + (false, false) => &theme.mode_button, + (false, true) => &theme.hovered_mode_button, + (true, false) => &theme.active_mode_button, + (true, true) => &theme.active_hovered_mode_button, + }; + Label::new(icon.to_string(), style.text.clone()) + .contained() + .with_style(style.container) + .boxed() + }) + .on_click(move |cx| cx.dispatch_action(ToggleMode(mode))) + .boxed() + } + fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext) { let settings = workspace.settings(); workspace.active_pane().update(cx, |pane, cx| { @@ -102,6 +156,25 @@ impl FindBar { .update(cx, |pane, cx| pane.hide_toolbar(cx)); } + fn is_mode_enabled(&self, mode: SearchMode) -> bool { + match mode { + SearchMode::WholeWord => self.whole_word_mode, + SearchMode::CaseSensitive => self.case_sensitive_mode, + SearchMode::Regex => self.regex_mode, + } + } + + fn toggle_mode(&mut self, ToggleMode(mode): &ToggleMode, cx: &mut ViewContext) { + eprintln!("TOGGLE MODE"); + let value = match mode { + SearchMode::WholeWord => &mut self.whole_word_mode, + SearchMode::CaseSensitive => &mut self.case_sensitive_mode, + SearchMode::Regex => &mut self.regex_mode, + }; + *value = !*value; + cx.notify(); + } + fn on_query_editor_event( &mut self, _: ViewHandle, @@ -117,7 +190,10 @@ impl FindBar { return; } - let search = AhoCorasick::new_auto_configured(&[search]); + let search = AhoCorasickBuilder::new() + .auto_configure(&[&search]) + .ascii_case_insensitive(!self.case_sensitive_mode) + .build(&[&search]); let buffer = editor.buffer().read(cx).snapshot(cx); let ranges = search .stream_find_iter(buffer.bytes_in_range(0..buffer.len())) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 9452204617..0ea5ebee40 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -90,6 +90,12 @@ pub struct Tab { #[derive(Clone, Deserialize, Default)] pub struct Find { + pub query: InputEditorStyle, + pub mode_button_group: ContainerStyle, + pub mode_button: ContainedText, + pub active_mode_button: ContainedText, + pub hovered_mode_button: ContainedText, + pub active_hovered_mode_button: ContainedText, pub match_background: Color, } diff --git a/crates/zed/assets/themes/_base.toml b/crates/zed/assets/themes/_base.toml index e92715793c..0f8326e838 100644 --- a/crates/zed/assets/themes/_base.toml +++ b/crates/zed/assets/themes/_base.toml @@ -321,3 +321,31 @@ tab_summary_spacing = 10 [find] match_background = "$state.highlighted_line" + +[find.mode_button] +extends = "$text.1" + +[find.mode_button_group] +corner_radius = 6 +border = { width = 1, color = "$border.0" } + +[find.active_mode_button] +extends = "$find.mode_button" +background = "$surface.2" + +[find.hovered_mode_button] +extends = "$find.mode_button" +background = "$surface.2" + +[find.active_hovered_mode_button] +extends = "$find.mode_button" +background = "$surface.2" + +[find.query] +background = "$surface.1" +corner_radius = 6 +padding = { left = 16, right = 16, top = 7, bottom = 7 } +text = "$text.0" +placeholder_text = "$text.2" +selection = "$selection.host" +border = { width = 1, color = "$border.0" }