From 306e4693fad8355c2e5d83f516de70e86449aded Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 17 Jan 2024 15:11:33 +0200 Subject: [PATCH 1/4] Start adding project search listeners to workspace co-authored-by: Piotr To be able to trigger them from search multibuffer excerpts. --- crates/assistant/src/assistant_panel.rs | 2 +- crates/search/src/buffer_search.rs | 72 +++++++++++++++++----- crates/search/src/project_search.rs | 70 ++++++++++++++++++++- crates/terminal_view/src/terminal_panel.rs | 2 +- 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index df3dc3754f66aff8d83a6fcd3b92edd38c7c4e45..5a8376554e9c66db347dc7012e45208a6ab5f157 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -1148,7 +1148,7 @@ impl Render for AssistantPanel { |panel, cx| panel.toolbar.read(cx).item_of_type::(), cx, ); - BufferSearchBar::register_inner(&mut registrar); + BufferSearchBar::register(&mut registrar); registrar.into_div() } else { div() diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index e217a7ab73cd2fd1aaa540f1b56cf13b7ec1c84b..4c6d9a5708e3f2965a223a26a979258822ab446e 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -496,67 +496,111 @@ impl SearchActionsRegistrar for Workspace { }); } } + impl BufferSearchBar { - pub fn register_inner(registrar: &mut impl SearchActionsRegistrar) { + pub fn register(registrar: &mut impl SearchActionsRegistrar) { registrar.register_handler(|this, action: &ToggleCaseSensitive, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + if this.supported_options().case { this.toggle_case_sensitive(action, cx); } }); - registrar.register_handler(|this, action: &ToggleWholeWord, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + if this.supported_options().word { this.toggle_whole_word(action, cx); } }); - registrar.register_handler(|this, action: &ToggleReplace, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + if this.supported_options().replacement { this.toggle_replace(action, cx); } }); - registrar.register_handler(|this, _: &ActivateRegexMode, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + if this.supported_options().regex { this.activate_search_mode(SearchMode::Regex, cx); } }); - registrar.register_handler(|this, _: &ActivateTextMode, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + this.activate_search_mode(SearchMode::Text, cx); }); - registrar.register_handler(|this, action: &CycleMode, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + if this.supported_options().regex { // If regex is not supported then search has just one mode (text) - in that case there's no point in supporting // cycling. this.cycle_mode(action, cx) } }); - registrar.register_handler(|this, action: &SelectNextMatch, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + this.select_next_match(action, cx); }); registrar.register_handler(|this, action: &SelectPrevMatch, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + this.select_prev_match(action, cx); }); registrar.register_handler(|this, action: &SelectAllMatches, cx| { + if this.is_dismissed() { + cx.propagate(); + return; + } + this.select_all_matches(action, cx); }); registrar.register_handler(|this, _: &editor::Cancel, cx| { - if this.dismissed { + if this.is_dismissed() { cx.propagate(); - } else { - this.dismiss(&Dismiss, cx); + return; } + + this.dismiss(&Dismiss, cx); }); registrar.register_handler(|this, deploy, cx| { - this.deploy(deploy, cx); + if this.is_dismissed() { + this.deploy(deploy, cx); + return; + } + + cx.propagate(); }) } - fn register(workspace: &mut Workspace) { - Self::register_inner(workspace); - } + pub fn new(cx: &mut ViewContext) -> Self { let query_editor = cx.new_view(|cx| Editor::single_line(cx)); cx.subscribe(&query_editor, Self::on_query_editor_event) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 49eb24ce9ee9e267dc921b6ddb8eb10e92c83c97..30c29a0c089c067d1482074a7940892b3497929d 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -63,7 +63,57 @@ pub fn init(cx: &mut AppContext) { workspace .register_action(ProjectSearchView::new_search) .register_action(ProjectSearchView::deploy_search) - .register_action(ProjectSearchBar::search_in_new); + .register_action(ProjectSearchBar::search_in_new) + // TODO kb register these too, consider having the methods for &Workspace for that, as above + // ToggleCaseSensitive + // ToggleWholeWord + // ToggleReplace + // ActivateRegexMode + // SelectPrevMatch + // ActivateTextMode + // ActivateSemanticMode + // CycleMode + // SelectNextMatch (see a proto below) + /* + // Have a generic method similar to the registrar has: + fn register_workspace_action( + &mut workspace, + callback: fn(&mut ProjectSearchBar, &A, &mut ViewContext), + ) { + workspace.register_action(move |workspace, action: &A, cx| { + if workspace.has_active_modal(cx) { + cx.propagate(); + return; + } + if let Some(search_bar) = workspace.active_item(cx).and_then(|item| item.downcast::()) { + search_bar.update(cx, move |this, cx| callback(this, action, cx)); + cx.notify(); + } + }); + } + */ + .register_action(move |workspace, action: &SelectNextMatch, cx| { + dbg!("@@@@@@@@@1"); + if workspace.has_active_modal(cx) { + cx.propagate(); + return; + } + + dbg!("????? 2"); + let pane = workspace.active_pane(); + pane.update(cx, move |this, cx| { + this.toolbar().update(cx, move |this, cx| { + dbg!("@@@@@@@@@ 3"); + if let Some(search_bar) = this.item_of_type::() { + dbg!("$$$$$$$$$ 4"); + search_bar.update(cx, move |search_bar, cx| { + search_bar.select_next_match(action, cx) + }); + cx.notify(); + } + }) + }); + }); }) .detach(); } @@ -1502,6 +1552,22 @@ impl ProjectSearchBar { } } + pub fn select_next_match(&mut self, _: &SelectNextMatch, cx: &mut ViewContext) { + if let Some(search) = self.active_project_search.as_ref() { + search.update(cx, |this, cx| { + this.select_match(Direction::Next, cx); + }) + } + } + + fn select_prev_match(&mut self, _: &SelectPrevMatch, cx: &mut ViewContext) { + if let Some(search) = self.active_project_search.as_ref() { + search.update(cx, |this, cx| { + this.select_match(Direction::Prev, cx); + }) + } + } + fn new_placeholder_text(&self, cx: &mut ViewContext) -> Option { let previous_query_keystrokes = cx .bindings_for_action(&PreviousHistoryQuery {}) @@ -1870,6 +1936,8 @@ impl Render for ProjectSearchBar { })) }) }) + .on_action(cx.listener(Self::select_next_match)) + .on_action(cx.listener(Self::select_prev_match)) .child( h_flex() .justify_between() diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 8954e70e8fc18d3d78775ba4eb56b11ec251c0de..7a988851d8a34b8533631e1f74dfcb5d73c45ed1 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -387,7 +387,7 @@ impl Render for TerminalPanel { }, cx, ); - BufferSearchBar::register_inner(&mut registrar); + BufferSearchBar::register(&mut registrar); registrar.into_div().size_full().child(self.pane.clone()) } } From 0be2f7f32891c628fbb02771cfcf7f1453804960 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 17 Jan 2024 21:09:28 +0200 Subject: [PATCH 2/4] Properly register buffer_search'es actions handlers Now those handlers do not intercept events/actions when the buffer search bar is dismissed. co-authored-by: Piotr --- crates/search/src/buffer_search.rs | 162 +++++++++++++++++----------- crates/search/src/project_search.rs | 4 - 2 files changed, 100 insertions(+), 66 deletions(-) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 4c6d9a5708e3f2965a223a26a979258822ab446e..ee395328c38b459ecff5e19e7d47d97ca719f692 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -429,6 +429,11 @@ pub trait SearchActionsRegistrar { &mut self, callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ); + + fn register_handler_for_dismissed_bar( + &mut self, + callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), + ); } type GetSearchBar = @@ -457,16 +462,60 @@ impl<'a, 'b, T: 'static> DivRegistrar<'a, 'b, T> { } impl SearchActionsRegistrar for DivRegistrar<'_, '_, T> { - fn register_handler( + fn register_handler( &mut self, callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ) { let getter = self.search_getter; self.div = self.div.take().map(|div| { div.on_action(self.cx.listener(move |this, action, cx| { - (getter)(this, cx) + let should_notify = (getter)(this, cx) .clone() - .map(|search_bar| search_bar.update(cx, |this, cx| callback(this, action, cx))); + .map(|search_bar| { + search_bar.update(cx, |search_bar, cx| { + if search_bar.is_dismissed() { + false + } else { + callback(search_bar, action, cx); + true + } + }) + }) + .unwrap_or(false); + if should_notify { + cx.notify(); + } else { + cx.propagate(); + } + })) + }); + } + + fn register_handler_for_dismissed_bar( + &mut self, + callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), + ) { + let getter = self.search_getter; + self.div = self.div.take().map(|div| { + div.on_action(self.cx.listener(move |this, action, cx| { + let should_notify = (getter)(this, cx) + .clone() + .map(|search_bar| { + search_bar.update(cx, |search_bar, cx| { + if search_bar.is_dismissed() { + callback(search_bar, action, cx); + true + } else { + false + } + }) + }) + .unwrap_or(false); + if should_notify { + cx.notify(); + } else { + cx.propagate(); + } })) }); } @@ -488,71 +537,85 @@ impl SearchActionsRegistrar for Workspace { pane.update(cx, move |this, cx| { this.toolbar().update(cx, move |this, cx| { if let Some(search_bar) = this.item_of_type::() { - search_bar.update(cx, move |this, cx| callback(this, action, cx)); - cx.notify(); + let should_notify = search_bar.update(cx, move |search_bar, cx| { + if search_bar.is_dismissed() { + false + } else { + callback(search_bar, action, cx); + true + } + }); + if should_notify { + cx.notify(); + } else { + cx.propagate(); + } } }) }); }); } -} -impl BufferSearchBar { - pub fn register(registrar: &mut impl SearchActionsRegistrar) { - registrar.register_handler(|this, action: &ToggleCaseSensitive, cx| { - if this.is_dismissed() { + fn register_handler_for_dismissed_bar( + &mut self, + callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), + ) { + self.register_action(move |workspace, action: &A, cx| { + if workspace.has_active_modal(cx) { cx.propagate(); return; } + let pane = workspace.active_pane(); + pane.update(cx, move |this, cx| { + this.toolbar().update(cx, move |this, cx| { + if let Some(search_bar) = this.item_of_type::() { + let should_notify = search_bar.update(cx, move |search_bar, cx| { + if search_bar.is_dismissed() { + callback(search_bar, action, cx); + true + } else { + false + } + }); + if should_notify { + cx.notify(); + } else { + cx.propagate(); + } + } + }) + }); + }); + } +} + +impl BufferSearchBar { + pub fn register(registrar: &mut impl SearchActionsRegistrar) { + registrar.register_handler(|this, action: &ToggleCaseSensitive, cx| { if this.supported_options().case { this.toggle_case_sensitive(action, cx); } }); registrar.register_handler(|this, action: &ToggleWholeWord, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - if this.supported_options().word { this.toggle_whole_word(action, cx); } }); registrar.register_handler(|this, action: &ToggleReplace, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - if this.supported_options().replacement { this.toggle_replace(action, cx); } }); registrar.register_handler(|this, _: &ActivateRegexMode, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - if this.supported_options().regex { this.activate_search_mode(SearchMode::Regex, cx); } }); registrar.register_handler(|this, _: &ActivateTextMode, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - this.activate_search_mode(SearchMode::Text, cx); }); registrar.register_handler(|this, action: &CycleMode, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - if this.supported_options().regex { // If regex is not supported then search has just one mode (text) - in that case there's no point in supporting // cycling. @@ -560,44 +623,19 @@ impl BufferSearchBar { } }); registrar.register_handler(|this, action: &SelectNextMatch, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - this.select_next_match(action, cx); }); registrar.register_handler(|this, action: &SelectPrevMatch, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - this.select_prev_match(action, cx); }); registrar.register_handler(|this, action: &SelectAllMatches, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - this.select_all_matches(action, cx); }); registrar.register_handler(|this, _: &editor::Cancel, cx| { - if this.is_dismissed() { - cx.propagate(); - return; - } - this.dismiss(&Dismiss, cx); }); - registrar.register_handler(|this, deploy, cx| { - if this.is_dismissed() { - this.deploy(deploy, cx); - return; - } - - cx.propagate(); + registrar.register_handler_for_dismissed_bar(|this, deploy, cx| { + this.deploy(deploy, cx); }) } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 30c29a0c089c067d1482074a7940892b3497929d..a13f70fbe8a394c7b6a092fe4ce4ddf155128312 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -93,19 +93,15 @@ pub fn init(cx: &mut AppContext) { } */ .register_action(move |workspace, action: &SelectNextMatch, cx| { - dbg!("@@@@@@@@@1"); if workspace.has_active_modal(cx) { cx.propagate(); return; } - dbg!("????? 2"); let pane = workspace.active_pane(); pane.update(cx, move |this, cx| { this.toolbar().update(cx, move |this, cx| { - dbg!("@@@@@@@@@ 3"); if let Some(search_bar) = this.item_of_type::() { - dbg!("$$$$$$$$$ 4"); search_bar.update(cx, move |search_bar, cx| { search_bar.select_next_match(action, cx) }); From 65be90937887fcbfb114e7e7a0154579ff371eff Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 17 Jan 2024 22:07:00 +0200 Subject: [PATCH 3/4] Implement similar workspace registration flow for project search actions --- crates/search/src/buffer_search.rs | 8 +- crates/search/src/project_search.rs | 241 +++++++++++++++++----------- 2 files changed, 153 insertions(+), 96 deletions(-) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index ee395328c38b459ecff5e19e7d47d97ca719f692..e4a68b6105eb0ca6a55e89136822041524391820 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -430,7 +430,7 @@ pub trait SearchActionsRegistrar { callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ); - fn register_handler_for_dismissed_bar( + fn register_handler_for_dismissed_search( &mut self, callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ); @@ -491,7 +491,7 @@ impl SearchActionsRegistrar for DivRegistrar<'_, '_, T> { }); } - fn register_handler_for_dismissed_bar( + fn register_handler_for_dismissed_search( &mut self, callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ) { @@ -556,7 +556,7 @@ impl SearchActionsRegistrar for Workspace { }); } - fn register_handler_for_dismissed_bar( + fn register_handler_for_dismissed_search( &mut self, callback: fn(&mut BufferSearchBar, &A, &mut ViewContext), ) { @@ -634,7 +634,7 @@ impl BufferSearchBar { registrar.register_handler(|this, _: &editor::Cancel, cx| { this.dismiss(&Dismiss, cx); }); - registrar.register_handler_for_dismissed_bar(|this, deploy, cx| { + registrar.register_handler_for_dismissed_search(|this, deploy, cx| { this.deploy(deploy, cx); }) } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index a13f70fbe8a394c7b6a092fe4ce4ddf155128312..098fa184e353ab58b05a6e5709b0eb62f1a5a16f 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -12,10 +12,10 @@ use editor::{ }; use editor::{EditorElement, EditorStyle}; use gpui::{ - actions, div, AnyElement, AnyView, AppContext, Context as _, Element, EntityId, EventEmitter, - FocusHandle, FocusableView, FontStyle, FontWeight, Hsla, InteractiveElement, IntoElement, - KeyContext, Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled, - Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView, + actions, div, Action, AnyElement, AnyView, AppContext, Context as _, Element, EntityId, + EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, Hsla, InteractiveElement, + IntoElement, KeyContext, Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, + Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace, WindowContext, }; use menu::Confirm; @@ -36,6 +36,7 @@ use std::{ time::{Duration, Instant}, }; use theme::ThemeSettings; +use workspace::{DeploySearch, NewSearch}; use ui::{ h_flex, prelude::*, v_flex, Icon, IconButton, IconName, Label, LabelCommon, LabelSize, @@ -60,56 +61,64 @@ struct ActiveSettings(HashMap, ProjectSearchSettings>); pub fn init(cx: &mut AppContext) { cx.set_global(ActiveSettings::default()); cx.observe_new_views(|workspace: &mut Workspace, _cx| { - workspace - .register_action(ProjectSearchView::new_search) - .register_action(ProjectSearchView::deploy_search) - .register_action(ProjectSearchBar::search_in_new) - // TODO kb register these too, consider having the methods for &Workspace for that, as above - // ToggleCaseSensitive - // ToggleWholeWord - // ToggleReplace - // ActivateRegexMode - // SelectPrevMatch - // ActivateTextMode - // ActivateSemanticMode - // CycleMode - // SelectNextMatch (see a proto below) - /* - // Have a generic method similar to the registrar has: - fn register_workspace_action( - &mut workspace, - callback: fn(&mut ProjectSearchBar, &A, &mut ViewContext), - ) { - workspace.register_action(move |workspace, action: &A, cx| { - if workspace.has_active_modal(cx) { - cx.propagate(); - return; - } - if let Some(search_bar) = workspace.active_item(cx).and_then(|item| item.downcast::()) { - search_bar.update(cx, move |this, cx| callback(this, action, cx)); - cx.notify(); - } - }); - } - */ - .register_action(move |workspace, action: &SelectNextMatch, cx| { - if workspace.has_active_modal(cx) { - cx.propagate(); - return; - } + register_workspace_action(workspace, move |search_bar, _: &ToggleFilters, cx| { + search_bar.toggle_filters(cx); + }); + register_workspace_action(workspace, move |search_bar, _: &ToggleCaseSensitive, cx| { + search_bar.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx); + }); + register_workspace_action(workspace, move |search_bar, _: &ToggleWholeWord, cx| { + search_bar.toggle_search_option(SearchOptions::WHOLE_WORD, cx); + }); + register_workspace_action(workspace, move |search_bar, action: &ToggleReplace, cx| { + search_bar.toggle_replace(action, cx) + }); + register_workspace_action(workspace, move |search_bar, _: &ActivateRegexMode, cx| { + search_bar.activate_search_mode(SearchMode::Regex, cx) + }); + register_workspace_action(workspace, move |search_bar, _: &ActivateTextMode, cx| { + search_bar.activate_search_mode(SearchMode::Text, cx) + }); + register_workspace_action( + workspace, + move |search_bar, _: &ActivateSemanticMode, cx| { + search_bar.activate_search_mode(SearchMode::Semantic, cx) + }, + ); + register_workspace_action(workspace, move |search_bar, action: &CycleMode, cx| { + search_bar.cycle_mode(action, cx) + }); + register_workspace_action( + workspace, + move |search_bar, action: &SelectNextMatch, cx| { + search_bar.select_next_match(action, cx) + }, + ); + register_workspace_action( + workspace, + move |search_bar, action: &SelectPrevMatch, cx| { + search_bar.select_prev_match(action, cx) + }, + ); - let pane = workspace.active_pane(); - pane.update(cx, move |this, cx| { - this.toolbar().update(cx, move |this, cx| { - if let Some(search_bar) = this.item_of_type::() { - search_bar.update(cx, move |search_bar, cx| { - search_bar.select_next_match(action, cx) - }); - cx.notify(); - } - }) - }); - }); + register_workspace_action_for_dismissed_search( + workspace, + move |workspace, action: &NewSearch, cx| { + ProjectSearchView::new_search(workspace, action, cx) + }, + ); + register_workspace_action_for_dismissed_search( + workspace, + move |workspace, action: &DeploySearch, cx| { + ProjectSearchView::deploy_search(workspace, action, cx) + }, + ); + register_workspace_action_for_dismissed_search( + workspace, + move |workspace, action: &SearchInNew, cx| { + ProjectSearchView::search_in_new(workspace, action, cx) + }, + ); }) .detach(); } @@ -1006,6 +1015,37 @@ impl ProjectSearchView { Self::existing_or_new_search(workspace, existing, cx) } + fn search_in_new(workspace: &mut Workspace, _: &SearchInNew, cx: &mut ViewContext) { + if let Some(search_view) = workspace + .active_item(cx) + .and_then(|item| item.downcast::()) + { + let new_query = search_view.update(cx, |search_view, cx| { + let new_query = search_view.build_search_query(cx); + if new_query.is_some() { + if let Some(old_query) = search_view.model.read(cx).active_query.clone() { + search_view.query_editor.update(cx, |editor, cx| { + editor.set_text(old_query.as_str(), cx); + }); + search_view.search_options = SearchOptions::from_query(&old_query); + } + } + new_query + }); + if let Some(new_query) = new_query { + let model = cx.new_model(|cx| { + let mut model = ProjectSearch::new(workspace.project().clone(), cx); + model.search(new_query, cx); + model + }); + workspace.add_item( + Box::new(cx.new_view(|cx| ProjectSearchView::new(model, cx, None))), + cx, + ); + } + } + } + // Add another search tab to the workspace. fn new_search( workspace: &mut Workspace, @@ -1308,17 +1348,11 @@ impl ProjectSearchView { } } -impl Default for ProjectSearchBar { - fn default() -> Self { - Self::new() - } -} - impl ProjectSearchBar { pub fn new() -> Self { Self { - active_project_search: Default::default(), - subscription: Default::default(), + active_project_search: None, + subscription: None, } } @@ -1349,37 +1383,6 @@ impl ProjectSearchBar { } } - fn search_in_new(workspace: &mut Workspace, _: &SearchInNew, cx: &mut ViewContext) { - if let Some(search_view) = workspace - .active_item(cx) - .and_then(|item| item.downcast::()) - { - let new_query = search_view.update(cx, |search_view, cx| { - let new_query = search_view.build_search_query(cx); - if new_query.is_some() { - if let Some(old_query) = search_view.model.read(cx).active_query.clone() { - search_view.query_editor.update(cx, |editor, cx| { - editor.set_text(old_query.as_str(), cx); - }); - search_view.search_options = SearchOptions::from_query(&old_query); - } - } - new_query - }); - if let Some(new_query) = new_query { - let model = cx.new_model(|cx| { - let mut model = ProjectSearch::new(workspace.project().clone(), cx); - model.search(new_query, cx); - model - }); - workspace.add_item( - Box::new(cx.new_view(|cx| ProjectSearchView::new(model, cx, None))), - cx, - ); - } - } - } - fn tab(&mut self, _: &editor::Tab, cx: &mut ViewContext) { self.cycle_field(Direction::Next, cx); } @@ -2027,6 +2030,60 @@ impl ToolbarItemView for ProjectSearchBar { } } +fn register_workspace_action( + workspace: &mut Workspace, + callback: fn(&mut ProjectSearchBar, &A, &mut ViewContext), +) { + workspace.register_action(move |workspace, action: &A, cx| { + if workspace.has_active_modal(cx) { + cx.propagate(); + return; + } + + workspace.active_pane().update(cx, |pane, cx| { + pane.toolbar().update(cx, move |workspace, cx| { + if let Some(search_bar) = workspace.item_of_type::() { + search_bar.update(cx, move |search_bar, cx| { + if search_bar.active_project_search.is_some() { + callback(search_bar, action, cx); + cx.notify(); + } else { + cx.propagate(); + } + }); + } + }); + }) + }); +} + +fn register_workspace_action_for_dismissed_search( + workspace: &mut Workspace, + callback: fn(&mut Workspace, &A, &mut ViewContext), +) { + workspace.register_action(move |workspace, action: &A, cx| { + if workspace.has_active_modal(cx) { + cx.propagate(); + return; + } + + let should_notify = workspace + .active_pane() + .read(cx) + .toolbar() + .read(cx) + .item_of_type::() + .map(|search_bar| search_bar.read(cx).active_project_search.is_none()) + .unwrap_or(false); + if should_notify { + callback(workspace, action, cx); + cx.notify(); + } else { + cx.propagate(); + } + }); +} + #[cfg(test)] pub mod tests { use super::*; From 1e6757755ef5b34089d90aa8733a248fa8afe74f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 17 Jan 2024 22:18:54 +0200 Subject: [PATCH 4/4] Ignore buffer search events if it's not for the current buffer --- crates/search/src/buffer_search.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index e4a68b6105eb0ca6a55e89136822041524391820..fbc7101355e08a0701f71559e98b4711a076d38d 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -473,7 +473,9 @@ impl SearchActionsRegistrar for DivRegistrar<'_, '_, T> { .clone() .map(|search_bar| { search_bar.update(cx, |search_bar, cx| { - if search_bar.is_dismissed() { + if search_bar.is_dismissed() + || search_bar.active_searchable_item.is_none() + { false } else { callback(search_bar, action, cx); @@ -538,7 +540,9 @@ impl SearchActionsRegistrar for Workspace { this.toolbar().update(cx, move |this, cx| { if let Some(search_bar) = this.item_of_type::() { let should_notify = search_bar.update(cx, move |search_bar, cx| { - if search_bar.is_dismissed() { + if search_bar.is_dismissed() + || search_bar.active_searchable_item.is_none() + { false } else { callback(search_bar, action, cx);