Add Buffer::language_at, update MultiBuffer to use it
Co-authored-by: Julia Risley <floc@unpromptedtirade.com>
This commit is contained in:
parent
a2e57e8d71
commit
67e188a015
16 changed files with 245 additions and 81 deletions
|
@ -641,6 +641,15 @@ impl Buffer {
|
|||
self.language.as_ref()
|
||||
}
|
||||
|
||||
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<Arc<Language>> {
|
||||
let offset = position.to_offset(self);
|
||||
self.syntax_map
|
||||
.lock()
|
||||
.layers_for_range(offset..offset, &self.text)
|
||||
.last()
|
||||
.map(|info| info.language.clone())
|
||||
}
|
||||
|
||||
pub fn parse_count(&self) -> usize {
|
||||
self.parse_count
|
||||
}
|
||||
|
@ -1826,6 +1835,14 @@ impl BufferSnapshot {
|
|||
self.language.as_ref()
|
||||
}
|
||||
|
||||
pub fn language_at<D: ToOffset>(&self, position: D) -> Option<&Arc<Language>> {
|
||||
let offset = position.to_offset(self);
|
||||
self.syntax
|
||||
.layers_for_range(offset..offset, &self.text)
|
||||
.last()
|
||||
.map(|info| info.language)
|
||||
}
|
||||
|
||||
pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
|
||||
let mut start = start.to_offset(self);
|
||||
let mut end = start;
|
||||
|
@ -1858,8 +1875,8 @@ impl BufferSnapshot {
|
|||
pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
let mut result: Option<Range<usize>> = None;
|
||||
'outer: for (_, _, node) in self.syntax.layers_for_range(range.clone(), &self.text) {
|
||||
let mut cursor = node.walk();
|
||||
'outer: for layer in self.syntax.layers_for_range(range.clone(), &self.text) {
|
||||
let mut cursor = layer.node.walk();
|
||||
|
||||
// Descend to the first leaf that touches the start of the range,
|
||||
// and if the range is non-empty, extends beyond the start.
|
||||
|
|
|
@ -135,7 +135,7 @@ impl CachedLspAdapter {
|
|||
pub async fn label_for_completion(
|
||||
&self,
|
||||
completion_item: &lsp::CompletionItem,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
self.adapter
|
||||
.label_for_completion(completion_item, language)
|
||||
|
@ -146,7 +146,7 @@ impl CachedLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
self.adapter.label_for_symbol(name, kind, language).await
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
_: &lsp::CompletionItem,
|
||||
_: &Language,
|
||||
_: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
None
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
&self,
|
||||
_: &str,
|
||||
_: lsp::SymbolKind,
|
||||
_: &Language,
|
||||
_: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
None
|
||||
}
|
||||
|
@ -793,7 +793,7 @@ impl Language {
|
|||
}
|
||||
|
||||
pub async fn label_for_completion(
|
||||
&self,
|
||||
self: &Arc<Self>,
|
||||
completion: &lsp::CompletionItem,
|
||||
) -> Option<CodeLabel> {
|
||||
self.adapter
|
||||
|
@ -802,7 +802,11 @@ impl Language {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn label_for_symbol(&self, name: &str, kind: lsp::SymbolKind) -> Option<CodeLabel> {
|
||||
pub async fn label_for_symbol(
|
||||
self: &Arc<Self>,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
) -> Option<CodeLabel> {
|
||||
self.adapter
|
||||
.as_ref()?
|
||||
.label_for_symbol(name, kind, self)
|
||||
|
@ -810,20 +814,17 @@ impl Language {
|
|||
}
|
||||
|
||||
pub fn highlight_text<'a>(
|
||||
&'a self,
|
||||
self: &'a Arc<Self>,
|
||||
text: &'a Rope,
|
||||
range: Range<usize>,
|
||||
) -> Vec<(Range<usize>, HighlightId)> {
|
||||
let mut result = Vec::new();
|
||||
if let Some(grammar) = &self.grammar {
|
||||
let tree = grammar.parse_text(text, None);
|
||||
let captures = SyntaxSnapshot::single_tree_captures(
|
||||
range.clone(),
|
||||
text,
|
||||
&tree,
|
||||
grammar,
|
||||
|grammar| grammar.highlights_query.as_ref(),
|
||||
);
|
||||
let captures =
|
||||
SyntaxSnapshot::single_tree_captures(range.clone(), text, &tree, self, |grammar| {
|
||||
grammar.highlights_query.as_ref()
|
||||
});
|
||||
let highlight_maps = vec![grammar.highlight_map()];
|
||||
let mut offset = 0;
|
||||
for chunk in BufferChunks::new(text, range, Some((captures, highlight_maps)), vec![]) {
|
||||
|
|
|
@ -92,6 +92,12 @@ struct SyntaxLayer {
|
|||
language: Arc<Language>,
|
||||
}
|
||||
|
||||
pub struct SyntaxLayerInfo<'a> {
|
||||
pub depth: usize,
|
||||
pub node: Node<'a>,
|
||||
pub language: &'a Arc<Language>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct SyntaxLayerSummary {
|
||||
min_depth: usize,
|
||||
|
@ -473,13 +479,18 @@ impl SyntaxSnapshot {
|
|||
range: Range<usize>,
|
||||
text: &'a Rope,
|
||||
tree: &'a Tree,
|
||||
grammar: &'a Grammar,
|
||||
language: &'a Arc<Language>,
|
||||
query: fn(&Grammar) -> Option<&Query>,
|
||||
) -> SyntaxMapCaptures<'a> {
|
||||
SyntaxMapCaptures::new(
|
||||
range.clone(),
|
||||
text,
|
||||
[(grammar, 0, tree.root_node())].into_iter(),
|
||||
[SyntaxLayerInfo {
|
||||
language,
|
||||
depth: 0,
|
||||
node: tree.root_node(),
|
||||
}]
|
||||
.into_iter(),
|
||||
query,
|
||||
)
|
||||
}
|
||||
|
@ -513,7 +524,7 @@ impl SyntaxSnapshot {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn layers(&self, buffer: &BufferSnapshot) -> Vec<(&Grammar, usize, Node)> {
|
||||
pub fn layers(&self, buffer: &BufferSnapshot) -> Vec<SyntaxLayerInfo> {
|
||||
self.layers_for_range(0..buffer.len(), buffer)
|
||||
}
|
||||
|
||||
|
@ -521,7 +532,7 @@ impl SyntaxSnapshot {
|
|||
&self,
|
||||
range: Range<T>,
|
||||
buffer: &BufferSnapshot,
|
||||
) -> Vec<(&Grammar, usize, Node)> {
|
||||
) -> Vec<SyntaxLayerInfo> {
|
||||
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
||||
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
||||
|
||||
|
@ -538,16 +549,14 @@ impl SyntaxSnapshot {
|
|||
let mut result = Vec::new();
|
||||
cursor.next(buffer);
|
||||
while let Some(layer) = cursor.item() {
|
||||
if let Some(grammar) = &layer.language.grammar {
|
||||
result.push((
|
||||
grammar.as_ref(),
|
||||
layer.depth,
|
||||
layer.tree.root_node_with_offset(
|
||||
layer.range.start.to_offset(buffer),
|
||||
layer.range.start.to_point(buffer).to_ts_point(),
|
||||
),
|
||||
));
|
||||
}
|
||||
result.push(SyntaxLayerInfo {
|
||||
language: &layer.language,
|
||||
depth: layer.depth,
|
||||
node: layer.tree.root_node_with_offset(
|
||||
layer.range.start.to_offset(buffer),
|
||||
layer.range.start.to_point(buffer).to_ts_point(),
|
||||
),
|
||||
});
|
||||
cursor.next(buffer)
|
||||
}
|
||||
|
||||
|
@ -559,7 +568,7 @@ impl<'a> SyntaxMapCaptures<'a> {
|
|||
fn new(
|
||||
range: Range<usize>,
|
||||
text: &'a Rope,
|
||||
layers: impl Iterator<Item = (&'a Grammar, usize, Node<'a>)>,
|
||||
layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
|
||||
query: fn(&Grammar) -> Option<&Query>,
|
||||
) -> Self {
|
||||
let mut result = Self {
|
||||
|
@ -567,11 +576,19 @@ impl<'a> SyntaxMapCaptures<'a> {
|
|||
grammars: Vec::new(),
|
||||
active_layer_count: 0,
|
||||
};
|
||||
for (grammar, depth, node) in layers {
|
||||
let query = if let Some(query) = query(grammar) {
|
||||
query
|
||||
} else {
|
||||
continue;
|
||||
for SyntaxLayerInfo {
|
||||
language,
|
||||
depth,
|
||||
node,
|
||||
} in layers
|
||||
{
|
||||
let grammar = match &language.grammar {
|
||||
Some(grammer) => grammer,
|
||||
None => continue,
|
||||
};
|
||||
let query = match query(&grammar) {
|
||||
Some(query) => query,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let mut query_cursor = QueryCursorHandle::new();
|
||||
|
@ -678,15 +695,23 @@ impl<'a> SyntaxMapMatches<'a> {
|
|||
fn new(
|
||||
range: Range<usize>,
|
||||
text: &'a Rope,
|
||||
layers: impl Iterator<Item = (&'a Grammar, usize, Node<'a>)>,
|
||||
layers: impl Iterator<Item = SyntaxLayerInfo<'a>>,
|
||||
query: fn(&Grammar) -> Option<&Query>,
|
||||
) -> Self {
|
||||
let mut result = Self::default();
|
||||
for (grammar, depth, node) in layers {
|
||||
let query = if let Some(query) = query(grammar) {
|
||||
query
|
||||
} else {
|
||||
continue;
|
||||
for SyntaxLayerInfo {
|
||||
language,
|
||||
depth,
|
||||
node,
|
||||
} in layers
|
||||
{
|
||||
let grammar = match &language.grammar {
|
||||
Some(grammer) => grammer,
|
||||
None => continue,
|
||||
};
|
||||
let query = match query(&grammar) {
|
||||
Some(query) => query,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let mut query_cursor = QueryCursorHandle::new();
|
||||
|
@ -1624,8 +1649,8 @@ mod tests {
|
|||
let reference_layers = reference_syntax_map.layers(&buffer);
|
||||
for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter())
|
||||
{
|
||||
assert_eq!(edited_layer.2.to_sexp(), reference_layer.2.to_sexp());
|
||||
assert_eq!(edited_layer.2.range(), reference_layer.2.range());
|
||||
assert_eq!(edited_layer.node.to_sexp(), reference_layer.node.to_sexp());
|
||||
assert_eq!(edited_layer.node.range(), reference_layer.node.range());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1770,13 +1795,13 @@ mod tests {
|
|||
mutated_layers.into_iter().zip(reference_layers.into_iter())
|
||||
{
|
||||
assert_eq!(
|
||||
edited_layer.2.to_sexp(),
|
||||
reference_layer.2.to_sexp(),
|
||||
edited_layer.node.to_sexp(),
|
||||
reference_layer.node.to_sexp(),
|
||||
"different layer at step {i}"
|
||||
);
|
||||
assert_eq!(
|
||||
edited_layer.2.range(),
|
||||
reference_layer.2.range(),
|
||||
edited_layer.node.range(),
|
||||
reference_layer.node.range(),
|
||||
"different layer at step {i}"
|
||||
);
|
||||
}
|
||||
|
@ -1828,7 +1853,7 @@ mod tests {
|
|||
expected_layers.len(),
|
||||
"wrong number of layers"
|
||||
);
|
||||
for (i, ((_, _, node), expected_s_exp)) in
|
||||
for (i, (SyntaxLayerInfo { node, .. }, expected_s_exp)) in
|
||||
layers.iter().zip(expected_layers.iter()).enumerate()
|
||||
{
|
||||
let actual_s_exp = node.to_sexp();
|
||||
|
|
|
@ -1449,7 +1449,7 @@ fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> Str
|
|||
buffer.read_with(cx, |buffer, _| {
|
||||
let snapshot = buffer.snapshot();
|
||||
let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
|
||||
layers[0].2.to_sexp()
|
||||
layers[0].node.to_sexp()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue