Add match associated type and fix failing test

This commit is contained in:
K Simmons 2022-08-30 21:53:49 -07:00
parent 91a5d0b036
commit d7e6e8c5a1
3 changed files with 81 additions and 82 deletions

View file

@ -15,7 +15,6 @@ use rpc::proto::{self, update_view};
use settings::Settings; use settings::Settings;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
any::Any,
borrow::Cow, borrow::Cow,
cmp::{self, Ordering}, cmp::{self, Ordering},
fmt::Write, fmt::Write,
@ -510,6 +509,8 @@ impl ProjectItem for Editor {
enum BufferSearchHighlights {} enum BufferSearchHighlights {}
impl SearchableItem for Editor { impl SearchableItem for Editor {
type Match = Range<Anchor>;
fn to_search_event(event: &Self::Event) -> Option<SearchEvent> { fn to_search_event(event: &Self::Event) -> Option<SearchEvent> {
match event { match event {
Event::BufferEdited => Some(SearchEvent::ContentsUpdated), Event::BufferEdited => Some(SearchEvent::ContentsUpdated),
@ -522,6 +523,14 @@ impl SearchableItem for Editor {
self.clear_background_highlights::<BufferSearchHighlights>(cx); 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 { fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
let display_map = self.snapshot(cx).display_snapshot; let display_map = self.snapshot(cx).display_snapshot;
let selection = self.selections.newest::<usize>(cx); let selection = self.selections.newest::<usize>(cx);
@ -548,61 +557,40 @@ impl SearchableItem for Editor {
&mut self, &mut self,
index: usize, index: usize,
direction: Direction, direction: Direction,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if let Some(matches) = matches let new_index: usize = match_index_for_direction(
.iter() matches.as_slice(),
.map(|range| range.downcast_ref::<Range<Anchor>>().cloned()) &self.selections.newest_anchor().head(),
.collect::<Option<Vec<_>>>() index,
{ direction,
let new_index: usize = match_index_for_direction( &self.buffer().read(cx).snapshot(cx),
matches.as_slice(), );
&self.selections.newest_anchor().head(),
index,
direction,
&self.buffer().read(cx).snapshot(cx),
);
let range_to_select = matches[new_index].clone(); let range_to_select = matches[new_index].clone();
self.unfold_ranges([range_to_select.clone()], false, cx); self.unfold_ranges([range_to_select.clone()], false, cx);
self.change_selections(Some(Autoscroll::Fit), cx, |s| { self.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.select_ranges([range_to_select]) s.select_ranges([range_to_select])
}); });
} else {
log::error!("Select next match in direction called with unexpected type matches");
}
} }
fn select_match_by_index( fn select_match_by_index(
&mut self, &mut self,
index: usize, index: usize,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if let Some(matches) = matches self.change_selections(Some(Autoscroll::Fit), cx, |s| {
.iter() s.select_ranges([matches[index].clone()])
.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");
}
} }
fn matches( fn matches(
&mut self, &mut self,
query: project::search::SearchQuery, query: project::search::SearchQuery,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Task<Vec<Box<dyn Any + Send>>> { ) -> Task<Vec<Range<Anchor>>> {
let buffer = self.buffer().read(cx).snapshot(cx); let buffer = self.buffer().read(cx).snapshot(cx);
cx.background().spawn(async move { cx.background().spawn(async move {
let mut ranges = Vec::new(); let mut ranges = Vec::new();
@ -633,30 +621,19 @@ impl SearchableItem for Editor {
} }
} }
ranges ranges
.into_iter()
.map::<Box<dyn Any + Send>, _>(|range| Box::new(range))
.collect()
}) })
} }
fn active_match_index( fn active_match_index(
&mut self, &mut self,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<usize> { ) -> Option<usize> {
if let Some(matches) = matches active_match_index(
.iter() &matches,
.map(|range| range.downcast_ref::<Range<Anchor>>().cloned()) &self.selections.newest_anchor().head(),
.collect::<Option<Vec<_>>>() &self.buffer().read(cx).snapshot(cx),
{ )
active_match_index(
&matches,
&self.selections.newest_anchor().head(),
&self.buffer().read(cx).snapshot(cx),
)
} else {
None
}
} }
} }

View file

@ -421,6 +421,7 @@ impl BufferSearchBar {
.get(&searchable_item.downgrade()) .get(&searchable_item.downgrade())
{ {
searchable_item.select_next_match_in_direction(index, direction, matches, cx); 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>) { 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() { for (searchable_item, matches) in self.seachable_items_with_matches.drain() {
if let Some(searchable_item) = if let Some(searchable_item) =
WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx) WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx)
{ {
if self if Some(&searchable_item) == self.active_searchable_item.as_ref() {
.active_searchable_item active_item_matches = Some((searchable_item.downgrade(), matches));
.as_ref()
.map(|active_item| active_item == &searchable_item)
.unwrap_or(false)
{
active_editor_matches = Some((searchable_item.downgrade(), matches));
} else { } else {
searchable_item.clear_highlights(cx); searchable_item.clear_highlights(cx);
} }
@ -487,7 +483,7 @@ impl BufferSearchBar {
} }
self.seachable_items_with_matches 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>) { fn update_matches(&mut self, select_closest_match: bool, cx: &mut ViewContext<Self>) {
@ -527,17 +523,17 @@ impl BufferSearchBar {
this.update_match_index(cx); this.update_match_index(cx);
if !this.dismissed { if !this.dismissed {
let matches = this
.seachable_items_with_matches
.get(&active_searchable_item.downgrade())
.unwrap();
if select_closest_match { if select_closest_match {
if let Some(match_ix) = this.active_match_index { if let Some(match_ix) = this.active_match_index {
active_searchable_item.select_match_by_index( active_searchable_item
match_ix, .select_match_by_index(match_ix, matches, cx);
this.seachable_items_with_matches
.get(&active_searchable_item.downgrade())
.unwrap(),
cx,
);
} }
} }
active_searchable_item.highlight_matches(matches, cx);
} }
cx.notify(); cx.notify();
} }

View file

@ -8,6 +8,7 @@ use project::search::SearchQuery;
use crate::{Item, ItemHandle, WeakItemHandle}; use crate::{Item, ItemHandle, WeakItemHandle};
#[derive(Debug)]
pub enum SearchEvent { pub enum SearchEvent {
ContentsUpdated, ContentsUpdated,
SelectionsChanged, SelectionsChanged,
@ -20,30 +21,30 @@ pub enum Direction {
} }
pub trait SearchableItem: Item { pub trait SearchableItem: Item {
type Match: Any + Sync + Send + Clone;
fn to_search_event(event: &Self::Event) -> Option<SearchEvent>; fn to_search_event(event: &Self::Event) -> Option<SearchEvent>;
fn clear_highlights(&mut self, cx: &mut ViewContext<Self>); 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 query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String;
fn select_next_match_in_direction( fn select_next_match_in_direction(
&mut self, &mut self,
index: usize, index: usize,
direction: Direction, direction: Direction,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
); );
fn select_match_by_index( fn select_match_by_index(
&mut self, &mut self,
index: usize, index: usize,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
); );
fn matches( fn matches(&mut self, query: SearchQuery, cx: &mut ViewContext<Self>)
&mut self, -> Task<Vec<Self::Match>>;
query: SearchQuery,
cx: &mut ViewContext<Self>,
) -> Task<Vec<Box<dyn Any + Send>>>;
fn active_match_index( fn active_match_index(
&mut self, &mut self,
matches: &Vec<Box<dyn Any + Send>>, matches: Vec<Self::Match>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<usize>; ) -> Option<usize>;
} }
@ -57,6 +58,7 @@ pub trait SearchableItemHandle: ItemHandle {
handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>, handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
) -> Subscription; ) -> Subscription;
fn clear_highlights(&self, cx: &mut MutableAppContext); 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 query_suggestion(&self, cx: &mut MutableAppContext) -> String;
fn select_next_match_in_direction( fn select_next_match_in_direction(
&self, &self,
@ -107,6 +109,10 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
fn clear_highlights(&self, cx: &mut MutableAppContext) { fn clear_highlights(&self, cx: &mut MutableAppContext) {
self.update(cx, |this, cx| this.clear_highlights(cx)); 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 { fn query_suggestion(&self, cx: &mut MutableAppContext) -> String {
self.update(cx, |this, cx| this.query_suggestion(cx)) 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>>, matches: &Vec<Box<dyn Any + Send>>,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) { ) {
let matches = downcast_matches(matches);
self.update(cx, |this, cx| { self.update(cx, |this, cx| {
this.select_next_match_in_direction(index, direction, matches, 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>>, matches: &Vec<Box<dyn Any + Send>>,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) { ) {
let matches = downcast_matches(matches);
self.update(cx, |this, cx| { self.update(cx, |this, cx| {
this.select_match_by_index(index, matches, cx) this.select_match_by_index(index, matches, cx)
}); });
@ -136,17 +144,35 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
query: SearchQuery, query: SearchQuery,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) -> Task<Vec<Box<dyn Any + Send>>> { ) -> 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( fn active_match_index(
&self, &self,
matches: &Vec<Box<dyn Any + Send>>, matches: &Vec<Box<dyn Any + Send>>,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) -> Option<usize> { ) -> Option<usize> {
let matches = downcast_matches(matches);
self.update(cx, |this, cx| this.active_match_index(matches, cx)) 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 { impl From<Box<dyn SearchableItemHandle>> for AnyViewHandle {
fn from(this: Box<dyn SearchableItemHandle>) -> Self { fn from(this: Box<dyn SearchableItemHandle>) -> Self {
this.to_any() this.to_any()