Detailed changes
@@ -61,7 +61,7 @@ use ui::{
use util::{ResultExt, maybe};
use workspace::{
CollaboratorId,
- searchable::{Direction, SearchableItemHandle},
+ searchable::{Direction, SearchToken, SearchableItemHandle},
};
use workspace::{
@@ -2799,11 +2799,12 @@ impl SearchableItem for TextThreadEditor {
&mut self,
matches: &[Self::Match],
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
- editor.update_matches(matches, active_match_index, window, cx)
+ editor.update_matches(matches, active_match_index, token, window, cx)
});
}
@@ -2816,33 +2817,37 @@ impl SearchableItem for TextThreadEditor {
&mut self,
index: usize,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
- editor.activate_match(index, matches, window, cx);
+ editor.activate_match(index, matches, token, window, cx);
});
}
fn select_matches(
&mut self,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.editor
- .update(cx, |editor, cx| editor.select_matches(matches, window, cx));
+ self.editor.update(cx, |editor, cx| {
+ editor.select_matches(matches, token, window, cx)
+ });
}
fn replace(
&mut self,
identifier: &Self::Match,
query: &project::search::SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |editor, cx| {
- editor.replace(identifier, query, window, cx)
+ editor.replace(identifier, query, token, window, cx)
});
}
@@ -2860,11 +2865,12 @@ impl SearchableItem for TextThreadEditor {
&mut self,
direction: Direction,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
self.editor.update(cx, |editor, cx| {
- editor.active_match_index(direction, matches, window, cx)
+ editor.active_match_index(direction, matches, token, window, cx)
})
}
}
@@ -28,7 +28,7 @@ use util::maybe;
use workspace::{
ToolbarItemEvent, ToolbarItemView, Workspace,
item::Item,
- searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
+ searchable::{Direction, SearchEvent, SearchToken, SearchableItem, SearchableItemHandle},
ui::{Button, Clickable, ContextMenu, Label, LabelCommon, PopoverMenu, h_flex},
};
@@ -1018,11 +1018,12 @@ impl SearchableItem for DapLogView {
&mut self,
matches: &[Self::Match],
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |e, cx| {
- e.update_matches(matches, active_match_index, window, cx)
+ e.update_matches(matches, active_match_index, token, window, cx)
})
}
@@ -1035,21 +1036,24 @@ impl SearchableItem for DapLogView {
&mut self,
index: usize,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.editor
- .update(cx, |e, cx| e.activate_match(index, matches, window, cx))
+ self.editor.update(cx, |e, cx| {
+ e.activate_match(index, matches, token, window, cx)
+ })
}
fn select_matches(
&mut self,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor
- .update(cx, |e, cx| e.select_matches(matches, window, cx))
+ .update(cx, |e, cx| e.select_matches(matches, token, window, cx))
}
fn find_matches(
@@ -1066,6 +1070,7 @@ impl SearchableItem for DapLogView {
&mut self,
_: &Self::Match,
_: &SearchQuery,
+ _token: SearchToken,
_window: &mut Window,
_: &mut Context<Self>,
) {
@@ -1087,11 +1092,12 @@ impl SearchableItem for DapLogView {
&mut self,
direction: Direction,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
self.editor.update(cx, |e, cx| {
- e.active_match_index(direction, matches, window, cx)
+ e.active_match_index(direction, matches, token, window, cx)
})
}
}
@@ -46,7 +46,8 @@ use workspace::{
invalid_item_view::InvalidItemView,
item::{FollowableItem, Item, ItemBufferKind, ItemEvent, ProjectItem, SaveOptions},
searchable::{
- Direction, FilteredSearchRange, SearchEvent, SearchableItem, SearchableItemHandle,
+ Direction, FilteredSearchRange, SearchEvent, SearchToken, SearchableItem,
+ SearchableItemHandle,
},
};
use workspace::{
@@ -1496,12 +1497,15 @@ impl Editor {
impl SearchableItem for Editor {
type Match = Range<Anchor>;
- fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Range<Anchor>> {
- self.background_highlights
- .get(&HighlightKey::BufferSearchHighlights)
- .map_or(Vec::new(), |(_color, ranges)| {
- ranges.iter().cloned().collect()
- })
+ fn get_matches(&self, _window: &mut Window, _: &mut App) -> (Vec<Range<Anchor>>, SearchToken) {
+ (
+ self.background_highlights
+ .get(&HighlightKey::BufferSearchHighlights)
+ .map_or(Vec::new(), |(_color, ranges)| {
+ ranges.iter().cloned().collect()
+ }),
+ SearchToken::default(),
+ )
}
fn clear_matches(&mut self, _: &mut Window, cx: &mut Context<Self>) {
@@ -1517,6 +1521,7 @@ impl SearchableItem for Editor {
&mut self,
matches: &[Range<Anchor>],
active_match_index: Option<usize>,
+ _token: SearchToken,
_: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1630,6 +1635,7 @@ impl SearchableItem for Editor {
&mut self,
index: usize,
matches: &[Range<Anchor>],
+ _token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1648,6 +1654,7 @@ impl SearchableItem for Editor {
fn select_matches(
&mut self,
matches: &[Self::Match],
+ _token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1660,6 +1667,7 @@ impl SearchableItem for Editor {
&mut self,
identifier: &Self::Match,
query: &SearchQuery,
+ _token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1683,6 +1691,7 @@ impl SearchableItem for Editor {
&mut self,
matches: &mut dyn Iterator<Item = &Self::Match>,
query: &SearchQuery,
+ _token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1725,6 +1734,7 @@ impl SearchableItem for Editor {
current_index: usize,
direction: Direction,
count: usize,
+ _token: SearchToken,
_: &mut Window,
cx: &mut Context<Self>,
) -> usize {
@@ -1832,6 +1842,7 @@ impl SearchableItem for Editor {
&mut self,
direction: Direction,
matches: &[Range<Anchor>],
+ _token: SearchToken,
_: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
@@ -24,12 +24,13 @@ use ui::{
use crate::{
display_map::CompanionExcerptPatch,
+ element::SplitSide,
split_editor_view::{SplitEditorState, SplitEditorView},
};
use workspace::{
ActivatePaneLeft, ActivatePaneRight, Item, ToolbarItemLocation, Workspace,
item::{BreadcrumbText, ItemBufferKind, ItemEvent, SaveOptions, TabContentParams},
- searchable::{SearchEvent, SearchableItem, SearchableItemHandle},
+ searchable::{SearchEvent, SearchToken, SearchableItem, SearchableItemHandle},
};
use crate::{
@@ -381,6 +382,7 @@ pub struct SplittableEditor {
lhs: Option<LhsEditor>,
workspace: WeakEntity<Workspace>,
split_state: Entity<SplitEditorState>,
+ searched_side: Option<SplitSide>,
_subscriptions: Vec<Subscription>,
}
@@ -420,7 +422,17 @@ impl SplittableEditor {
}
}
- pub fn last_selected_editor(&self) -> &Entity<Editor> {
+ fn focused_side(&self) -> SplitSide {
+ if let Some(lhs) = &self.lhs
+ && lhs.was_last_focused
+ {
+ SplitSide::Left
+ } else {
+ SplitSide::Right
+ }
+ }
+
+ pub fn focused_editor(&self) -> &Entity<Editor> {
if let Some(lhs) = &self.lhs
&& lhs.was_last_focused
{
@@ -459,8 +471,10 @@ impl SplittableEditor {
_ => cx.emit(event.clone()),
},
),
- cx.subscribe(&rhs_editor, |_, _, event: &SearchEvent, cx| {
- cx.emit(event.clone());
+ cx.subscribe(&rhs_editor, |this, _, event: &SearchEvent, cx| {
+ if this.searched_side.is_none() || this.searched_side == Some(SplitSide::Right) {
+ cx.emit(event.clone());
+ }
}),
];
@@ -493,6 +507,7 @@ impl SplittableEditor {
lhs: None,
workspace: workspace.downgrade(),
split_state,
+ searched_side: None,
_subscriptions: subscriptions,
}
}
@@ -596,13 +611,20 @@ impl SplittableEditor {
},
)];
+ subscriptions.push(
+ cx.subscribe(&lhs_editor, |this, _, event: &SearchEvent, cx| {
+ if this.searched_side == Some(SplitSide::Left) {
+ cx.emit(event.clone());
+ }
+ }),
+ );
+
let lhs_focus_handle = lhs_editor.read(cx).focus_handle(cx);
subscriptions.push(
cx.on_focus_in(&lhs_focus_handle, window, |this, _window, cx| {
if let Some(lhs) = &mut this.lhs {
if !lhs.was_last_focused {
lhs.was_last_focused = true;
- cx.emit(SearchEvent::MatchesInvalidated);
cx.notify();
}
}
@@ -615,7 +637,6 @@ impl SplittableEditor {
if let Some(lhs) = &mut this.lhs {
if lhs.was_last_focused {
lhs.was_last_focused = false;
- cx.emit(SearchEvent::MatchesInvalidated);
cx.notify();
}
}
@@ -1085,6 +1106,19 @@ impl SplittableEditor {
});
}
}
+
+ fn search_token(&self) -> SearchToken {
+ SearchToken::new(self.focused_side() as u64)
+ }
+
+ fn editor_for_token(&self, token: SearchToken) -> &Entity<Editor> {
+ if token.value() == SplitSide::Left as u64 {
+ if let Some(lhs) = &self.lhs {
+ return &lhs.editor;
+ }
+ }
+ &self.rhs_editor
+ }
}
#[cfg(test)]
@@ -1665,12 +1699,12 @@ impl Item for SplittableEditor {
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
- self.last_selected_editor()
+ self.focused_editor()
.update(cx, |editor, cx| editor.navigate(data, window, cx))
}
fn deactivated(&mut self, window: &mut Window, cx: &mut Context<Self>) {
- self.last_selected_editor().update(cx, |editor, cx| {
+ self.focused_editor().update(cx, |editor, cx| {
editor.deactivated(window, cx);
});
}
@@ -1709,9 +1743,7 @@ impl Item for SplittableEditor {
}
fn pixel_position_of_cursor(&self, cx: &App) -> Option<gpui::Point<gpui::Pixels>> {
- self.last_selected_editor()
- .read(cx)
- .pixel_position_of_cursor(cx)
+ self.focused_editor().read(cx).pixel_position_of_cursor(cx)
}
}
@@ -1719,25 +1751,59 @@ impl SearchableItem for SplittableEditor {
type Match = Range<Anchor>;
fn clear_matches(&mut self, window: &mut Window, cx: &mut Context<Self>) {
- self.last_selected_editor().update(cx, |editor, cx| {
+ self.rhs_editor.update(cx, |editor, cx| {
editor.clear_matches(window, cx);
});
+ if let Some(lhs_editor) = self.lhs_editor() {
+ lhs_editor.update(cx, |editor, cx| {
+ editor.clear_matches(window, cx);
+ })
+ }
}
fn update_matches(
&mut self,
matches: &[Self::Match],
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.last_selected_editor().update(cx, |editor, cx| {
- editor.update_matches(matches, active_match_index, window, cx);
+ self.editor_for_token(token).update(cx, |editor, cx| {
+ editor.update_matches(matches, active_match_index, token, window, cx);
});
}
+ fn search_bar_visibility_changed(
+ &mut self,
+ visible: bool,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if visible {
+ let side = self.focused_side();
+ self.searched_side = Some(side);
+ match side {
+ SplitSide::Left => {
+ self.rhs_editor.update(cx, |editor, cx| {
+ editor.clear_matches(window, cx);
+ });
+ }
+ SplitSide::Right => {
+ if let Some(lhs) = &self.lhs {
+ lhs.editor.update(cx, |editor, cx| {
+ editor.clear_matches(window, cx);
+ });
+ }
+ }
+ }
+ } else {
+ self.searched_side = None;
+ }
+ }
+
fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context<Self>) -> String {
- self.last_selected_editor()
+ self.focused_editor()
.update(cx, |editor, cx| editor.query_suggestion(window, cx))
}
@@ -1745,22 +1811,24 @@ impl SearchableItem for SplittableEditor {
&mut self,
index: usize,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.last_selected_editor().update(cx, |editor, cx| {
- editor.activate_match(index, matches, window, cx);
+ self.editor_for_token(token).update(cx, |editor, cx| {
+ editor.activate_match(index, matches, token, window, cx);
});
}
fn select_matches(
&mut self,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.last_selected_editor().update(cx, |editor, cx| {
- editor.select_matches(matches, window, cx);
+ self.editor_for_token(token).update(cx, |editor, cx| {
+ editor.select_matches(matches, token, window, cx);
});
}
@@ -1768,11 +1836,12 @@ impl SearchableItem for SplittableEditor {
&mut self,
identifier: &Self::Match,
query: &project::search::SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.last_selected_editor().update(cx, |editor, cx| {
- editor.replace(identifier, query, window, cx);
+ self.editor_for_token(token).update(cx, |editor, cx| {
+ editor.replace(identifier, query, token, window, cx);
});
}
@@ -1782,19 +1851,41 @@ impl SearchableItem for SplittableEditor {
window: &mut Window,
cx: &mut Context<Self>,
) -> gpui::Task<Vec<Self::Match>> {
- self.last_selected_editor()
+ self.focused_editor()
.update(cx, |editor, cx| editor.find_matches(query, window, cx))
}
+ fn find_matches_with_token(
+ &mut self,
+ query: Arc<project::search::SearchQuery>,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) -> gpui::Task<(Vec<Self::Match>, SearchToken)> {
+ let token = self.search_token();
+ let editor = self.focused_editor().downgrade();
+ cx.spawn_in(window, async move |_, cx| {
+ let Some(matches) = editor
+ .update_in(cx, |editor, window, cx| {
+ editor.find_matches(query, window, cx)
+ })
+ .ok()
+ else {
+ return (Vec::new(), token);
+ };
+ (matches.await, token)
+ })
+ }
+
fn active_match_index(
&mut self,
direction: workspace::searchable::Direction,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
- self.last_selected_editor().update(cx, |editor, cx| {
- editor.active_match_index(direction, matches, window, cx)
+ self.editor_for_token(token).update(cx, |editor, cx| {
+ editor.active_match_index(direction, matches, token, window, cx)
})
}
}
@@ -1803,7 +1894,7 @@ impl EventEmitter<EditorEvent> for SplittableEditor {}
impl EventEmitter<SearchEvent> for SplittableEditor {}
impl Focusable for SplittableEditor {
fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
- self.last_selected_editor().read(cx).focus_handle(cx)
+ self.focused_editor().read(cx).focus_handle(cx)
}
}
@@ -450,7 +450,7 @@ impl ProjectDiff {
}
pub fn active_path(&self, cx: &App) -> Option<ProjectPath> {
- let editor = self.editor.read(cx).last_selected_editor().read(cx);
+ let editor = self.editor.read(cx).focused_editor().read(cx);
let position = editor.selections.newest_anchor().head();
let multi_buffer = editor.buffer().read(cx);
let (_, buffer, _) = multi_buffer.excerpt_containing(position, cx)?;
@@ -23,7 +23,7 @@ use util::ResultExt as _;
use workspace::{
SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId,
item::{Item, ItemHandle},
- searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
+ searchable::{Direction, SearchEvent, SearchToken, SearchableItem, SearchableItemHandle},
};
use crate::get_or_create_tool;
@@ -813,11 +813,12 @@ impl SearchableItem for LspLogView {
&mut self,
matches: &[Self::Match],
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor.update(cx, |e, cx| {
- e.update_matches(matches, active_match_index, window, cx)
+ e.update_matches(matches, active_match_index, token, window, cx)
})
}
@@ -830,21 +831,24 @@ impl SearchableItem for LspLogView {
&mut self,
index: usize,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
- self.editor
- .update(cx, |e, cx| e.activate_match(index, matches, window, cx))
+ self.editor.update(cx, |e, cx| {
+ e.activate_match(index, matches, token, window, cx)
+ })
}
fn select_matches(
&mut self,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.editor
- .update(cx, |e, cx| e.select_matches(matches, window, cx))
+ .update(cx, |e, cx| e.select_matches(matches, token, window, cx))
}
fn find_matches(
@@ -861,6 +865,7 @@ impl SearchableItem for LspLogView {
&mut self,
_: &Self::Match,
_: &SearchQuery,
+ _token: SearchToken,
_window: &mut Window,
_: &mut Context<Self>,
) {
@@ -881,11 +886,12 @@ impl SearchableItem for LspLogView {
&mut self,
direction: Direction,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
self.editor.update(cx, |e, cx| {
- e.active_match_index(direction, matches, window, cx)
+ e.active_match_index(direction, matches, token, window, cx)
})
}
}
@@ -4245,7 +4245,7 @@ impl OutlinePanel {
let buffer_search_matches = self
.active_editor()
.map(|active_editor| {
- active_editor.update(cx, |editor, cx| editor.get_matches(window, cx))
+ active_editor.update(cx, |editor, cx| editor.get_matches(window, cx).0)
})
.unwrap_or_default();
@@ -40,8 +40,8 @@ use workspace::{
ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
item::{ItemBufferKind, ItemHandle},
searchable::{
- CollapseDirection, Direction, FilteredSearchRange, SearchEvent, SearchableItemHandle,
- WeakSearchableItemHandle,
+ CollapseDirection, Direction, FilteredSearchRange, SearchEvent, SearchToken,
+ SearchableItemHandle, WeakSearchableItemHandle,
},
};
@@ -76,7 +76,8 @@ pub struct BufferSearchBar {
#[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>>,
+ searchable_items_with_matches:
+ HashMap<Box<dyn WeakSearchableItemHandle>, (AnyVec<dyn Send>, SearchToken)>,
pending_search: Option<Task<()>>,
search_options: SearchOptions,
default_options: SearchOptions,
@@ -233,7 +234,7 @@ impl Render for BufferSearchBar {
let matches_count = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
- .map(AnyVec::len)
+ .map(|(matches, _)| matches.len())
.unwrap_or(0);
if let Some(match_ix) = self.active_match_index {
Some(format!("{}/{}", match_ix + 1, matches_count))
@@ -1041,11 +1042,11 @@ impl BufferSearchBar {
pub fn activate_current_match(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if let Some(match_ix) = self.active_match_index
&& let Some(active_searchable_item) = self.active_searchable_item.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&active_searchable_item.downgrade())
{
- active_searchable_item.activate_match(match_ix, matches, window, cx)
+ active_searchable_item.activate_match(match_ix, matches, *token, window, cx)
}
}
@@ -1227,11 +1228,11 @@ impl BufferSearchBar {
if !self.dismissed
&& self.active_match_index.is_some()
&& let Some(searchable_item) = self.active_searchable_item.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
- searchable_item.select_matches(matches, window, cx);
+ searchable_item.select_matches(matches, *token, window, cx);
self.focus_editor(&FocusEditor, window, cx);
}
}
@@ -1261,10 +1262,10 @@ impl BufferSearchBar {
if let Some(index) = self.active_match_index
&& let Some(searchable_item) = self.active_searchable_item.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
- .filter(|matches| !matches.is_empty())
+ .filter(|(matches, _)| !matches.is_empty())
{
// If 'wrapscan' is disabled, searches do not wrap around the end of the file.
if !EditorSettings::get_global(cx).search_wrap
@@ -1275,30 +1276,30 @@ impl BufferSearchBar {
return;
}
let new_match_index = searchable_item
- .match_index_for_direction(matches, index, direction, count, window, cx);
+ .match_index_for_direction(matches, index, direction, count, *token, window, cx);
- searchable_item.update_matches(matches, Some(new_match_index), window, cx);
- searchable_item.activate_match(new_match_index, matches, window, cx);
+ searchable_item.update_matches(matches, Some(new_match_index), *token, window, cx);
+ searchable_item.activate_match(new_match_index, matches, *token, window, cx);
}
}
pub fn select_first_match(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if let Some(searchable_item) = self.active_searchable_item.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
if matches.is_empty() {
return;
}
- searchable_item.update_matches(matches, Some(0), window, cx);
- searchable_item.activate_match(0, matches, window, cx);
+ searchable_item.update_matches(matches, Some(0), *token, window, cx);
+ searchable_item.activate_match(0, matches, *token, window, cx);
}
}
pub fn select_last_match(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if let Some(searchable_item) = self.active_searchable_item.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
@@ -1306,8 +1307,8 @@ impl BufferSearchBar {
return;
}
let new_match_index = matches.len() - 1;
- searchable_item.update_matches(matches, Some(new_match_index), window, cx);
- searchable_item.activate_match(new_match_index, matches, window, cx);
+ searchable_item.update_matches(matches, Some(new_match_index), *token, window, cx);
+ searchable_item.activate_match(new_match_index, matches, *token, window, cx);
}
}
@@ -1532,18 +1533,19 @@ impl BufferSearchBar {
self.active_search = Some(query.clone());
let query_text = query.as_str().to_string();
- let matches = active_searchable_item.find_matches(query, window, cx);
+ let matches_with_token =
+ active_searchable_item.find_matches_with_token(query, window, cx);
let active_searchable_item = active_searchable_item.downgrade();
self.pending_search = Some(cx.spawn_in(window, async move |this, cx| {
- let matches = matches.await;
+ let (matches, token) = matches_with_token.await;
this.update_in(cx, |this, window, cx| {
if let Some(active_searchable_item) =
WeakSearchableItemHandle::upgrade(active_searchable_item.as_ref(), cx)
{
this.searchable_items_with_matches
- .insert(active_searchable_item.downgrade(), matches);
+ .insert(active_searchable_item.downgrade(), (matches, token));
this.update_match_index(window, cx);
@@ -1552,7 +1554,7 @@ impl BufferSearchBar {
.add(&mut this.search_history_cursor, query_text);
}
if !this.dismissed {
- let matches = this
+ let (matches, token) = this
.searchable_items_with_matches
.get(&active_searchable_item.downgrade())
.unwrap();
@@ -1562,6 +1564,7 @@ impl BufferSearchBar {
active_searchable_item.update_matches(
matches,
this.active_match_index,
+ *token,
window,
cx,
);
@@ -1592,21 +1595,21 @@ impl BufferSearchBar {
.active_searchable_item
.as_ref()
.and_then(|searchable_item| {
- let matches = self
+ let (matches, token) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())?;
- searchable_item.active_match_index(direction, matches, window, cx)
+ searchable_item.active_match_index(direction, matches, *token, window, cx)
});
if new_index != self.active_match_index {
self.active_match_index = new_index;
if !self.dismissed {
if let Some(searchable_item) = self.active_searchable_item.as_ref() {
- if let Some(matches) = self
+ if let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
if !matches.is_empty() {
- searchable_item.update_matches(matches, new_index, window, cx);
+ searchable_item.update_matches(matches, new_index, *token, window, cx);
}
}
}
@@ -1712,7 +1715,7 @@ impl BufferSearchBar {
&& self.active_search.is_some()
&& let Some(searchable_item) = self.active_searchable_item.as_ref()
&& let Some(query) = self.active_search.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
@@ -1721,7 +1724,7 @@ impl BufferSearchBar {
.as_ref()
.clone()
.with_replacement(self.replacement(cx));
- searchable_item.replace(matches.at(active_index), &query, window, cx);
+ searchable_item.replace(matches.at(active_index), &query, *token, window, cx);
self.select_next_match(&SelectNextMatch, window, cx);
}
should_propagate = false;
@@ -1736,7 +1739,7 @@ impl BufferSearchBar {
&& self.active_search.is_some()
&& let Some(searchable_item) = self.active_searchable_item.as_ref()
&& let Some(query) = self.active_search.as_ref()
- && let Some(matches) = self
+ && let Some((matches, token)) = self
.searchable_items_with_matches
.get(&searchable_item.downgrade())
{
@@ -1744,7 +1747,7 @@ impl BufferSearchBar {
.as_ref()
.clone()
.with_replacement(self.replacement(cx));
- searchable_item.replace_all(&mut matches.iter(), &query, window, cx);
+ searchable_item.replace_all(&mut matches.iter(), &query, *token, window, cx);
}
}
@@ -49,7 +49,10 @@ use workspace::{
DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation,
ToolbarItemView, Workspace, WorkspaceId,
item::{Item, ItemEvent, ItemHandle, SaveOptions},
- searchable::{CollapseDirection, Direction, SearchEvent, SearchableItem, SearchableItemHandle},
+ searchable::{
+ CollapseDirection, Direction, SearchEvent, SearchToken, SearchableItem,
+ SearchableItemHandle,
+ },
};
actions!(
@@ -731,7 +734,7 @@ impl ProjectSearchView {
let mat = self.entity.read(cx).match_ranges.get(active_index).cloned();
self.results_editor.update(cx, |editor, cx| {
if let Some(mat) = mat.as_ref() {
- editor.replace(mat, &query, window, cx);
+ editor.replace(mat, &query, SearchToken::default(), window, cx);
}
});
self.select_match(Direction::Next, window, cx)
@@ -761,7 +764,13 @@ impl ProjectSearchView {
}
self.results_editor.update(cx, |editor, cx| {
- editor.replace_all(&mut match_ranges.iter(), &query, window, cx);
+ editor.replace_all(
+ &mut match_ranges.iter(),
+ &query,
+ SearchToken::default(),
+ window,
+ cx,
+ );
});
self.entity.update(cx, |model, _cx| {
@@ -1394,7 +1403,15 @@ impl ProjectSearchView {
}
let new_index = self.results_editor.update(cx, |editor, cx| {
- editor.match_index_for_direction(&match_ranges, index, direction, 1, window, cx)
+ editor.match_index_for_direction(
+ &match_ranges,
+ index,
+ direction,
+ 1,
+ SearchToken::default(),
+ window,
+ cx,
+ )
});
let range_to_select = match_ranges[new_index].clone();
@@ -56,7 +56,9 @@ use workspace::{
BreadcrumbText, Item, ItemEvent, SerializableItem, TabContentParams, TabTooltipContent,
},
register_serializable_item,
- searchable::{Direction, SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle},
+ searchable::{
+ Direction, SearchEvent, SearchOptions, SearchToken, SearchableItem, SearchableItemHandle,
+ },
};
use zed_actions::{agent::AddSelectionToThread, assistant::InlineAssist};
@@ -1664,6 +1666,7 @@ impl SearchableItem for TerminalView {
&mut self,
matches: &[Self::Match],
_active_match_index: Option<usize>,
+ _token: SearchToken,
_window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1686,6 +1689,7 @@ impl SearchableItem for TerminalView {
&mut self,
index: usize,
_: &[Self::Match],
+ _token: SearchToken,
_window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1695,7 +1699,13 @@ impl SearchableItem for TerminalView {
}
/// Add selections for all matches given.
- fn select_matches(&mut self, matches: &[Self::Match], _: &mut Window, cx: &mut Context<Self>) {
+ fn select_matches(
+ &mut self,
+ matches: &[Self::Match],
+ _token: SearchToken,
+ _: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
self.terminal()
.update(cx, |term, _| term.select_matches(matches));
cx.notify();
@@ -1721,6 +1731,7 @@ impl SearchableItem for TerminalView {
&mut self,
direction: Direction,
matches: &[Self::Match],
+ _token: SearchToken,
_: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
@@ -1774,6 +1785,7 @@ impl SearchableItem for TerminalView {
&mut self,
_: &Self::Match,
_: &SearchQuery,
+ _token: SearchToken,
_window: &mut Window,
_: &mut Context<Self>,
) {
@@ -12,6 +12,19 @@ use crate::{
item::{Item, WeakItemHandle},
};
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub struct SearchToken(u64);
+
+impl SearchToken {
+ pub fn new(value: u64) -> Self {
+ Self(value)
+ }
+
+ pub fn value(&self) -> u64 {
+ self.0
+ }
+}
+
#[derive(Clone, Debug)]
pub enum CollapseDirection {
Collapsed,
@@ -96,14 +109,15 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
) {
}
- fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Self::Match> {
- Vec::new()
+ fn get_matches(&self, _window: &mut Window, _: &mut App) -> (Vec<Self::Match>, SearchToken) {
+ (Vec::new(), SearchToken::default())
}
fn clear_matches(&mut self, window: &mut Window, cx: &mut Context<Self>);
fn update_matches(
&mut self,
matches: &[Self::Match],
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
);
@@ -112,12 +126,14 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
&mut self,
index: usize,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
);
fn select_matches(
&mut self,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
);
@@ -125,6 +141,7 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
&mut self,
_: &Self::Match,
_: &SearchQuery,
+ _token: SearchToken,
_window: &mut Window,
_: &mut Context<Self>,
);
@@ -132,11 +149,12 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
&mut self,
matches: &mut dyn Iterator<Item = &Self::Match>,
query: &SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) {
for item in matches {
- self.replace(item, query, window, cx);
+ self.replace(item, query, token, window, cx);
}
}
fn match_index_for_direction(
@@ -145,6 +163,7 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
current_index: usize,
direction: Direction,
count: usize,
+ _token: SearchToken,
_window: &mut Window,
_: &mut Context<Self>,
) -> usize {
@@ -166,10 +185,22 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Vec<Self::Match>>;
+
+ fn find_matches_with_token(
+ &mut self,
+ query: Arc<SearchQuery>,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) -> Task<(Vec<Self::Match>, SearchToken)> {
+ let matches = self.find_matches(query, window, cx);
+ cx.spawn(async move |_, _| (matches.await, SearchToken::default()))
+ }
+
fn active_match_index(
&mut self,
direction: Direction,
matches: &[Self::Match],
+ token: SearchToken,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize>;
@@ -191,6 +222,7 @@ pub trait SearchableItemHandle: ItemHandle {
&self,
matches: &AnyVec<dyn Send>,
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
);
@@ -199,14 +231,22 @@ pub trait SearchableItemHandle: ItemHandle {
&self,
index: usize,
matches: &AnyVec<dyn Send>,
+ token: SearchToken,
+ window: &mut Window,
+ cx: &mut App,
+ );
+ fn select_matches(
+ &self,
+ matches: &AnyVec<dyn Send>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
);
- fn select_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App);
fn replace(
&self,
_: any_vec::element::ElementRef<'_, dyn Send>,
_: &SearchQuery,
+ token: SearchToken,
_window: &mut Window,
_: &mut App,
);
@@ -214,6 +254,7 @@ pub trait SearchableItemHandle: ItemHandle {
&self,
matches: &mut dyn Iterator<Item = any_vec::element::ElementRef<'_, dyn Send>>,
query: &SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
);
@@ -223,6 +264,7 @@ pub trait SearchableItemHandle: ItemHandle {
current_index: usize,
direction: Direction,
count: usize,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) -> usize;
@@ -232,10 +274,17 @@ pub trait SearchableItemHandle: ItemHandle {
window: &mut Window,
cx: &mut App,
) -> Task<AnyVec<dyn Send>>;
+ fn find_matches_with_token(
+ &self,
+ query: Arc<SearchQuery>,
+ window: &mut Window,
+ cx: &mut App,
+ ) -> Task<(AnyVec<dyn Send>, SearchToken)>;
fn active_match_index(
&self,
direction: Direction,
matches: &AnyVec<dyn Send>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) -> Option<usize>;
@@ -282,12 +331,13 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
&self,
matches: &AnyVec<dyn Send>,
active_match_index: Option<usize>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
- this.update_matches(matches.as_slice(), active_match_index, window, cx)
+ this.update_matches(matches.as_slice(), active_match_index, token, window, cx)
});
}
fn query_suggestion(&self, window: &mut Window, cx: &mut App) -> String {
@@ -297,19 +347,26 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
&self,
index: usize,
matches: &AnyVec<dyn Send>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
- this.activate_match(index, matches.as_slice(), window, cx)
+ this.activate_match(index, matches.as_slice(), token, window, cx)
});
}
- fn select_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App) {
+ fn select_matches(
+ &self,
+ matches: &AnyVec<dyn Send>,
+ token: SearchToken,
+ window: &mut Window,
+ cx: &mut App,
+ ) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
- this.select_matches(matches.as_slice(), window, cx)
+ this.select_matches(matches.as_slice(), token, window, cx)
});
}
@@ -319,6 +376,7 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
current_index: usize,
direction: Direction,
count: usize,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) -> usize {
@@ -329,6 +387,7 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
current_index,
direction,
count,
+ token,
window,
cx,
)
@@ -353,16 +412,38 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
any_matches
})
}
+ fn find_matches_with_token(
+ &self,
+ query: Arc<SearchQuery>,
+ window: &mut Window,
+ cx: &mut App,
+ ) -> Task<(AnyVec<dyn Send>, SearchToken)> {
+ let matches_with_token = self.update(cx, |this, cx| {
+ this.find_matches_with_token(query, window, cx)
+ });
+ window.spawn(cx, async |_| {
+ let (matches, token) = matches_with_token.await;
+ let mut any_matches = AnyVec::with_capacity::<T::Match>(matches.len());
+ {
+ let mut any_matches = any_matches.downcast_mut::<T::Match>().unwrap();
+ for mat in matches {
+ any_matches.push(mat);
+ }
+ }
+ (any_matches, token)
+ })
+ }
fn active_match_index(
&self,
direction: Direction,
matches: &AnyVec<dyn Send>,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) -> Option<usize> {
let matches = matches.downcast_ref()?;
self.update(cx, |this, cx| {
- this.active_match_index(direction, matches.as_slice(), window, cx)
+ this.active_match_index(direction, matches.as_slice(), token, window, cx)
})
}
@@ -370,17 +451,19 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
&self,
mat: any_vec::element::ElementRef<'_, dyn Send>,
query: &SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) {
let mat = mat.downcast_ref().unwrap();
- self.update(cx, |this, cx| this.replace(mat, query, window, cx))
+ self.update(cx, |this, cx| this.replace(mat, query, token, window, cx))
}
fn replace_all(
&self,
matches: &mut dyn Iterator<Item = any_vec::element::ElementRef<'_, dyn Send>>,
query: &SearchQuery,
+ token: SearchToken,
window: &mut Window,
cx: &mut App,
) {
@@ -388,6 +471,7 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
this.replace_all(
&mut matches.map(|m| m.downcast_ref().unwrap()),
query,
+ token,
window,
cx,
);