mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Add match associated type and fix failing test
This commit is contained in:
parent
91a5d0b036
commit
d7e6e8c5a1
3 changed files with 81 additions and 82 deletions
|
@ -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,14 +557,9 @@ 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
|
|
||||||
.iter()
|
|
||||||
.map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
|
|
||||||
.collect::<Option<Vec<_>>>()
|
|
||||||
{
|
|
||||||
let new_index: usize = match_index_for_direction(
|
let new_index: usize = match_index_for_direction(
|
||||||
matches.as_slice(),
|
matches.as_slice(),
|
||||||
&self.selections.newest_anchor().head(),
|
&self.selections.newest_anchor().head(),
|
||||||
|
@ -569,40 +573,24 @@ impl SearchableItem for Editor {
|
||||||
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
|
|
||||||
.iter()
|
|
||||||
.map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
|
|
||||||
.collect::<Option<Vec<_>>>()
|
|
||||||
{
|
|
||||||
self.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
self.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
||||||
s.select_ranges([matches[index].clone()])
|
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
|
|
||||||
.iter()
|
|
||||||
.map(|range| range.downcast_ref::<Range<Anchor>>().cloned())
|
|
||||||
.collect::<Option<Vec<_>>>()
|
|
||||||
{
|
|
||||||
active_match_index(
|
active_match_index(
|
||||||
&matches,
|
&matches,
|
||||||
&self.selections.newest_anchor().head(),
|
&self.selections.newest_anchor().head(),
|
||||||
&self.buffer().read(cx).snapshot(cx),
|
&self.buffer().read(cx).snapshot(cx),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue