Add buffer method for getting the symbols containing a position
This commit is contained in:
parent
a0224cbe71
commit
257601b3c1
3 changed files with 146 additions and 38 deletions
|
@ -1667,6 +1667,31 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
|
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
|
||||||
|
self.outline_items_containing(0..self.len(), theme)
|
||||||
|
.map(Outline::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbols_containing<T: ToOffset>(
|
||||||
|
&self,
|
||||||
|
position: T,
|
||||||
|
theme: Option<&SyntaxTheme>,
|
||||||
|
) -> Option<Vec<OutlineItem<Anchor>>> {
|
||||||
|
let position = position.to_offset(&self);
|
||||||
|
let mut items = self.outline_items_containing(position - 1..position + 1, theme)?;
|
||||||
|
let mut prev_depth = None;
|
||||||
|
items.retain(|item| {
|
||||||
|
let result = prev_depth.map_or(true, |prev_depth| item.depth > prev_depth);
|
||||||
|
prev_depth = Some(item.depth);
|
||||||
|
result
|
||||||
|
});
|
||||||
|
Some(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outline_items_containing(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
theme: Option<&SyntaxTheme>,
|
||||||
|
) -> Option<Vec<OutlineItem<Anchor>>> {
|
||||||
let tree = self.tree.as_ref()?;
|
let tree = self.tree.as_ref()?;
|
||||||
let grammar = self
|
let grammar = self
|
||||||
.language
|
.language
|
||||||
|
@ -1674,6 +1699,7 @@ impl BufferSnapshot {
|
||||||
.and_then(|language| language.grammar.as_ref())?;
|
.and_then(|language| language.grammar.as_ref())?;
|
||||||
|
|
||||||
let mut cursor = QueryCursorHandle::new();
|
let mut cursor = QueryCursorHandle::new();
|
||||||
|
cursor.set_byte_range(range);
|
||||||
let matches = cursor.matches(
|
let matches = cursor.matches(
|
||||||
&grammar.outline_query,
|
&grammar.outline_query,
|
||||||
tree.root_node(),
|
tree.root_node(),
|
||||||
|
@ -1766,12 +1792,7 @@ impl BufferSnapshot {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
Some(items)
|
||||||
if items.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(Outline::new(items))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enclosing_bracket_ranges<T: ToOffset>(
|
pub fn enclosing_bracket_ranges<T: ToOffset>(
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub struct Outline<T> {
|
||||||
path_candidate_prefixes: Vec<usize>,
|
path_candidate_prefixes: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct OutlineItem<T> {
|
pub struct OutlineItem<T> {
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub range: Range<T>,
|
pub range: Range<T>,
|
||||||
|
|
|
@ -282,36 +282,6 @@ async fn test_reparse(cx: &mut gpui::TestAppContext) {
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_outline(cx: &mut gpui::TestAppContext) {
|
async fn test_outline(cx: &mut gpui::TestAppContext) {
|
||||||
let language = Arc::new(
|
|
||||||
rust_lang()
|
|
||||||
.with_outline_query(
|
|
||||||
r#"
|
|
||||||
(struct_item
|
|
||||||
"struct" @context
|
|
||||||
name: (_) @name) @item
|
|
||||||
(enum_item
|
|
||||||
"enum" @context
|
|
||||||
name: (_) @name) @item
|
|
||||||
(enum_variant
|
|
||||||
name: (_) @name) @item
|
|
||||||
(field_declaration
|
|
||||||
name: (_) @name) @item
|
|
||||||
(impl_item
|
|
||||||
"impl" @context
|
|
||||||
trait: (_) @name
|
|
||||||
"for" @context
|
|
||||||
type: (_) @name) @item
|
|
||||||
(function_item
|
|
||||||
"fn" @context
|
|
||||||
name: (_) @name) @item
|
|
||||||
(mod_item
|
|
||||||
"mod" @context
|
|
||||||
name: (_) @name) @item
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let text = r#"
|
let text = r#"
|
||||||
struct Person {
|
struct Person {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -339,7 +309,8 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
|
let buffer =
|
||||||
|
cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
|
||||||
let outline = buffer
|
let outline = buffer
|
||||||
.read_with(cx, |buffer, _| buffer.snapshot().outline(None))
|
.read_with(cx, |buffer, _| buffer.snapshot().outline(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -413,6 +384,93 @@ async fn test_outline(cx: &mut gpui::TestAppContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
|
||||||
|
let text = r#"
|
||||||
|
impl Person {
|
||||||
|
fn one() {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn two() {
|
||||||
|
2
|
||||||
|
}fn three() {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.unindent();
|
||||||
|
|
||||||
|
let buffer =
|
||||||
|
cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
|
||||||
|
let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
|
||||||
|
|
||||||
|
// point is at the start of an item
|
||||||
|
assert_eq!(
|
||||||
|
symbols_containing(Point::new(1, 4), &snapshot),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
"impl Person".to_string(),
|
||||||
|
Point::new(0, 0)..Point::new(10, 1)
|
||||||
|
),
|
||||||
|
("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// point is in the middle of an item
|
||||||
|
assert_eq!(
|
||||||
|
symbols_containing(Point::new(2, 8), &snapshot),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
"impl Person".to_string(),
|
||||||
|
Point::new(0, 0)..Point::new(10, 1)
|
||||||
|
),
|
||||||
|
("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// point is at the end of an item
|
||||||
|
assert_eq!(
|
||||||
|
symbols_containing(Point::new(3, 5), &snapshot),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
"impl Person".to_string(),
|
||||||
|
Point::new(0, 0)..Point::new(10, 1)
|
||||||
|
),
|
||||||
|
("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// point is in between two adjacent items
|
||||||
|
assert_eq!(
|
||||||
|
symbols_containing(Point::new(7, 5), &snapshot),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
"impl Person".to_string(),
|
||||||
|
Point::new(0, 0)..Point::new(10, 1)
|
||||||
|
),
|
||||||
|
("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
fn symbols_containing<'a>(
|
||||||
|
position: Point,
|
||||||
|
snapshot: &'a BufferSnapshot,
|
||||||
|
) -> Vec<(String, Range<Point>)> {
|
||||||
|
snapshot
|
||||||
|
.symbols_containing(position, None)
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| {
|
||||||
|
(
|
||||||
|
item.text,
|
||||||
|
item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
||||||
let buffer = cx.add_model(|cx| {
|
let buffer = cx.add_model(|cx| {
|
||||||
|
@ -851,6 +909,35 @@ fn rust_lang() -> Language {
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.with_outline_query(
|
||||||
|
r#"
|
||||||
|
(struct_item
|
||||||
|
"struct" @context
|
||||||
|
name: (_) @name) @item
|
||||||
|
(enum_item
|
||||||
|
"enum" @context
|
||||||
|
name: (_) @name) @item
|
||||||
|
(enum_variant
|
||||||
|
name: (_) @name) @item
|
||||||
|
(field_declaration
|
||||||
|
name: (_) @name) @item
|
||||||
|
(impl_item
|
||||||
|
"impl" @context
|
||||||
|
type: (_) @name) @item
|
||||||
|
(impl_item
|
||||||
|
"impl" @context
|
||||||
|
trait: (_) @name
|
||||||
|
"for" @context
|
||||||
|
type: (_) @name) @item
|
||||||
|
(function_item
|
||||||
|
"fn" @context
|
||||||
|
name: (_) @name) @item
|
||||||
|
(mod_item
|
||||||
|
"mod" @context
|
||||||
|
name: (_) @name) @item
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty(point: Point) -> Range<Point> {
|
fn empty(point: Point) -> Range<Point> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue