intial fix

Smit Barmase created

Change summary

crates/language/src/buffer.rs            | 101 +++++++++++++++++++------
crates/language/src/language.rs          |  31 +++++++
crates/languages/src/rust/highlights.scm |  13 +++
3 files changed, 118 insertions(+), 27 deletions(-)

Detailed changes

crates/language/src/buffer.rs πŸ”—

@@ -539,8 +539,51 @@ struct IndentSuggestion {
 struct BufferChunkHighlights<'a> {
     captures: SyntaxMapCaptures<'a>,
     next_capture: Option<SyntaxMapCapture<'a>>,
-    stack: Vec<(usize, HighlightId)>,
+    stack: Vec<HighlightStackEntry>,
     highlight_maps: Vec<HighlightMap>,
+    block_nested_captures: Vec<Vec<bool>>,
+}
+
+#[derive(Clone)]
+struct HighlightStackEntry {
+    end_offset: usize,
+    highlight_id: HighlightId,
+    block_nested: bool,
+}
+
+impl BufferChunkHighlights<'_> {
+    fn blocks_nested_captures(&self, grammar_index: usize, capture_index: u32) -> bool {
+        self.block_nested_captures
+            .get(grammar_index)
+            .and_then(|captures| captures.get(capture_index as usize))
+            .copied()
+            .unwrap_or(false)
+    }
+}
+
+fn build_buffer_chunk_highlights<'a>(
+    captures: SyntaxMapCaptures<'a>,
+    highlight_maps: Vec<HighlightMap>,
+) -> BufferChunkHighlights<'a> {
+    let block_nested_captures = captures
+        .grammars()
+        .iter()
+        .map(|grammar| {
+            grammar
+                .highlights_config
+                .as_ref()
+                .map(|config| config.block_nested_captures.clone())
+                .unwrap_or_default()
+        })
+        .collect();
+
+    BufferChunkHighlights {
+        captures,
+        next_capture: None,
+        stack: Default::default(),
+        highlight_maps,
+        block_nested_captures,
+    }
 }
 
 /// An iterator that yields chunks of a buffer's text, along with their
