Detailed changes
@@ -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<Anchor>;
+
fn to_search_event(event: &Self::Event) -> Option<SearchEvent> {
match event {
Event::BufferEdited => Some(SearchEvent::ContentsUpdated),
@@ -522,6 +523,14 @@ impl SearchableItem for Editor {
self.clear_background_highlights::<BufferSearchHighlights>(cx);
}
+ fn highlight_matches(&mut self, matches: Vec<Range<Anchor>>, cx: &mut ViewContext<Self>) {
+ self.highlight_background::<BufferSearchHighlights>(
+ matches,
+ |theme| theme.search.match_background,
+ cx,
+ );
+ }
+
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
let display_map = self.snapshot(cx).display_snapshot;
let selection = self.selections.newest::<usize>(cx);
@@ -548,61 +557,40 @@ impl SearchableItem for Editor {
&mut self,
index: usize,
direction: Direction,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>,
) {
- if let Some(matches) = matches
- .iter()
- .map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
- .collect::<Option<Vec<_>>>()
- {
- 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 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])
+ });
}
fn select_match_by_index(
&mut self,
index: usize,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>,
) {
- if let Some(matches) = matches
- .iter()
- .map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
- .collect::<Option<Vec<_>>>()
- {
- self.change_selections(Some(Autoscroll::Fit), cx, |s| {
- s.select_ranges([matches[index].clone()])
- });
- self.highlight_background::<BufferSearchHighlights>(
- 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<Self>,
- ) -> Task<Vec<Box<dyn Any + Send>>> {
+ ) -> Task<Vec<Range<Anchor>>> {
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::<Box<dyn Any + Send>, _>(|range| Box::new(range))
- .collect()
})
}
fn active_match_index(
&mut self,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>,
) -> Option<usize> {
- if let Some(matches) = matches
- .iter()
- .map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
- .collect::<Option<Vec<_>>>()
- {
- 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),
+ )
}
}
@@ -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<Self>) {
- 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<Self>) {
@@ -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();
}
@@ -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<SearchEvent>;
fn clear_highlights(&mut self, cx: &mut ViewContext<Self>);
+ fn highlight_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>);
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String;
fn select_next_match_in_direction(
&mut self,
index: usize,
direction: Direction,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>,
);
fn select_match_by_index(
&mut self,
index: usize,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>,
);
- fn matches(
- &mut self,
- query: SearchQuery,
- cx: &mut ViewContext<Self>,
- ) -> Task<Vec<Box<dyn Any + Send>>>;
+ fn matches(&mut self, query: SearchQuery, cx: &mut ViewContext<Self>)
+ -> Task<Vec<Self::Match>>;
fn active_match_index(
&mut self,
- matches: &Vec<Box<dyn Any + Send>>,
+ matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>,
) -> Option<usize>;
}
@@ -57,6 +58,7 @@ pub trait SearchableItemHandle: ItemHandle {
handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
) -> Subscription;
fn clear_highlights(&self, cx: &mut MutableAppContext);
+ fn highlight_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext);
fn query_suggestion(&self, cx: &mut MutableAppContext) -> String;
fn select_next_match_in_direction(
&self,
@@ -107,6 +109,10 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
fn clear_highlights(&self, cx: &mut MutableAppContext) {
self.update(cx, |this, cx| this.clear_highlights(cx));
}
+ fn highlight_matches(&self, matches: &Vec<Box<dyn Any + Send>>, 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<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
matches: &Vec<Box<dyn Any + Send>>,
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<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
matches: &Vec<Box<dyn Any + Send>>,
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<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
query: SearchQuery,
cx: &mut MutableAppContext,
) -> Task<Vec<Box<dyn Any + Send>>> {
- 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::<Box<dyn Any + Send>, _>(|range| Box::new(range))
+ .collect()
+ })
}
fn active_match_index(
&self,
matches: &Vec<Box<dyn Any + Send>>,
cx: &mut MutableAppContext,
) -> Option<usize> {
+ let matches = downcast_matches(matches);
self.update(cx, |this, cx| this.active_match_index(matches, cx))
}
}
+fn downcast_matches<T: Any + Clone>(matches: &Vec<Box<dyn Any + Send>>) -> Vec<T> {
+ matches
+ .iter()
+ .map(|range| range.downcast_ref::<T>().cloned())
+ .collect::<Option<Vec<_>>>()
+ .expect(
+ "SearchableItemHandle function called with vec of matches of a different type than expected",
+ )
+}
+
impl From<Box<dyn SearchableItemHandle>> for AnyViewHandle {
fn from(this: Box<dyn SearchableItemHandle>) -> Self {
this.to_any()