From 7247db2ed3be9693192a950496bb530ef9133f2e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:25:01 +0100 Subject: [PATCH] WIP Co-authored-by: Kirill --- crates/language/src/buffer.rs | 127 ++++++++++++++++------------ crates/language/src/buffer_tests.rs | 25 ++++++ 2 files changed, 97 insertions(+), 55 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index a30bb786df..729f30b526 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -66,7 +66,6 @@ pub use text::{ Transaction, TransactionId, Unclipped, }; use theme::{ActiveTheme as _, SyntaxTheme}; -use tree_sitter::QueryMatches; #[cfg(any(test, feature = "test-support"))] use util::RandomCharIter; @@ -483,15 +482,16 @@ struct BufferChunkHighlights<'a> { trait Highlighter<'a>: 'a { fn narrow(&mut self, range: Range); // Return starting offset of the next capture. - fn seek_next_capture_offset(&mut self, current_offset: usize) -> usize; - fn current_capture(&self) -> Option<(usize, HighlightId)>; + fn seek_next_capture_offset(&mut self, current_offset: usize); + fn current_capture(&self) -> Option<(Range, HighlightId)>; + fn advance(&mut self); fn set_byte_range(&mut self, range: Range); } struct TreeSitterHighlights<'a> { captures: SyntaxMapCaptures<'a>, next_capture: Option>, - stack: Vec<(usize, HighlightId)>, + stack: Vec<(Range, HighlightId)>, highlight_maps: Vec, } @@ -510,13 +510,14 @@ impl<'a> Highlighter<'a> for TreeSitterHighlights<'a> { /// Preserve the existing highlights only if they fall within a provided range. fn narrow(&mut self, range: Range) { self.stack - .retain(|(end_offset, _)| *end_offset > range.start); + .retain(|(offset_range, _)| offset_range.end > range.start); if let Some(capture) = &self.next_capture { - if range.start >= capture.node.start_byte() { + let next_capture_start = capture.node.start_byte(); + if range.start >= next_capture_start { let next_capture_end = capture.node.end_byte(); if range.start < next_capture_end { self.stack.push(( - next_capture_end, + next_capture_start..next_capture_end, self.highlight_maps[capture.grammar_index].get(capture.index), )); } @@ -525,10 +526,9 @@ impl<'a> Highlighter<'a> for TreeSitterHighlights<'a> { } } - fn seek_next_capture_offset(&mut self, current_offset: usize) -> usize { - let mut next_capture_start = usize::MAX; - while let Some((parent_capture_end, _)) = self.stack.last() { - if *parent_capture_end <= current_offset { + fn seek_next_capture_offset(&mut self, current_offset: usize) { + while let Some((parent_range, _)) = self.stack.last() { + if parent_range.end <= current_offset { self.stack.pop(); } else { break; @@ -542,21 +542,23 @@ impl<'a> Highlighter<'a> for TreeSitterHighlights<'a> { while let Some(capture) = self.next_capture.as_ref() { let start_byte = capture.node.start_byte(); if current_offset < start_byte { - next_capture_start = start_byte; break; } else { let highlight_id = self.highlight_maps[capture.grammar_index].get(capture.index); - self.stack.push((capture.node.end_byte(), highlight_id)); + self.stack + .push((start_byte..capture.node.end_byte(), highlight_id)); self.next_capture = self.captures.next(); } } - next_capture_start } fn set_byte_range(&mut self, range: Range) { self.captures.set_byte_range(range); } - fn current_capture(&self) -> Option<(usize, HighlightId)> { - self.stack.last().copied() + fn current_capture(&self) -> Option<(Range, HighlightId)> { + self.stack.last().cloned() + } + fn advance(&mut self) { + self.stack.pop(); } } @@ -566,26 +568,27 @@ struct RainbowBracketsHighlighter<'a> { colors: BTreeMap, /// Index of next color to use. - palette_index: u32, - palette: HighlightMap, + palette_index: usize, + palette: Vec, } impl<'a> RainbowBracketsHighlighter<'a> { - fn new(palette: HighlightMap, matches: SyntaxMapMatches<'a>) -> Option { - if palette.is_empty() { - return None; - } + fn new(_palette: HighlightMap, matches: SyntaxMapMatches<'a>) -> Option { + // if palette.is_empty() { + // return None; + // } + // let palette = HighlightMap::new() Some(RainbowBracketsHighlighter { matches, colors: BTreeMap::new(), palette_index: 0, - palette, + palette: vec![HighlightId(0), HighlightId(1)], }) } - fn next_highlight_id(palette: &HighlightMap, palette_index: &mut u32) -> HighlightId { + fn next_highlight_id(palette: &[HighlightId], palette_index: &mut usize) -> HighlightId { let next_highlight_id = palette.get(*palette_index); - *palette_index = (*palette_index + 1) % palette.len() as u32; - next_highlight_id + *palette_index = (*palette_index + 1) % palette.len(); + *(next_highlight_id.unwrap()) } } impl<'a> Highlighter<'a> for RainbowBracketsHighlighter<'a> { @@ -606,15 +609,17 @@ impl<'a> Highlighter<'a> for RainbowBracketsHighlighter<'a> { // } } - fn seek_next_capture_offset(&mut self, current_offset: usize) -> usize { + fn seek_next_capture_offset(&mut self, current_offset: usize) { // First let's fetch captures up until the opening brace is past the current_offset // The ending brace might fall within visible range. - let mut next_capture_start = usize::MAX; + if self .colors .iter() .next() - .map_or(true, |((start_byte, _), _)| *start_byte < current_offset) + .map_or(true, |((start_byte, _), _)| { + dbg!(*start_byte) < dbg!(current_offset) + }) { while let Some(matches) = self.matches.peek() { let [start, end] = matches.captures else { @@ -629,7 +634,7 @@ impl<'a> Highlighter<'a> for RainbowBracketsHighlighter<'a> { } let Range { start, end } = end.node.byte_range(); self.colors.insert((start, end), highlight_id); - if !self.matches.advance() { + if !dbg!(self.matches.advance()) { break; } if start_byte > current_offset { @@ -641,19 +646,22 @@ impl<'a> Highlighter<'a> for RainbowBracketsHighlighter<'a> { // Now let's throw away anything that starts before current_offset self.colors .retain(|(start, end), _| *start > current_offset || *end > current_offset); - if let Some(((start_offset, _), _)) = self.colors.iter().next() { - next_capture_start = *start_offset.max(¤t_offset); - } - next_capture_start } fn set_byte_range(&mut self, range: Range) { self.matches.set_byte_range(range); } - fn current_capture(&self) -> Option<(usize, HighlightId)> { + + fn current_capture(&self) -> Option<(Range, HighlightId)> { + dbg!(&self.colors); self.colors .iter() .next() - .map(|((_, end_offset), highlight_id)| (*end_offset, *highlight_id)) + .map(|((start_offset, end_offset), highlight_id)| { + (*start_offset..*end_offset, *highlight_id) + }) + } + fn advance(&mut self) { + self.colors.pop_first(); } } @@ -674,24 +682,27 @@ impl<'a> BufferChunkHighlights<'a> { }); } - fn seek_next_capture_offset(&mut self, current_offset: usize) -> usize { - let mut next_capture_start = usize::MAX; - + fn seek_next_capture_offset(&mut self, current_offset: usize) { for highlighter in &mut self.highlighters { - let next_start = highlighter.seek_next_capture_offset(current_offset); - next_capture_start = next_capture_start.min(next_start); + highlighter.seek_next_capture_offset(current_offset); } - next_capture_start } - fn current_capture(&self) -> Option<(usize, HighlightId)> { + fn current_capture(&mut self) -> Option<(Range, HighlightId)> { self.highlighters - .iter() + .iter_mut() .min_by_key(|highlighter| { highlighter .current_capture() - .map_or(usize::MAX, |(offset, _)| offset) + .map_or((usize::MAX, usize::MAX), |(range, _)| { + (range.start, range.end) + }) + }) + .and_then(|highlighter| { + let ret = highlighter.current_capture(); + highlighter.advance(); + dbg!(&ret); + ret }) - .and_then(|highlighter| highlighter.current_capture()) } } @@ -948,11 +959,13 @@ impl EditPreview { .iter() .map(|grammar| grammar.highlight_map()) .collect(); - + let matches = syntax_snapshot.matches(range.clone(), snapshot, |grammar| { + grammar.brackets_config.as_ref().map(|config| &config.query) + }); BufferChunks::new( snapshot.as_rope(), range, - Some((captures, highlight_maps)), + Some((captures, highlight_maps, matches)), false, None, ) @@ -4442,8 +4455,14 @@ impl<'a> Iterator for BufferChunks<'a> { fn next(&mut self) -> Option { let mut next_diagnostic_endpoint = usize::MAX; let mut next_capture_start = usize::MAX; + let mut current_capture = None; if let Some(highlights) = self.highlights.as_mut() { - next_capture_start = highlights.seek_next_capture_offset(self.range.start); + highlights.seek_next_capture_offset(self.range.start); + current_capture = highlights.current_capture(); + dbg!(¤t_capture, &self.range); + if let Some(next_capture) = ¤t_capture { + next_capture_start = next_capture.0.start; + } } let mut diagnostic_endpoints = std::mem::take(&mut self.diagnostic_endpoints); @@ -4467,12 +4486,10 @@ impl<'a> Iterator for BufferChunks<'a> { .min(next_capture_start) .min(next_diagnostic_endpoint); let mut highlight_id = None; - if let Some(highlights) = self.highlights.as_ref() { - if let Some((parent_capture_end, parent_highlight_id)) = - highlights.current_capture() - { - chunk_end = chunk_end.min(parent_capture_end); - highlight_id = Some(parent_highlight_id); + if let Some(highlights) = self.highlights.as_mut() { + if let Some((parent_range, parent_highlight_id)) = ¤t_capture { + chunk_end = chunk_end.min(parent_range.end); + highlight_id = Some(*parent_highlight_id); } } diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index 2beae53e2f..e6bc217685 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -3118,6 +3118,31 @@ fn test_trailing_whitespace_ranges(mut rng: StdRng) { ); } +#[gpui::test] +async fn test_rainbow_brackets(cx: &mut TestAppContext) { + cx.update(|cx| { + init_settings(cx, |_| {}); + theme::init(theme::LoadThemes::JustBase, cx); + }); + + static BUFFER_TEXT: &str = r#" + use crate::{bar}; + "#; + + let rust_lang = Arc::new(rust_lang().with_highlights_query("").unwrap()); + rust_lang.set_theme(&SyntaxTheme { + highlights: vec![("foo".to_string(), HighlightStyle::default())], + }); + let buffer = cx.new(|cx| Buffer::local(BUFFER_TEXT, cx).with_language(rust_lang, cx)); + buffer.update(cx, |buffer, cx| { + let snapshot = buffer.snapshot(); + let chunks = snapshot + .chunks(0..BUFFER_TEXT.len(), true) + .collect::>(); + dbg!(&chunks); + }); +} + fn ruby_lang() -> Language { Language::new( LanguageConfig {