diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index d5e1643589..82fb1dd83d 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -279,7 +279,17 @@ impl AssistantPanel { }); pane.toolbar().update(cx, |toolbar, cx| { toolbar.add_item(context_editor_toolbar.clone(), window, cx); - toolbar.add_item(cx.new(|cx| BufferSearchBar::new(window, cx)), window, cx) + toolbar.add_item( + cx.new(|cx| { + BufferSearchBar::new( + Some(workspace.project().read(cx).languages().clone()), + window, + cx, + ) + }), + window, + cx, + ) }); pane }); diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index e983682225..5cc644e253 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -6,6 +6,7 @@ use crate::{ ToggleCaseSensitive, ToggleRegex, ToggleReplace, ToggleSelection, ToggleWholeWord, }; use any_vec::AnyVec; +use anyhow::Context as _; use collections::HashMap; use editor::{ actions::{Tab, TabPrev}, @@ -14,9 +15,10 @@ use editor::{ use futures::channel::oneshot; use gpui::{ actions, div, impl_actions, Action, App, ClickEvent, Context, Entity, EventEmitter, - FocusHandle, Focusable, Hsla, InteractiveElement as _, IntoElement, KeyContext, - ParentElement as _, Render, ScrollHandle, Styled, Subscription, Task, TextStyle, Window, + FocusHandle, Focusable, InteractiveElement as _, IntoElement, KeyContext, ParentElement as _, + Render, ScrollHandle, Styled, Subscription, Task, TextStyle, Window, }; +use language::{Language, LanguageRegistry}; use project::{ search::SearchQuery, search_history::{SearchHistory, SearchHistoryCursor}, @@ -108,41 +110,48 @@ pub struct BufferSearchBar { scroll_handle: ScrollHandle, editor_scroll_handle: ScrollHandle, editor_needed_width: Pixels, + regex_language: Option>, } impl BufferSearchBar { fn render_text_input( &self, editor: &Entity, - color: Hsla, - + color_override: Option, cx: &mut Context, ) -> impl IntoElement { + let (color, use_syntax) = if editor.read(cx).read_only(cx) { + (cx.theme().colors().text_disabled, false) + } else { + match color_override { + Some(color_override) => (color_override.color(cx), false), + None => (cx.theme().colors().text, true), + } + }; + let settings = ThemeSettings::get_global(cx); let text_style = TextStyle { - color: if editor.read(cx).read_only(cx) { - cx.theme().colors().text_disabled - } else { - color - }, + color, font_family: settings.buffer_font.family.clone(), font_features: settings.buffer_font.features.clone(), font_fallbacks: settings.buffer_font.fallbacks.clone(), font_size: rems(0.875).into(), font_weight: settings.buffer_font.weight, line_height: relative(1.3), - ..Default::default() + ..TextStyle::default() }; - EditorElement::new( - editor, - EditorStyle { - background: cx.theme().colors().editor_background, - local_player: cx.theme().players().local(), - text: text_style, - ..Default::default() - }, - ) + let mut editor_style = EditorStyle { + background: cx.theme().colors().editor_background, + local_player: cx.theme().players().local(), + text: text_style, + ..EditorStyle::default() + }; + if use_syntax { + editor_style.syntax = cx.theme().syntax().clone(); + } + + EditorElement::new(editor, editor_style) } pub fn query_editor_focused(&self) -> bool { @@ -179,7 +188,7 @@ impl Render for BufferSearchBar { editor.set_placeholder_text("Replace with…", cx); }); - let mut text_color = Color::Default; + let mut color_override = None; let match_text = self .active_searchable_item .as_ref() @@ -195,7 +204,7 @@ impl Render for BufferSearchBar { if let Some(match_ix) = self.active_match_index { Some(format!("{}/{}", match_ix + 1, matches_count)) } else { - text_color = Color::Error; // No matches found + color_override = Some(Color::Error); // No matches found None } }) @@ -239,7 +248,7 @@ impl Render for BufferSearchBar { input_base_styles() .id("editor-scroll") .track_scroll(&self.editor_scroll_handle) - .child(self.render_text_input(&self.query_editor, text_color.color(cx), cx)) + .child(self.render_text_input(&self.query_editor, color_override, cx)) .when(!hide_inline_icons, |div| { div.child( h_flex() @@ -412,7 +421,7 @@ impl Render for BufferSearchBar { .gap_2() .child(input_base_styles().child(self.render_text_input( &self.replacement_editor, - cx.theme().colors().text, + None, cx, ))) .child( @@ -652,7 +661,11 @@ impl BufferSearchBar { })) } - pub fn new(window: &mut Window, cx: &mut Context) -> Self { + pub fn new( + languages: Option>, + window: &mut Window, + cx: &mut Context, + ) -> Self { let query_editor = cx.new(|cx| Editor::single_line(window, cx)); cx.subscribe_in(&query_editor, window, Self::on_query_editor_event) .detach(); @@ -661,6 +674,32 @@ impl BufferSearchBar { .detach(); let search_options = SearchOptions::from_settings(&EditorSettings::get_global(cx).search); + if let Some(languages) = languages { + let query_buffer = query_editor + .read(cx) + .buffer() + .read(cx) + .as_singleton() + .expect("query editor should be backed by a singleton buffer"); + query_buffer.update(cx, |query_buffer, _| { + query_buffer.set_language_registry(languages.clone()); + }); + + cx.spawn(|buffer_search_bar, mut cx| async move { + let regex_language = languages + .language_for_name("regex") + .await + .context("loading regex language")?; + buffer_search_bar + .update(&mut cx, |buffer_search_bar, cx| { + buffer_search_bar.regex_language = Some(regex_language); + buffer_search_bar.adjust_query_regex_language(cx); + }) + .ok(); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } Self { query_editor, @@ -688,6 +727,7 @@ impl BufferSearchBar { scroll_handle: ScrollHandle::new(), editor_scroll_handle: ScrollHandle::new(), editor_needed_width: px(0.), + regex_language: None, } } @@ -910,6 +950,7 @@ impl BufferSearchBar { self.search_options.toggle(search_option); self.default_options = self.search_options; drop(self.update_matches(false, window, cx)); + self.adjust_query_regex_language(cx); cx.notify(); } @@ -1429,6 +1470,28 @@ impl BufferSearchBar { } } } + + fn adjust_query_regex_language(&self, cx: &mut App) { + let enable = self.search_options.contains(SearchOptions::REGEX); + let query_buffer = self + .query_editor + .read(cx) + .buffer() + .read(cx) + .as_singleton() + .expect("query editor should be backed by a singleton buffer"); + if enable { + if let Some(regex_language) = self.regex_language.clone() { + query_buffer.update(cx, |query_buffer, cx| { + query_buffer.set_language(Some(regex_language), cx); + }) + } + } else { + query_buffer.update(cx, |query_buffer, cx| { + query_buffer.set_language(None, cx); + }) + } + } } #[cfg(test)] @@ -1482,7 +1545,7 @@ mod tests { cx.new_window_entity(|window, cx| Editor::for_buffer(buffer.clone(), None, window, cx)); let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar @@ -1851,7 +1914,7 @@ mod tests { }); let search_bar = window.build_entity(cx, |window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar @@ -2059,7 +2122,7 @@ mod tests { cx.new_window_entity(|window, cx| Editor::for_buffer(buffer.clone(), None, window, cx)); let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar @@ -2133,7 +2196,7 @@ mod tests { cx.new_window_entity(|window, cx| Editor::for_buffer(buffer.clone(), None, window, cx)); let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar @@ -2513,7 +2576,7 @@ mod tests { cx.new_window_entity(|window, cx| Editor::for_buffer(buffer.clone(), None, window, cx)); let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar @@ -2596,7 +2659,7 @@ mod tests { }); let search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = BufferSearchBar::new(None, window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index f4c04447fe..513ff7decd 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -3804,7 +3804,8 @@ pub mod tests { cx.run_until_parked(); let buffer_search_bar = cx.new_window_entity(|window, cx| { - let mut search_bar = BufferSearchBar::new(window, cx); + let mut search_bar = + BufferSearchBar::new(Some(project.read(cx).languages().clone()), window, cx); search_bar.set_active_pane_item(Some(&editor), window, cx); search_bar.show(window, cx); search_bar diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index af19555fe9..48fd332ef4 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -980,7 +980,9 @@ pub fn new_terminal_pane( false }))); - let buffer_search_bar = cx.new(|cx| search::BufferSearchBar::new(window, cx)); + let buffer_search_bar = cx.new(|cx| { + search::BufferSearchBar::new(Some(project.read(cx).languages().clone()), window, cx) + }); let breadcrumbs = cx.new(|_| Breadcrumbs::new()); pane.toolbar().update(cx, |toolbar, cx| { toolbar.add_item(buffer_search_bar, window, cx); diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 8a24b3e572..2c7f1caeef 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -78,7 +78,7 @@ impl VimTestContext { cx.update_workspace(|workspace, window, cx| { workspace.active_pane().update(cx, |pane, cx| { pane.toolbar().update(cx, |toolbar, cx| { - let buffer_search_bar = cx.new(|cx| BufferSearchBar::new(window, cx)); + let buffer_search_bar = cx.new(|cx| BufferSearchBar::new(None, window, cx)); toolbar.add_item(buffer_search_bar, window, cx); let project_search_bar = cx.new(|_| ProjectSearchBar::new()); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index dc632d166d..9b7304355e 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -885,7 +885,13 @@ fn initialize_pane( toolbar.add_item(multibuffer_hint, window, cx); let breadcrumbs = cx.new(|_| Breadcrumbs::new()); toolbar.add_item(breadcrumbs, window, cx); - let buffer_search_bar = cx.new(|cx| search::BufferSearchBar::new(window, cx)); + let buffer_search_bar = cx.new(|cx| { + search::BufferSearchBar::new( + Some(workspace.project().read(cx).languages().clone()), + window, + cx, + ) + }); toolbar.add_item(buffer_search_bar.clone(), window, cx); let proposed_change_bar = cx.new(|_| ProposedChangesEditorToolbar::new()); toolbar.add_item(proposed_change_bar, window, cx);