mac: Delay initial find pasteboard search until ⌘G or ⌘F (#45605)

Follow up to https://github.com/zed-industries/zed/pull/45311. Instead
of searching for the string in the find pasteboard as soon as the pane
is focused, we will now wait until the search bar is either deployed or
`Select{Next|Prev}Match` is triggered.

Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga
2025-12-26 15:22:57 -03:00
committed by GitHub
parent a7ce677ac3
commit f1b723973b
2 changed files with 78 additions and 35 deletions

View File

@@ -4,6 +4,7 @@ use crate::{
FocusSearch, NextHistoryQuery, PreviousHistoryQuery, ReplaceAll, ReplaceNext, SearchOption,
SearchOptions, SearchSource, SelectAllMatches, SelectNextMatch, SelectPreviousMatch,
ToggleCaseSensitive, ToggleRegex, ToggleReplace, ToggleSelection, ToggleWholeWord,
buffer_search::registrar::WithResultsOrExternalQuery,
search_bar::{ActionButtonState, input_base_styles, render_action_button, render_text_input},
};
use any_vec::AnyVec;
@@ -43,7 +44,7 @@ use workspace::{
};
pub use registrar::DivRegistrar;
use registrar::{ForDeployed, ForDismissed, SearchActionsRegistrar, WithResults};
use registrar::{ForDeployed, ForDismissed, SearchActionsRegistrar};
const MAX_BUFFER_SEARCH_HISTORY_SIZE: usize = 50;
@@ -110,6 +111,8 @@ pub struct BufferSearchBar {
active_searchable_item_subscriptions: Option<[Subscription; 2]>,
#[cfg(not(target_os = "macos"))]
active_searchable_item_subscriptions: Option<Subscription>,
#[cfg(target_os = "macos")]
pending_external_query: Option<(String, SearchOptions)>,
active_search: Option<Arc<SearchQuery>>,
searchable_items_with_matches: HashMap<Box<dyn WeakSearchableItemHandle>, AnyVec<dyn Send>>,
pending_search: Option<Task<()>>,
@@ -510,24 +513,27 @@ impl ToolbarItemView for BufferSearchBar {
}
cx.defer_in(window, |this, window, cx| {
if let Some(item) = cx.read_from_find_pasteboard()
&& let Some(text) = item.text()
{
if this.query(cx) != text {
let search_options = item
.metadata()
.and_then(|m| m.parse().ok())
.and_then(SearchOptions::from_bits)
.unwrap_or(this.search_options);
let Some(item) = cx.read_from_find_pasteboard() else {
return;
};
let Some(text) = item.text() else {
return;
};
drop(this.search(
&text,
Some(search_options),
true,
window,
cx,
));
}
if this.query(cx) == text {
return;
}
let search_options = item
.metadata()
.and_then(|m| m.parse().ok())
.and_then(SearchOptions::from_bits)
.unwrap_or(this.search_options);
if this.dismissed {
this.pending_external_query = Some((text, search_options));
} else {
drop(this.search(&text, Some(search_options), true, window, cx));
}
});
}),
@@ -594,14 +600,16 @@ impl BufferSearchBar {
cx.propagate();
}
}));
registrar.register_handler(WithResults(|this, action: &SelectNextMatch, window, cx| {
if this.supported_options(cx).find_in_results {
cx.propagate();
} else {
this.select_next_match(action, window, cx);
}
}));
registrar.register_handler(WithResults(
registrar.register_handler(WithResultsOrExternalQuery(
|this, action: &SelectNextMatch, window, cx| {
if this.supported_options(cx).find_in_results {
cx.propagate();
} else {
this.select_next_match(action, window, cx);
}
},
));
registrar.register_handler(WithResultsOrExternalQuery(
|this, action: &SelectPreviousMatch, window, cx| {
if this.supported_options(cx).find_in_results {
cx.propagate();
@@ -610,7 +618,7 @@ impl BufferSearchBar {
}
},
));
registrar.register_handler(WithResults(
registrar.register_handler(WithResultsOrExternalQuery(
|this, action: &SelectAllMatches, window, cx| {
if this.supported_options(cx).find_in_results {
cx.propagate();
@@ -707,6 +715,8 @@ impl BufferSearchBar {
replacement_editor_focused: false,
active_searchable_item: None,
active_searchable_item_subscriptions: None,
#[cfg(target_os = "macos")]
pending_external_query: None,
active_match_index: None,
searchable_items_with_matches: Default::default(),
default_options: search_options,
@@ -852,11 +862,20 @@ impl BufferSearchBar {
self.search(&suggestion, Some(self.default_options), true, window, cx)
});
#[cfg(target_os = "macos")]
let search = search.or_else(|| {
self.pending_external_query
.take()
.map(|(query, options)| self.search(&query, Some(options), true, window, cx))
});
if let Some(search) = search {
cx.spawn_in(window, async move |this, cx| {
if search.await.is_ok() {
this.update_in(cx, |this, window, cx| {
this.activate_current_match(window, cx)
if !this.dismissed {
this.activate_current_match(window, cx)
}
})
} else {
Ok(())
@@ -1071,6 +1090,22 @@ impl BufferSearchBar {
window: &mut Window,
cx: &mut Context<Self>,
) {
#[cfg(target_os = "macos")]
if let Some((query, options)) = self.pending_external_query.take() {
let search_rx = self.search(&query, Some(options), true, window, cx);
cx.spawn_in(window, async move |this, cx| {
if search_rx.await.is_ok() {
this.update_in(cx, |this, window, cx| {
this.activate_current_match(window, cx);
})
.ok();
}
})
.detach();
return;
}
if let Some(index) = self.active_match_index
&& let Some(searchable_item) = self.active_searchable_item.as_ref()
&& let Some(matches) = self
@@ -1271,6 +1306,8 @@ impl BufferSearchBar {
let (done_tx, done_rx) = oneshot::channel();
let query = self.query(cx);
self.pending_search.take();
#[cfg(target_os = "macos")]
self.pending_external_query.take();
if let Some(active_searchable_item) = self.active_searchable_item.as_ref() {
self.query_error = None;
@@ -1367,8 +1404,8 @@ impl BufferSearchBar {
cx,
);
}
let _ = done_tx.send(());
}
let _ = done_tx.send(());
cx.notify();
}
})

View File

@@ -149,16 +149,16 @@ impl<A: Action> ActionExecutor<A> for ForDeployed<A> {
}
}
/// Run an action when the search bar has any matches, regardless of whether it
/// is visible or not.
pub struct WithResults<A>(pub(super) SearchBarActionCallback<A>);
impl<A> Clone for WithResults<A> {
/// Run an action when the search bar has any matches or a pending external query,
/// regardless of whether it is visible or not.
pub struct WithResultsOrExternalQuery<A>(pub(super) SearchBarActionCallback<A>);
impl<A> Clone for WithResultsOrExternalQuery<A> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<A: Action> ActionExecutor<A> for WithResults<A> {
impl<A: Action> ActionExecutor<A> for WithResultsOrExternalQuery<A> {
fn execute(
&self,
search_bar: &mut BufferSearchBar,
@@ -166,7 +166,13 @@ impl<A: Action> ActionExecutor<A> for WithResults<A> {
window: &mut Window,
cx: &mut Context<BufferSearchBar>,
) -> DidHandleAction {
if search_bar.active_match_index.is_some() {
#[cfg(not(target_os = "macos"))]
let has_external_query = false;
#[cfg(target_os = "macos")]
let has_external_query = search_bar.pending_external_query.is_some();
if has_external_query || search_bar.active_match_index.is_some() {
self.0(search_bar, action, window, cx);
true
} else {