diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 00f83d79e1..b147d2af2c 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -15,7 +15,6 @@ use rpc::proto::{self, update_view}; use settings::Settings; use smallvec::SmallVec; use std::{ - any::Any, borrow::Cow, cmp::{self, Ordering}, fmt::Write, @@ -510,6 +509,8 @@ impl ProjectItem for Editor { enum BufferSearchHighlights {} impl SearchableItem for Editor { + type Match = Range; + fn to_search_event(event: &Self::Event) -> Option { match event { Event::BufferEdited => Some(SearchEvent::ContentsUpdated), @@ -522,6 +523,14 @@ impl SearchableItem for Editor { self.clear_background_highlights::(cx); } + fn highlight_matches(&mut self, matches: Vec>, cx: &mut ViewContext) { + self.highlight_background::( + matches, + |theme| theme.search.match_background, + cx, + ); + } + fn query_suggestion(&mut self, cx: &mut ViewContext) -> String { let display_map = self.snapshot(cx).display_snapshot; let selection = self.selections.newest::(cx); @@ -548,61 +557,40 @@ impl SearchableItem for Editor { &mut self, index: usize, direction: Direction, - matches: &Vec>, + matches: Vec>, cx: &mut ViewContext, ) { - if let Some(matches) = matches - .iter() - .map(|range| range.downcast_ref::>().cloned()) - .collect::>>() - { - let new_index: usize = match_index_for_direction( - matches.as_slice(), - &self.selections.newest_anchor().head(), - index, - direction, - &self.buffer().read(cx).snapshot(cx), - ); + let new_index: usize = match_index_for_direction( + matches.as_slice(), + &self.selections.newest_anchor().head(), + index, + direction, + &self.buffer().read(cx).snapshot(cx), + ); - let range_to_select = matches[new_index].clone(); - self.unfold_ranges([range_to_select.clone()], false, cx); - self.change_selections(Some(Autoscroll::Fit), cx, |s| { - s.select_ranges([range_to_select]) - }); - } else { - log::error!("Select next match in direction called with unexpected type matches"); - } + let range_to_select = matches[new_index].clone(); + self.unfold_ranges([range_to_select.clone()], false, cx); + self.change_selections(Some(Autoscroll::Fit), cx, |s| { + s.select_ranges([range_to_select]) + }); } fn select_match_by_index( &mut self, index: usize, - matches: &Vec>, + matches: Vec>, cx: &mut ViewContext, ) { - if let Some(matches) = matches - .iter() - .map(|range| range.downcast_ref::>().cloned()) - .collect::>>() - { - self.change_selections(Some(Autoscroll::Fit), cx, |s| { - s.select_ranges([matches[index].clone()]) - }); - self.highlight_background::( - matches, - |theme| theme.search.match_background, - cx, - ); - } else { - log::error!("Select next match in direction called with unexpected type matches"); - } + self.change_selections(Some(Autoscroll::Fit), cx, |s| { + s.select_ranges([matches[index].clone()]) + }); } fn matches( &mut self, query: project::search::SearchQuery, cx: &mut ViewContext, - ) -> Task>> { + ) -> Task>> { let buffer = self.buffer().read(cx).snapshot(cx); cx.background().spawn(async move { let mut ranges = Vec::new(); @@ -633,30 +621,19 @@ impl SearchableItem for Editor { } } ranges - .into_iter() - .map::, _>(|range| Box::new(range)) - .collect() }) } fn active_match_index( &mut self, - matches: &Vec>, + matches: Vec>, cx: &mut ViewContext, ) -> Option { - if let Some(matches) = matches - .iter() - .map(|range| range.downcast_ref::>().cloned()) - .collect::>>() - { - active_match_index( - &matches, - &self.selections.newest_anchor().head(), - &self.buffer().read(cx).snapshot(cx), - ) - } else { - None - } + active_match_index( + &matches, + &self.selections.newest_anchor().head(), + &self.buffer().read(cx).snapshot(cx), + ) } } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 942c7e354a..a2fb342e3f 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -421,6 +421,7 @@ impl BufferSearchBar { .get(&searchable_item.downgrade()) { searchable_item.select_next_match_in_direction(index, direction, matches, cx); + searchable_item.highlight_matches(matches, cx); } } } @@ -468,18 +469,13 @@ impl BufferSearchBar { } fn clear_matches(&mut self, cx: &mut ViewContext) { - let mut active_editor_matches = None; + let mut active_item_matches = None; for (searchable_item, matches) in self.seachable_items_with_matches.drain() { if let Some(searchable_item) = WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx) { - if self - .active_searchable_item - .as_ref() - .map(|active_item| active_item == &searchable_item) - .unwrap_or(false) - { - active_editor_matches = Some((searchable_item.downgrade(), matches)); + if Some(&searchable_item) == self.active_searchable_item.as_ref() { + active_item_matches = Some((searchable_item.downgrade(), matches)); } else { searchable_item.clear_highlights(cx); } @@ -487,7 +483,7 @@ impl BufferSearchBar { } self.seachable_items_with_matches - .extend(active_editor_matches); + .extend(active_item_matches); } fn update_matches(&mut self, select_closest_match: bool, cx: &mut ViewContext) { @@ -527,17 +523,17 @@ impl BufferSearchBar { this.update_match_index(cx); if !this.dismissed { + let matches = this + .seachable_items_with_matches + .get(&active_searchable_item.downgrade()) + .unwrap(); if select_closest_match { if let Some(match_ix) = this.active_match_index { - active_searchable_item.select_match_by_index( - match_ix, - this.seachable_items_with_matches - .get(&active_searchable_item.downgrade()) - .unwrap(), - cx, - ); + active_searchable_item + .select_match_by_index(match_ix, matches, cx); } } + active_searchable_item.highlight_matches(matches, cx); } cx.notify(); } diff --git a/crates/workspace/src/searchable.rs b/crates/workspace/src/searchable.rs index 3b252aedb8..b0791ff4b3 100644 --- a/crates/workspace/src/searchable.rs +++ b/crates/workspace/src/searchable.rs @@ -8,6 +8,7 @@ use project::search::SearchQuery; use crate::{Item, ItemHandle, WeakItemHandle}; +#[derive(Debug)] pub enum SearchEvent { ContentsUpdated, SelectionsChanged, @@ -20,30 +21,30 @@ pub enum Direction { } pub trait SearchableItem: Item { + type Match: Any + Sync + Send + Clone; + fn to_search_event(event: &Self::Event) -> Option; fn clear_highlights(&mut self, cx: &mut ViewContext); + fn highlight_matches(&mut self, matches: Vec, cx: &mut ViewContext); fn query_suggestion(&mut self, cx: &mut ViewContext) -> String; fn select_next_match_in_direction( &mut self, index: usize, direction: Direction, - matches: &Vec>, + matches: Vec, cx: &mut ViewContext, ); fn select_match_by_index( &mut self, index: usize, - matches: &Vec>, + matches: Vec, cx: &mut ViewContext, ); - fn matches( - &mut self, - query: SearchQuery, - cx: &mut ViewContext, - ) -> Task>>; + fn matches(&mut self, query: SearchQuery, cx: &mut ViewContext) + -> Task>; fn active_match_index( &mut self, - matches: &Vec>, + matches: Vec, cx: &mut ViewContext, ) -> Option; } @@ -57,6 +58,7 @@ pub trait SearchableItemHandle: ItemHandle { handler: Box, ) -> Subscription; fn clear_highlights(&self, cx: &mut MutableAppContext); + fn highlight_matches(&self, matches: &Vec>, cx: &mut MutableAppContext); fn query_suggestion(&self, cx: &mut MutableAppContext) -> String; fn select_next_match_in_direction( &self, @@ -107,6 +109,10 @@ impl SearchableItemHandle for ViewHandle { fn clear_highlights(&self, cx: &mut MutableAppContext) { self.update(cx, |this, cx| this.clear_highlights(cx)); } + fn highlight_matches(&self, matches: &Vec>, cx: &mut MutableAppContext) { + let matches = downcast_matches(matches); + self.update(cx, |this, cx| this.highlight_matches(matches, cx)); + } fn query_suggestion(&self, cx: &mut MutableAppContext) -> String { self.update(cx, |this, cx| this.query_suggestion(cx)) } @@ -117,6 +123,7 @@ impl SearchableItemHandle for ViewHandle { matches: &Vec>, cx: &mut MutableAppContext, ) { + let matches = downcast_matches(matches); self.update(cx, |this, cx| { this.select_next_match_in_direction(index, direction, matches, cx) }); @@ -127,6 +134,7 @@ impl SearchableItemHandle for ViewHandle { matches: &Vec>, cx: &mut MutableAppContext, ) { + let matches = downcast_matches(matches); self.update(cx, |this, cx| { this.select_match_by_index(index, matches, cx) }); @@ -136,17 +144,35 @@ impl SearchableItemHandle for ViewHandle { query: SearchQuery, cx: &mut MutableAppContext, ) -> Task>> { - self.update(cx, |this, cx| this.matches(query, cx)) + let matches = self.update(cx, |this, cx| this.matches(query, cx)); + cx.foreground().spawn(async { + let matches = matches.await; + matches + .into_iter() + .map::, _>(|range| Box::new(range)) + .collect() + }) } fn active_match_index( &self, matches: &Vec>, cx: &mut MutableAppContext, ) -> Option { + let matches = downcast_matches(matches); self.update(cx, |this, cx| this.active_match_index(matches, cx)) } } +fn downcast_matches(matches: &Vec>) -> Vec { + matches + .iter() + .map(|range| range.downcast_ref::().cloned()) + .collect::>>() + .expect( + "SearchableItemHandle function called with vec of matches of a different type than expected", + ) +} + impl From> for AnyViewHandle { fn from(this: Box) -> Self { this.to_any()