@@ -5474,12 +5517,7 @@ impl<'a> BufferChunks<'a> {
     ) -> Self {
         let mut highlights = None;
         if let Some((captures, highlight_maps)) = syntax {
-            highlights = Some(BufferChunkHighlights {
-                captures,
-                next_capture: None,
-                stack: Default::default(),
-                highlight_maps,
-            })
+            highlights = Some(build_buffer_chunk_highlights(captures, highlight_maps))
         }
 
         let diagnostic_endpoints = diagnostics.then(|| Vec::new().into_iter().peekable());
@@ -5511,27 +5549,25 @@ impl<'a> BufferChunks<'a> {
                 //Β Reuse existing highlights stack, as the new range is a subrange of the old one.
                 highlights
                     .stack
-                    .retain(|(end_offset, _)| *end_offset > range.start);
+                    .retain(|entry| entry.end_offset > range.start);
                 if let Some(capture) = &highlights.next_capture
                     && range.start >= capture.node.start_byte()
                 {
                     let next_capture_end = capture.node.end_byte();
                     if range.start < next_capture_end {
-                        highlights.stack.push((
-                            next_capture_end,
-                            highlights.highlight_maps[capture.grammar_index].get(capture.index),
-                        ));
+                        highlights.stack.push(HighlightStackEntry {
+                            end_offset: next_capture_end,
+                            highlight_id: highlights.highlight_maps[capture.grammar_index]
+                                .get(capture.index),
+                            block_nested: highlights
+                                .blocks_nested_captures(capture.grammar_index, capture.index),
+                        });
                     }
                     highlights.next_capture.take();
                 }
             } else if let Some(snapshot) = self.buffer_snapshot {
                 let (captures, highlight_maps) = snapshot.get_highlights(self.range.clone());
-                *highlights = BufferChunkHighlights {
-                    captures,
-                    next_capture: None,
-                    stack: Default::default(),
-                    highlight_maps,
-                };
+                *highlights = build_buffer_chunk_highlights(captures, highlight_maps);
             } else {
                 // We cannot obtain new highlights for a language-aware buffer iterator, as we don't have a buffer snapshot.
                 // Seeking such BufferChunks is not supported.
@@ -5636,8 +5672,8 @@ impl<'a> Iterator for BufferChunks<'a> {
         let mut next_diagnostic_endpoint = usize::MAX;
 
         if let Some(highlights) = self.highlights.as_mut() {
-            while let Some((parent_capture_end, _)) = highlights.stack.last() {
-                if *parent_capture_end <= self.range.start {
+            while let Some(parent_capture) = highlights.stack.last() {
+                if parent_capture.end_offset <= self.range.start {
                     highlights.stack.pop();
                 } else {
                     break;
@@ -5653,11 +5689,24 @@ impl<'a> Iterator for BufferChunks<'a> {
                     next_capture_start = capture.node.start_byte();
                     break;
                 } else {
+                    if highlights
+                        .stack
+                        .last()
+                        .is_some_and(|parent_capture| parent_capture.block_nested)
+                    {
+                        highlights.next_capture = highlights.captures.next();
+                        continue;
+                    }
+
                     let highlight_id =
                         highlights.highlight_maps[capture.grammar_index].get(capture.index);
-                    highlights
-                        .stack
-                        .push((capture.node.end_byte(), highlight_id));
+                    highlights.stack.push(HighlightStackEntry {
+                        end_offset: capture.node.end_byte(),
+                        highlight_id,
+                        block_nested: highlights
+                            .blocks_nested_captures(capture.grammar_index, capture.index),
+                    });
+
                     highlights.next_capture = highlights.captures.next();
                 }
             }
@@ -5691,10 +5740,10 @@ impl<'a> Iterator for BufferChunks<'a> {
                 .min(next_diagnostic_endpoint);
             let mut highlight_id = None;
             if let Some(highlights) = self.highlights.as_ref()
-                && let Some((parent_capture_end, parent_highlight_id)) = highlights.stack.last()
+                && let Some(parent_capture) = highlights.stack.last()
             {
-                chunk_end = chunk_end.min(*parent_capture_end);
-                highlight_id = Some(*parent_highlight_id);
+                chunk_end = chunk_end.min(parent_capture.end_offset);
+                highlight_id = Some(parent_capture.highlight_id);
             }
             let bit_start = chunk_start - self.chunks.offset();
             let bit_end = chunk_end - self.chunks.offset();

crates/language/src/language.rs πŸ”—

@@ -75,7 +75,7 @@ pub use toolchain::{
     LanguageToolchainStore, LocalLanguageToolchainStore, Toolchain, ToolchainList, ToolchainLister,
     ToolchainMetadata, ToolchainScope,
 };
-use tree_sitter::{self, Query, QueryCursor, WasmStore, wasmtime};
+use tree_sitter::{self, CaptureQuantifier, Query, QueryCursor, WasmStore, wasmtime};
 use util::rel_path::RelPath;
 use util::serde::default_true;
 
@@ -1383,6 +1383,7 @@ pub struct Grammar {
 pub struct HighlightsConfig {
     pub query: Query,
     pub identifier_capture_indices: Vec<u32>,
+    pub(crate) block_nested_captures: Vec<bool>,
 }
 
 struct IndentConfig {
@@ -1650,6 +1651,7 @@ impl Language {
     pub fn with_highlights_query(mut self, source: &str) -> Result<Self> {
         let grammar = self.grammar_mut()?;
         let query = Query::new(&grammar.ts_language, source)?;
+        let block_nested_captures = highlight_block_nested_captures(&query);
 
         let mut identifier_capture_indices = Vec::new();
         for name in [
@@ -1670,6 +1672,7 @@ impl Language {
         grammar.highlights_config = Some(HighlightsConfig {
             query,
             identifier_capture_indices,
+            block_nested_captures,
         });
 
         Ok(self)
@@ -2752,6 +2755,32 @@ fn populate_capture_indices(
     success
 }
 
+fn highlight_block_nested_captures(query: &Query) -> Vec<bool> {
+    let mut block_nested_captures = vec![false; query.capture_names().len()];
+
+    for pattern_index in 0..query.pattern_count() {
+        let block_nested = query
+            .property_settings(pattern_index)
+            .iter()
+            .any(|setting| setting.key.as_ref() == "highlight.block-nested");
+        if !block_nested {
+            continue;
+        }
+
+        for (capture_index, quantifier) in
+            query.capture_quantifiers(pattern_index).iter().enumerate()
+        {
+            if *quantifier == CaptureQuantifier::Zero {
+                continue;
+            }
+
+            block_nested_captures[capture_index] = true;
+        }
+    }
+
+    block_nested_captures
+}
+
 pub fn point_to_lsp(point: PointUtf16) -> lsp::Position {
     lsp::Position::new(point.row, point.column)
 }

crates/languages/src/rust/highlights.scm πŸ”—

@@ -258,3 +258,16 @@ operator: "/" @operator
         "::"
         (#match? @none "^[a-z\\d_]*$"))
     ]))
+
+((token_tree
+   [
+     "@"
+     ":"
+   ]
+   .
+   [
+     (string_literal)
+     (raw_string_literal)
+     (char_literal)
+   ] @string.macro)
+  (#set! highlight.block-nested))