Match on names only when outline query has no spaces
Co-Authored-By: Antonio Scandurra <me@as-cii.com> Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
ce51196eab
commit
ea69dcd42a
4 changed files with 73 additions and 34 deletions
|
@ -1712,6 +1712,7 @@ impl MultiBufferSnapshot {
|
||||||
..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
|
..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
|
||||||
text: item.text,
|
text: item.text,
|
||||||
highlight_ranges: item.highlight_ranges,
|
highlight_ranges: item.highlight_ranges,
|
||||||
|
name_ranges: item.name_ranges,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
|
|
|
@ -1864,11 +1864,15 @@ impl BufferSnapshot {
|
||||||
let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?;
|
let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?;
|
||||||
let range = item_node.start_byte()..item_node.end_byte();
|
let range = item_node.start_byte()..item_node.end_byte();
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
|
let mut name_ranges = Vec::new();
|
||||||
let mut highlight_ranges = Vec::new();
|
let mut highlight_ranges = Vec::new();
|
||||||
|
|
||||||
for capture in mat.captures {
|
for capture in mat.captures {
|
||||||
|
let node_is_name;
|
||||||
if capture.index == name_capture_ix {
|
if capture.index == name_capture_ix {
|
||||||
|
node_is_name = true;
|
||||||
} else if capture.index == context_capture_ix {
|
} else if capture.index == context_capture_ix {
|
||||||
|
node_is_name = false;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1877,6 +1881,18 @@ impl BufferSnapshot {
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
text.push(' ');
|
text.push(' ');
|
||||||
}
|
}
|
||||||
|
if node_is_name {
|
||||||
|
let mut start = text.len();
|
||||||
|
let end = start + range.len();
|
||||||
|
|
||||||
|
// 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;
|
let mut offset = range.start;
|
||||||
chunks.seek(offset);
|
chunks.seek(offset);
|
||||||
|
@ -1911,6 +1927,7 @@ impl BufferSnapshot {
|
||||||
range: self.anchor_after(range.start)..self.anchor_before(range.end),
|
range: self.anchor_after(range.start)..self.anchor_before(range.end),
|
||||||
text,
|
text,
|
||||||
highlight_ranges,
|
highlight_ranges,
|
||||||
|
name_ranges,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
@ -16,44 +16,49 @@ pub struct OutlineItem<T> {
|
||||||
pub range: Range<T>,
|
pub range: Range<T>,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub highlight_ranges: Vec<(Range<usize>, HighlightStyle)>,
|
pub highlight_ranges: Vec<(Range<usize>, HighlightStyle)>,
|
||||||
|
pub name_ranges: Vec<Range<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Outline<T> {
|
impl<T> Outline<T> {
|
||||||
pub fn new(items: Vec<OutlineItem<T>>) -> Self {
|
pub fn new(items: Vec<OutlineItem<T>>) -> Self {
|
||||||
|
let mut candidates = Vec::new();
|
||||||
let mut path_candidates = Vec::new();
|
let mut path_candidates = Vec::new();
|
||||||
let mut path_candidate_prefixes = Vec::new();
|
let mut path_candidate_prefixes = Vec::new();
|
||||||
let mut item_text = String::new();
|
let mut path_text = String::new();
|
||||||
let mut stack = Vec::new();
|
let mut path_stack = Vec::new();
|
||||||
|
|
||||||
for (id, item) in items.iter().enumerate() {
|
for (id, item) in items.iter().enumerate() {
|
||||||
if item.depth < stack.len() {
|
if item.depth < path_stack.len() {
|
||||||
stack.truncate(item.depth);
|
path_stack.truncate(item.depth);
|
||||||
item_text.truncate(stack.last().copied().unwrap_or(0));
|
path_text.truncate(path_stack.last().copied().unwrap_or(0));
|
||||||
}
|
}
|
||||||
if !item_text.is_empty() {
|
if !path_text.is_empty() {
|
||||||
item_text.push(' ');
|
path_text.push(' ');
|
||||||
}
|
}
|
||||||
path_candidate_prefixes.push(item_text.len());
|
path_candidate_prefixes.push(path_text.len());
|
||||||
item_text.push_str(&item.text);
|
path_text.push_str(&item.text);
|
||||||
stack.push(item_text.len());
|
path_stack.push(path_text.len());
|
||||||
|
|
||||||
|
let candidate_text = item
|
||||||
|
.name_ranges
|
||||||
|
.iter()
|
||||||
|
.map(|range| &item.text[range.start as usize..range.end as usize])
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
path_candidates.push(StringMatchCandidate {
|
path_candidates.push(StringMatchCandidate {
|
||||||
id,
|
id,
|
||||||
string: item_text.clone(),
|
char_bag: path_text.as_str().into(),
|
||||||
char_bag: item_text.as_str().into(),
|
string: path_text.clone(),
|
||||||
|
});
|
||||||
|
candidates.push(StringMatchCandidate {
|
||||||
|
id,
|
||||||
|
char_bag: candidate_text.as_str().into(),
|
||||||
|
string: candidate_text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
candidates: items
|
candidates,
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(id, item)| StringMatchCandidate {
|
|
||||||
id,
|
|
||||||
char_bag: item.text.as_str().into(),
|
|
||||||
string: item.text.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
path_candidates,
|
path_candidates,
|
||||||
path_candidate_prefixes,
|
path_candidate_prefixes,
|
||||||
items,
|
items,
|
||||||
|
@ -93,6 +98,17 @@ impl<T> Outline<T> {
|
||||||
for position in &mut string_match.positions {
|
for position in &mut string_match.positions {
|
||||||
*position -= prefix_len;
|
*position -= prefix_len;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
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 insertion_ix = tree_matches.len();
|
||||||
|
|
|
@ -365,29 +365,34 @@ async fn test_outline(mut cx: gpui::TestAppContext) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Without space, we only match on names
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
search(&outline, "oon", &cx).await,
|
search(&outline, "oon", &cx).await,
|
||||||
&[
|
&[
|
||||||
("mod module", vec![]), // included as the parent of a match
|
("mod module", vec![]), // included as the parent of a match
|
||||||
("enum LoginState", vec![]), // included as the parent of a match
|
("enum LoginState", vec![]), // included as the parent of a match
|
||||||
("LoggingOn", vec![1, 7, 8]), // matches
|
("LoggingOn", vec![1, 7, 8]), // matches
|
||||||
("impl Eq for Person", vec![9, 16, 17]), // matches part of the context
|
("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
|
||||||
("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, 9, 14]),
|
||||||
|
("fn drop", vec![]),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
search(&outline, "dp p", &cx).await,
|
|
||||||
&[("impl Drop for Person", vec![5, 8, 9, 14])]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
search(&outline, "dpn", &cx).await,
|
search(&outline, "dpn", &cx).await,
|
||||||
&[("impl Drop for Person", vec![5, 8, 19])]
|
&[("impl Drop for Person", vec![5, 14, 19])]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
search(&outline, "impl", &cx).await,
|
search(&outline, "impl ", &cx).await,
|
||||||
&[
|
&[
|
||||||
("impl Eq for Person", vec![0, 1, 2, 3]),
|
("impl Eq for Person", vec![0, 1, 2, 3, 4]),
|
||||||
("impl Drop for Person", vec![0, 1, 2, 3])
|
("impl Drop for Person", vec![0, 1, 2, 3, 4]),
|
||||||
|
("fn drop", vec![]),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue