diff --git a/crates/editor/src/bracket_colorization.rs b/crates/editor/src/bracket_colorization.rs index 2e27f585f978b00681db222f21e935f230a168c0..d1c9ce49709ea31ceb99d53b1fa56632fa7d8d65 100644 --- a/crates/editor/src/bracket_colorization.rs +++ b/crates/editor/src/bracket_colorization.rs @@ -63,13 +63,15 @@ impl Editor { ..multi_buffer_snapshot .anchor_in_excerpt(excerpt_id, buffer_close_range.end)?; - let accent_number = pair.id % accents_count; - - Some(( - accent_number, - multi_buffer_open_range, - multi_buffer_close_range, - )) + pair.id.map(|id| { + let accent_number = id % accents_count; + + ( + accent_number, + multi_buffer_open_range, + multi_buffer_close_range, + ) + }) }); for (accent_number, open_range, close_range) in brackets_by_accent { @@ -109,16 +111,40 @@ impl Editor { #[cfg(test)] mod tests { - use std::time::Duration; + use std::{ops::Range, time::Duration}; use super::*; - use crate::{editor_tests::init_test, test::editor_lsp_test_context::EditorLspTestContext}; + use crate::{ + editor_tests::init_test, + test::{ + editor_lsp_test_context::EditorLspTestContext, editor_test_context::EditorTestContext, + }, + }; + use gpui::Hsla; use indoc::indoc; use language::{BracketPair, BracketPairConfig, Language, LanguageConfig, LanguageMatcher}; use multi_buffer::AnchorRangeExt as _; + use rope::Point; #[gpui::test] async fn test_rainbow_bracket_highlights(cx: &mut gpui::TestAppContext) { + fn collect_colored_brackets( + cx: &mut EditorTestContext, + ) -> Vec<(Option, Range)> { + cx.update_editor(|editor, window, cx| { + let snapshot = editor.snapshot(window, cx); + snapshot + .all_text_highlight_ranges::() + .iter() + .flat_map(|ranges| { + ranges.1.iter().map(|range| { + (ranges.0.color, range.to_point(&snapshot.buffer_snapshot())) + }) + }) + .collect::>() + }) + } + init_test(cx, |language_settings| { language_settings.defaults.colorize_brackets = Some(true); }); @@ -164,6 +190,8 @@ mod tests { ) .await; + let mut highlighted_brackets = HashMap::default(); + // taken from r-a https://github.com/rust-lang/rust-analyzer/blob/d733c07552a2dc0ec0cc8f4df3f0ca969a93fd90/crates/ide/src/inlay_hints.rs#L81-L297 cx.set_state(indoc! {r#"ˇ pub(crate) fn inlay_hints( @@ -387,19 +415,12 @@ mod tests { cx.executor().advance_clock(Duration::from_millis(100)); cx.executor().run_until_parked(); - let actual_ranges = cx.update_editor(|editor, window, cx| { - let snapshot = editor.snapshot(window, cx); - snapshot - .all_text_highlight_ranges::() - .iter() - .flat_map(|ranges| { - ranges - .1 - .iter() - .map(|range| (ranges.0.color, range.to_point(&snapshot.buffer_snapshot()))) - }) - .collect::>() - }); + let actual_ranges = collect_colored_brackets(&mut cx); + + for (color, range) in actual_ranges.iter().cloned() { + highlighted_brackets.insert(range, color); + } + let last_bracket = actual_ranges .iter() .max_by_key(|(_, p)| p.end.row) @@ -417,28 +438,40 @@ mod tests { cx.executor().advance_clock(Duration::from_millis(100)); cx.executor().run_until_parked(); - let ranges_after_scrolling = cx.update_editor(|editor, window, cx| { - let snapshot = editor.snapshot(window, cx); - snapshot - .all_text_highlight_ranges::() - .iter() - .flat_map(|ranges| { - ranges - .1 - .iter() - .map(|range| (ranges.0.color, range.to_point(&snapshot.buffer_snapshot()))) - }) - .collect::>() - }); + let ranges_after_scrolling = collect_colored_brackets(&mut cx); let new_last_bracket = ranges_after_scrolling .iter() .max_by_key(|(_, p)| p.end.row) .unwrap() .clone(); - // todo! more tests, check consistency of the colors picked also, settings toggle + assert_ne!( last_bracket, new_last_bracket, "After scrolling down, we should have highlighted more brackets" ); + + cx.update_editor(|editor, window, cx| { + let was_scrolled = editor.set_scroll_position(gpui::Point::default(), window, cx); + assert!(was_scrolled.0); + }); + + for _ in 0..200 { + cx.update_editor(|editor, window, cx| { + editor.apply_scroll_delta(gpui::Point::new(0.0, 0.25), window, cx); + }); + cx.executor().run_until_parked(); + + for (color, range) in collect_colored_brackets(&mut cx) { + assert!( + highlighted_brackets + .entry(range.clone()) + .or_insert(color.clone()) + == &color, + "Colors should stay consistent while scrolling!" + ); + } + } + + // todo! more tests, check no brackets missing in range, settings toggle } } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index f3d555b157ad9348364d0808d65479342afc5f94..b3d8fa4ea541417e8ab4560b721a771cc82f023c 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -48,7 +48,7 @@ use std::{ iter::{self, Iterator, Peekable}, mem, num::NonZeroU32, - ops::{Deref, Range}, + ops::{Deref, Not, Range}, path::PathBuf, rc, sync::{Arc, LazyLock}, @@ -850,7 +850,7 @@ pub struct BracketMatch { pub open_range: Range, pub close_range: Range, pub newline_only: bool, - pub id: usize, + pub id: Option, } impl BracketMatch { @@ -4210,7 +4210,7 @@ impl BufferSnapshot { .as_ref() .and_then(|previous_brackets| previous_brackets.last()) // Try to continue previous sequence of IDs. - .map(|bracket| bracket.id + 1) + .and_then(|bracket| bracket.id.map(|id| id + 1)) // If not possible, start another sequence: pick it far enough to avoid overlaps. // // This for sure will introduce the gaps between chunks' bracket IDs, @@ -4261,7 +4261,10 @@ impl BufferSnapshot { open_range, close_range, newline_only: pattern.newline_only, - id: post_inc(&mut next_id), + id: pattern + .rainbow_exclude + .not() + .then(|| post_inc(&mut next_id)), }); } None diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 75f53524efc40e2cfaf06c5bbe893b7c5af5883c..6e6b3eee97c4b6117334bf7c811ffcf27cbc6c8d 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -1322,6 +1322,7 @@ struct BracketsConfig { #[derive(Clone, Debug, Default)] struct BracketsPatternConfig { newline_only: bool, + rainbow_exclude: bool, } pub struct DebugVariablesConfig { @@ -1684,9 +1685,13 @@ impl Language { .map(|ix| { let mut config = BracketsPatternConfig::default(); for setting in query.property_settings(ix) { - if setting.key.as_ref() == "newline.only" { + let setting_key = setting.key.as_ref(); + if setting_key == "newline.only" { config.newline_only = true } + if setting_key == "rainbow.exclude" { + config.rainbow_exclude = true + } } config }) diff --git a/crates/languages/src/rust/brackets.scm b/crates/languages/src/rust/brackets.scm index 0bf19b8085fb035b28c8b19dc07ff0df191c9c26..baa3178e51f894d1bea1dfc5c1bb308c43f140a1 100644 --- a/crates/languages/src/rust/brackets.scm +++ b/crates/languages/src/rust/brackets.scm @@ -2,6 +2,6 @@ ("[" @open "]" @close) ("{" @open "}" @close) ("<" @open ">" @close) -("\"" @open "\"" @close) +(("\"" @open "\"" @close) (#set! rainbow.exclude)) (closure_parameters "|" @open "|" @close) ("'" @open "'" @close)