Allow matching of context items in outline view

This commit is contained in:
Antonio Scandurra 2022-01-14 11:09:02 +01:00
parent e7f1398f3a
commit a64ba8b687
4 changed files with 44 additions and 64 deletions

View file

@ -1712,7 +1712,6 @@ impl MultiBufferSnapshot {
..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
text: item.text,
highlight_ranges: item.highlight_ranges,
name_ranges: item.name_ranges,
})
.collect(),
))

View file

@ -1864,15 +1864,11 @@ impl BufferSnapshot {
let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?;
let range = item_node.start_byte()..item_node.end_byte();
let mut text = String::new();
let mut name_ranges = Vec::new();
let mut highlight_ranges = Vec::new();
for capture in mat.captures {
let node_is_name;
if capture.index == name_capture_ix {
node_is_name = true;
} else if capture.index == context_capture_ix {
node_is_name = false;
} else {
continue;
}
@ -1881,18 +1877,6 @@ impl BufferSnapshot {
if !text.is_empty() {
text.push(' ');
}
if node_is_name {
let mut start = text.len() as u32;
let end = start + range.len() as u32;
// When multiple names are captured, then the matcheable text
// includes the whitespace in between the names.
if !name_ranges.is_empty() {
start -= 1;
}
name_ranges.push(start..end);
}
let mut offset = range.start;
chunks.seek(offset);
@ -1926,7 +1910,6 @@ impl BufferSnapshot {
depth: stack.len() - 1,
range: self.anchor_after(range.start)..self.anchor_before(range.end),
text,
name_ranges,
highlight_ranges,
})
})

View file

@ -13,7 +13,6 @@ pub struct OutlineItem<T> {
pub depth: usize,
pub range: Range<T>,
pub text: String,
pub name_ranges: Vec<Range<u32>>,
pub highlight_ranges: Vec<(Range<usize>, HighlightStyle)>,
}
@ -22,16 +21,9 @@ impl<T> Outline<T> {
Self {
candidates: items
.iter()
.map(|item| {
let text = item
.name_ranges
.iter()
.map(|range| &item.text[range.start as usize..range.end as usize])
.collect::<String>();
StringMatchCandidate {
char_bag: text.as_str().into(),
string: text,
}
.map(|item| StringMatchCandidate {
char_bag: item.text.as_str().into(),
string: item.text.clone(),
})
.collect(),
items,
@ -53,20 +45,8 @@ impl<T> Outline<T> {
let mut tree_matches = Vec::new();
let mut prev_item_ix = 0;
for mut string_match in matches {
for string_match in matches {
let outline_match = &self.items[string_match.candidate_index];
let mut name_ranges = outline_match.name_ranges.iter();
let mut name_range = name_ranges.next().unwrap();
let mut preceding_ranges_len = 0;
for position in &mut string_match.positions {
while *position >= preceding_ranges_len + name_range.len() as usize {
preceding_ranges_len += name_range.len();
name_range = name_ranges.next().unwrap();
}
*position = name_range.start as usize + (*position - preceding_ranges_len);
}
let insertion_ix = tree_matches.len();
let mut cur_depth = outline_match.depth;
for (ix, item) in self.items[prev_item_ix..string_match.candidate_index]

View file

@ -302,6 +302,9 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
(function_item
"fn" @context
name: (_) @name) @item
(mod_item
"mod" @context
name: (_) @name) @item
"#,
)
.unwrap(),
@ -313,15 +316,19 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
age: usize,
}
enum LoginState {
LoggedOut,
LoggingOn,
LoggedIn {
person: Person,
time: Instant,
mod module {
enum LoginState {
LoggedOut,
LoggingOn,
LoggedIn {
person: Person,
time: Instant,
}
}
}
impl Eq for Person {}
impl Drop for Person {
fn drop(&mut self) {
println!("bye");
@ -339,39 +346,50 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
outline
.items
.iter()
.map(|item| (item.text.as_str(), item.name_ranges.as_ref(), item.depth))
.map(|item| (item.text.as_str(), item.depth))
.collect::<Vec<_>>(),
&[
("struct Person", [7..13].as_slice(), 0),
("name", &[0..4], 1),
("age", &[0..3], 1),
("enum LoginState", &[5..15], 0),
("LoggedOut", &[0..9], 1),
("LoggingOn", &[0..9], 1),
("LoggedIn", &[0..8], 1),
("person", &[0..6], 2),
("time", &[0..4], 2),
("impl Drop for Person", &[5..9, 13..20], 0),
("fn drop", &[3..7], 1),
("struct Person", 0),
("name", 1),
("age", 1),
("mod module", 0),
("enum LoginState", 1),
("LoggedOut", 2),
("LoggingOn", 2),
("LoggedIn", 2),
("person", 3),
("time", 3),
("impl Eq for Person", 0),
("impl Drop for Person", 0),
("fn drop", 1),
]
);
assert_eq!(
search(&outline, "oon", &cx).await,
&[
("enum LoginState", vec![]), // included as the parent of a match
("LoggingOn", vec![1, 7, 8]), // matches
("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
("mod module", vec![]), // included as the parent of a match
("enum LoginState", vec![]), // included as the parent of a match
("LoggingOn", vec![1, 7, 8]), // matches
("impl Eq for Person", vec![9, 16, 17]), // matches part of the context
("impl Drop for Person", vec![11, 18, 19]), // matches in two disjoint names
]
);
assert_eq!(
search(&outline, "dp p", &cx).await,
&[("impl Drop for Person", vec![5, 8, 13, 14])]
&[("impl Drop for Person", vec![5, 8, 9, 14])]
);
assert_eq!(
search(&outline, "dpn", &cx).await,
&[("impl Drop for Person", vec![5, 8, 19])]
);
assert_eq!(
search(&outline, "impl", &cx).await,
&[
("impl Eq for Person", vec![0, 1, 2, 3]),
("impl Drop for Person", vec![0, 1, 2, 3])
]
);
async fn search<'a>(
outline: &'a Outline<Anchor>,