diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 68fe4b997e8be04406711e6b933edcef63c6d6a3..8d8f762b8dbb3af718841a0d7e25d1fdf790da3b 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -248,7 +248,10 @@ "context": "ProjectSearchBar", "bindings": { "escape": "project_search::ToggleFocus", - "alt-tab": "search::CycleMode" + "alt-tab": "search::CycleMode", + "alt-cmd-g": "search::ActivateRegexMode", + "alt-cmd-s": "search::ActivateSemanticMode", + "alt-cmd-x": "search::ActivateTextMode" } }, { @@ -262,7 +265,10 @@ "context": "ProjectSearchView", "bindings": { "escape": "project_search::ToggleFocus", - "alt-tab": "search::CycleMode" + "alt-tab": "search::CycleMode", + "alt-cmd-g": "search::ActivateRegexMode", + "alt-cmd-s": "search::ActivateSemanticMode", + "alt-cmd-x": "search::ActivateTextMode" } }, { @@ -275,7 +281,10 @@ "alt-cmd-c": "search::ToggleCaseSensitive", "alt-cmd-w": "search::ToggleWholeWord", "alt-tab": "search::CycleMode", - "alt-cmd-f": "project_search::ToggleFilters" + "alt-cmd-f": "project_search::ToggleFilters", + "alt-cmd-g": "search::ActivateRegexMode", + "alt-cmd-s": "search::ActivateSemanticMode", + "alt-cmd-x": "search::ActivateTextMode" } }, // Bindings from VS Code diff --git a/assets/settings/default.json b/assets/settings/default.json index 86def54d323aebc0225fb5c89ee8a7a104c50a40..22ea2665333b6eb1630755840f58888a56c67d67 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -370,8 +370,7 @@ }, // Difference settings for semantic_index "semantic_index": { - "enabled": false, - "reindexing_delay_seconds": 600 + "enabled": false }, // Different settings for specific languages. "languages": { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 19442191172b5713f56746a5c449df11bae923dd..69587f856e94e776618b9c7a8846fb3ba726b38c 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -2,8 +2,9 @@ use crate::{ history::SearchHistory, mode::{SearchMode, Side}, search_bar::{render_nav_button, render_option_button_icon, render_search_mode_button}, - ActivateRegexMode, CycleMode, NextHistoryQuery, PreviousHistoryQuery, SearchOptions, - SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, ToggleWholeWord, + ActivateRegexMode, ActivateSemanticMode, ActivateTextMode, CycleMode, NextHistoryQuery, + PreviousHistoryQuery, SearchOptions, SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, + ToggleWholeWord, }; use anyhow::{Context, Result}; use collections::HashMap; @@ -51,8 +52,12 @@ actions!( #[derive(Default)] struct ActiveSearches(HashMap, WeakViewHandle>); +#[derive(Default)] +struct ActiveSettings(HashMap, ProjectSearchSettings>); + pub fn init(cx: &mut AppContext) { cx.set_global(ActiveSearches::default()); + cx.set_global(ActiveSettings::default()); cx.add_action(ProjectSearchView::deploy); cx.add_action(ProjectSearchView::move_focus_to_results); cx.add_action(ProjectSearchBar::search); @@ -63,6 +68,13 @@ pub fn init(cx: &mut AppContext) { cx.add_action(ProjectSearchBar::next_history_query); cx.add_action(ProjectSearchBar::previous_history_query); cx.add_action(ProjectSearchBar::activate_regex_mode); + cx.add_action(ProjectSearchBar::activate_text_mode); + + // This action should only be registered if the semantic index is enabled + // We are registering it all the time, as I dont want to introduce a dependency + // for Semantic Index Settings globally whenever search is tested. + cx.add_action(ProjectSearchBar::activate_semantic_mode); + cx.capture_action(ProjectSearchBar::tab); cx.capture_action(ProjectSearchBar::tab_previous); add_toggle_option_action::(SearchOptions::CASE_SENSITIVE, cx); @@ -135,6 +147,13 @@ struct SemanticState { _subscription: Subscription, } +#[derive(Debug, Clone)] +struct ProjectSearchSettings { + search_options: SearchOptions, + filters_enabled: bool, + current_mode: SearchMode, +} + pub struct ProjectSearchBar { active_project_search: Option>, subscription: Option, @@ -460,6 +479,13 @@ impl View for ProjectSearchView { .insert(self.model.read(cx).project.downgrade(), handle) }); + cx.update_global(|state: &mut ActiveSettings, cx| { + state.0.insert( + self.model.read(cx).project.downgrade(), + self.current_settings(), + ); + }); + if cx.is_self_focused() { if self.query_editor_was_focused { cx.focus(&self.query_editor); @@ -483,6 +509,7 @@ impl Item for ProjectSearchView { fn should_close_item_on_event(event: &Self::Event) -> bool { event == &Self::Event::Dismiss } + fn act_as_type<'a>( &'a self, type_id: TypeId, @@ -593,7 +620,7 @@ impl Item for ProjectSearchView { Self: Sized, { let model = self.model.update(cx, |model, cx| model.clone(cx)); - Some(Self::new(model, cx)) + Some(Self::new(model, cx, None)) } fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext) { @@ -651,8 +678,31 @@ impl Item for ProjectSearchView { } impl ProjectSearchView { - fn toggle_search_option(&mut self, option: SearchOptions) { + fn toggle_filters(&mut self, cx: &mut ViewContext) { + self.filters_enabled = !self.filters_enabled; + cx.update_global(|state: &mut ActiveSettings, cx| { + state.0.insert( + self.model.read(cx).project.downgrade(), + self.current_settings(), + ); + }); + } + + fn current_settings(&self) -> ProjectSearchSettings { + ProjectSearchSettings { + search_options: self.search_options, + filters_enabled: self.filters_enabled, + current_mode: self.current_mode, + } + } + fn toggle_search_option(&mut self, option: SearchOptions, cx: &mut ViewContext) { self.search_options.toggle(option); + cx.update_global(|state: &mut ActiveSettings, cx| { + state.0.insert( + self.model.read(cx).project.downgrade(), + self.current_settings(), + ); + }); } fn index_project(&mut self, cx: &mut ViewContext) { @@ -785,14 +835,35 @@ impl ProjectSearchView { } } + cx.update_global(|state: &mut ActiveSettings, cx| { + state.0.insert( + self.model.read(cx).project.downgrade(), + self.current_settings(), + ); + }); + cx.notify(); } - fn new(model: ModelHandle, cx: &mut ViewContext) -> Self { + fn new( + model: ModelHandle, + cx: &mut ViewContext, + settings: Option, + ) -> Self { let project; let excerpts; let mut query_text = String::new(); - let mut options = SearchOptions::NONE; + + // Read in settings if available + let (mut options, current_mode, filters_enabled) = if let Some(settings) = settings { + ( + settings.search_options, + settings.current_mode, + settings.filters_enabled, + ) + } else { + (SearchOptions::NONE, Default::default(), false) + }; { let model = model.read(cx); @@ -871,7 +942,6 @@ impl ProjectSearchView { cx.emit(ViewEvent::EditorEvent(event.clone())) }) .detach(); - let filters_enabled = false; // Check if Worktrees have all been previously indexed let mut this = ProjectSearchView { @@ -888,7 +958,7 @@ impl ProjectSearchView { included_files_editor, excluded_files_editor, filters_enabled, - current_mode: Default::default(), + current_mode, }; this.model_changed(cx); this @@ -919,7 +989,7 @@ impl ProjectSearchView { }; let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx)); - let search = cx.add_view(|cx| ProjectSearchView::new(model, cx)); + let search = cx.add_view(|cx| ProjectSearchView::new(model, cx, None)); workspace.add_item(Box::new(search.clone()), cx); search.update(cx, |search, cx| { search @@ -969,8 +1039,20 @@ impl ProjectSearchView { workspace.activate_item(&existing, cx); existing } else { + let settings = cx + .global::() + .0 + .get(&workspace.project().downgrade()); + + let settings = if let Some(settings) = settings { + Some(settings.clone()) + } else { + None + }; + let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx)); - let view = cx.add_view(|cx| ProjectSearchView::new(model, cx)); + let view = cx.add_view(|cx| ProjectSearchView::new(model, cx, settings)); + workspace.add_item(Box::new(view.clone()), cx); view }; @@ -1246,7 +1328,7 @@ impl ProjectSearchBar { model }); workspace.add_item( - Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx))), + Box::new(cx.add_view(|cx| ProjectSearchView::new(model, cx, None))), cx, ); } @@ -1325,9 +1407,10 @@ impl ProjectSearchBar { fn toggle_search_option(&mut self, option: SearchOptions, cx: &mut ViewContext) -> bool { if let Some(search_view) = self.active_project_search.as_ref() { search_view.update(cx, |search_view, cx| { - search_view.toggle_search_option(option); + search_view.toggle_search_option(option, cx); search_view.search(cx); }); + cx.notify(); true } else { @@ -1335,6 +1418,19 @@ impl ProjectSearchBar { } } + fn activate_text_mode(pane: &mut Pane, _: &ActivateTextMode, cx: &mut ViewContext) { + if let Some(search_view) = pane + .active_item() + .and_then(|item| item.downcast::()) + { + search_view.update(cx, |view, cx| { + view.activate_search_mode(SearchMode::Text, cx) + }); + } else { + cx.propagate_action(); + } + } + fn activate_regex_mode(pane: &mut Pane, _: &ActivateRegexMode, cx: &mut ViewContext) { if let Some(search_view) = pane .active_item() @@ -1348,10 +1444,29 @@ impl ProjectSearchBar { } } + fn activate_semantic_mode( + pane: &mut Pane, + _: &ActivateSemanticMode, + cx: &mut ViewContext, + ) { + if SemanticIndex::enabled(cx) { + if let Some(search_view) = pane + .active_item() + .and_then(|item| item.downcast::()) + { + search_view.update(cx, |view, cx| { + view.activate_search_mode(SearchMode::Semantic, cx) + }); + } else { + cx.propagate_action(); + } + } + } + fn toggle_filters(&mut self, cx: &mut ViewContext) -> bool { if let Some(search_view) = self.active_project_search.as_ref() { search_view.update(cx, |search_view, cx| { - search_view.filters_enabled = !search_view.filters_enabled; + search_view.toggle_filters(cx); search_view .included_files_editor .update(cx, |_, cx| cx.notify()); @@ -1715,7 +1830,7 @@ pub mod tests { let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let search = cx.add_model(|cx| ProjectSearch::new(project, cx)); let search_view = cx - .add_window(|cx| ProjectSearchView::new(search.clone(), cx)) + .add_window(|cx| ProjectSearchView::new(search.clone(), cx, None)) .root(cx); search_view.update(cx, |search_view, cx| { diff --git a/crates/search/src/search.rs b/crates/search/src/search.rs index dabbc720cea9978aee65c76d5db1cbc5a3620167..ba06b3f9c772a5cd97483636fefc0d0c2bc7c191 100644 --- a/crates/search/src/search.rs +++ b/crates/search/src/search.rs @@ -39,7 +39,7 @@ actions!( ActivateSemanticMode, ActivateRegexMode, ReplaceAll, - ReplaceNext + ReplaceNext, ] ); diff --git a/crates/semantic_index/src/semantic_index_settings.rs b/crates/semantic_index/src/semantic_index_settings.rs index 86872457f841e1bfe1b601d1fb6d5d86a12911dc..dcfe05bab8ab1bb11e73f00a42a6f090c33aee93 100644 --- a/crates/semantic_index/src/semantic_index_settings.rs +++ b/crates/semantic_index/src/semantic_index_settings.rs @@ -6,13 +6,11 @@ use settings::Setting; #[derive(Deserialize, Debug)] pub struct SemanticIndexSettings { pub enabled: bool, - pub reindexing_delay_seconds: usize, } #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] pub struct SemanticIndexSettingsContent { pub enabled: Option, - pub reindexing_delay_seconds: Option, } impl Setting for SemanticIndexSettings {