Add rainbow highlights based on tree-sitter queries

rainbow
Michael Davis 2025-02-27 10:27:57 -05:00
parent f46222ced3
commit 71cc25cbef
No known key found for this signature in database
36 changed files with 844 additions and 5 deletions

View File

@ -13,14 +13,18 @@ use std::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use arc_swap::{ArcSwap, Guard}; use arc_swap::{ArcSwap, Guard};
use config::{Configuration, FileType, LanguageConfiguration, LanguageServerConfiguration}; use config::{Configuration, FileType, LanguageConfiguration, LanguageServerConfiguration};
use foldhash::HashSet;
use helix_loader::grammar::get_language; use helix_loader::grammar::get_language;
use helix_stdx::rope::RopeSliceExt as _; use helix_stdx::rope::RopeSliceExt as _;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use ropey::RopeSlice; use ropey::RopeSlice;
use tree_house::{ use tree_house::{
highlighter, highlighter,
query_iter::QueryIter, query_iter::{QueryIter, QueryIterEvent},
tree_sitter::{Grammar, InactiveQueryCursor, InputEdit, Node, Query, RopeInput, Tree}, tree_sitter::{
query::{InvalidPredicateError, UserPredicate},
Capture, Grammar, InactiveQueryCursor, InputEdit, Node, Pattern, Query, RopeInput, Tree,
},
Error, InjectionLanguageMarker, LanguageConfig as SyntaxConfig, Layer, Error, InjectionLanguageMarker, LanguageConfig as SyntaxConfig, Layer,
}; };
@ -37,6 +41,7 @@ pub struct LanguageData {
syntax: OnceCell<Option<SyntaxConfig>>, syntax: OnceCell<Option<SyntaxConfig>>,
indent_query: OnceCell<Option<IndentQuery>>, indent_query: OnceCell<Option<IndentQuery>>,
textobject_query: OnceCell<Option<TextObjectQuery>>, textobject_query: OnceCell<Option<TextObjectQuery>>,
rainbow_query: OnceCell<Option<RainbowQuery>>,
} }
impl LanguageData { impl LanguageData {
@ -46,6 +51,7 @@ impl LanguageData {
syntax: OnceCell::new(), syntax: OnceCell::new(),
indent_query: OnceCell::new(), indent_query: OnceCell::new(),
textobject_query: OnceCell::new(), textobject_query: OnceCell::new(),
rainbow_query: OnceCell::new(),
} }
} }
@ -154,6 +160,36 @@ impl LanguageData {
.as_ref() .as_ref()
} }
/// Compiles the rainbows.scm query for a language.
/// This function should only be used by this module or the xtask crate.
pub fn compile_rainbow_query(
grammar: Grammar,
config: &LanguageConfiguration,
) -> Result<Option<RainbowQuery>> {
let name = &config.language_id;
let text = read_query(name, "rainbows.scm");
if text.is_empty() {
return Ok(None);
}
let rainbow_query = RainbowQuery::new(grammar, &text)
.with_context(|| format!("Failed to compile rainbows.scm query for '{name}'"))?;
Ok(Some(rainbow_query))
}
fn rainbow_query(&self, loader: &Loader) -> Option<&RainbowQuery> {
self.rainbow_query
.get_or_init(|| {
let grammar = self.syntax_config(loader)?.grammar;
Self::compile_rainbow_query(grammar, &self.config)
.map_err(|err| {
log::error!("{err}");
})
.ok()
.flatten()
})
.as_ref()
}
fn reconfigure(&self, scopes: &[String]) { fn reconfigure(&self, scopes: &[String]) {
if let Some(Some(config)) = self.syntax.get() { if let Some(Some(config)) = self.syntax.get() {
reconfigure_highlights(config, scopes); reconfigure_highlights(config, scopes);
@ -324,6 +360,10 @@ impl Loader {
self.language(lang).textobject_query(self) self.language(lang).textobject_query(self)
} }
fn rainbow_query(&self, lang: Language) -> Option<&RainbowQuery> {
self.language(lang).rainbow_query(self)
}
pub fn language_server_configs(&self) -> &HashMap<String, LanguageServerConfiguration> { pub fn language_server_configs(&self) -> &HashMap<String, LanguageServerConfiguration> {
&self.language_server_configs &self.language_server_configs
} }
@ -496,6 +536,79 @@ impl Syntax {
{ {
QueryIter::new(&self.inner, source, loader, range) QueryIter::new(&self.inner, source, loader, range)
} }
pub fn rainbow_highlights(
&self,
source: RopeSlice,
rainbow_length: usize,
loader: &Loader,
range: impl RangeBounds<u32>,
) -> OverlayHighlights {
struct RainbowScope<'tree> {
end: u32,
node: Option<Node<'tree>>,
highlight: Highlight,
}
let mut scope_stack = Vec::<RainbowScope>::new();
let mut highlights = Vec::new();
let mut query_iter = self.query_iter::<_, (), _>(
source,
|lang| loader.rainbow_query(lang).map(|q| &q.query),
range,
);
while let Some(event) = query_iter.next() {
let QueryIterEvent::Match(mat) = event else {
continue;
};
let rainbow_query = loader
.rainbow_query(query_iter.current_language())
.expect("language must have a rainbow query to emit matches");
let byte_range = mat.node.byte_range();
// Pop any scopes that end before this capture begins.
while scope_stack
.last()
.is_some_and(|scope| byte_range.start >= scope.end)
{
scope_stack.pop();
}
let capture = Some(mat.capture);
if capture == rainbow_query.scope_capture {
scope_stack.push(RainbowScope {
end: byte_range.end,
node: if rainbow_query
.include_children_patterns
.contains(&mat.pattern)
{
None
} else {
Some(mat.node.clone())
},
highlight: Highlight::new((scope_stack.len() % rainbow_length) as u32),
});
} else if capture == rainbow_query.bracket_capture {
if let Some(scope) = scope_stack.last() {
if !scope
.node
.as_ref()
.is_some_and(|node| mat.node.parent().as_ref() != Some(node))
{
let start = source
.byte_to_char(source.floor_char_boundary(byte_range.start as usize));
let end =
source.byte_to_char(source.ceil_char_boundary(byte_range.end as usize));
highlights.push((scope.highlight, start..end));
}
}
}
}
OverlayHighlights::Heterogenous { highlights }
}
} }
pub type Highlighter<'a> = highlighter::Highlighter<'a, 'a, Loader>; pub type Highlighter<'a> = highlighter::Highlighter<'a, 'a, Loader>;
@ -939,6 +1052,57 @@ fn pretty_print_tree_impl<W: fmt::Write>(
Ok(()) Ok(())
} }
/// Finds the child of `node` which contains the given byte range.
pub fn child_for_byte_range<'a>(node: &Node<'a>, range: ops::Range<u32>) -> Option<Node<'a>> {
for child in node.children() {
let child_range = child.byte_range();
if range.start >= child_range.start && range.end <= child_range.end {
return Some(child);
}
}
None
}
#[derive(Debug)]
pub struct RainbowQuery {
query: Query,
include_children_patterns: HashSet<Pattern>,
scope_capture: Option<Capture>,
bracket_capture: Option<Capture>,
}
impl RainbowQuery {
fn new(grammar: Grammar, source: &str) -> Result<Self, tree_sitter::query::ParseError> {
let mut include_children_patterns = HashSet::default();
let query = Query::new(grammar, source, |pattern, predicate| match predicate {
UserPredicate::SetProperty {
key: "rainbow.include-children",
val,
} => {
if val.is_some() {
return Err(
"property 'rainbow.include-children' does not take an argument".into(),
);
}
include_children_patterns.insert(pattern);
Ok(())
}
_ => Err(InvalidPredicateError::unknown(predicate)),
})?;
Ok(Self {
include_children_patterns,
scope_capture: query.get_capture("rainbow.scope"),
bracket_capture: query.get_capture("rainbow.bracket"),
query,
})
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use once_cell::sync::Lazy; use once_cell::sync::Lazy;

View File

@ -98,6 +98,8 @@ pub struct LanguageConfiguration {
pub workspace_lsp_roots: Option<Vec<PathBuf>>, pub workspace_lsp_roots: Option<Vec<PathBuf>>,
#[serde(default)] #[serde(default)]
pub persistent_diagnostic_sources: Vec<String>, pub persistent_diagnostic_sources: Vec<String>,
/// Overrides the `editor.rainbow-brackets` config key for the language.
pub rainbow_brackets: Option<bool>,
} }
impl LanguageConfiguration { impl LanguageConfiguration {

View File

@ -127,6 +127,18 @@ impl EditorView {
&text_annotations, &text_annotations,
)); ));
if doc
.language_config()
.and_then(|config| config.rainbow_brackets)
.unwrap_or(config.rainbow_brackets)
{
if let Some(overlay) =
Self::doc_rainbow_highlights(doc, view_offset.anchor, inner.height, theme, &loader)
{
overlays.push(overlay);
}
}
Self::doc_diagnostics_highlights_into(doc, theme, &mut overlays); Self::doc_diagnostics_highlights_into(doc, theme, &mut overlays);
if is_focused { if is_focused {
@ -304,6 +316,27 @@ impl EditorView {
text_annotations.collect_overlay_highlights(range) text_annotations.collect_overlay_highlights(range)
} }
pub fn doc_rainbow_highlights(
doc: &Document,
anchor: usize,
height: u16,
theme: &Theme,
loader: &syntax::Loader,
) -> Option<OverlayHighlights> {
let syntax = doc.syntax()?;
let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars()));
let visible_range = Self::viewport_byte_range(text, row, height);
let start = syntax::child_for_byte_range(
&syntax.tree().root_node(),
visible_range.start as u32..visible_range.end as u32,
)
.map_or(visible_range.start as u32, |node| node.start_byte());
let range = start..visible_range.end as u32;
Some(syntax.rainbow_highlights(text, theme.rainbow_length(), loader, range))
}
/// Get highlight spans for document diagnostics /// Get highlight spans for document diagnostics
pub fn doc_diagnostics_highlights_into( pub fn doc_diagnostics_highlights_into(
doc: &Document, doc: &Document,

View File

@ -373,6 +373,8 @@ pub struct Config {
/// Whether to read settings from [EditorConfig](https://editorconfig.org) files. Defaults to /// Whether to read settings from [EditorConfig](https://editorconfig.org) files. Defaults to
/// `true`. /// `true`.
pub editor_config: bool, pub editor_config: bool,
/// Whether to render rainbow colors for matching brackets. Defaults to `false`.
pub rainbow_brackets: bool,
} }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)]
@ -1024,6 +1026,7 @@ impl Default for Config {
end_of_line_diagnostics: DiagnosticFilter::Disable, end_of_line_diagnostics: DiagnosticFilter::Disable,
clipboard_provider: ClipboardProvider::default(), clipboard_provider: ClipboardProvider::default(),
editor_config: true, editor_config: true,
rainbow_brackets: false,
} }
} }
} }

View File

@ -227,6 +227,7 @@ pub struct Theme {
// tree-sitter highlight styles are stored in a Vec to optimize lookups // tree-sitter highlight styles are stored in a Vec to optimize lookups
scopes: Vec<String>, scopes: Vec<String>,
highlights: Vec<Style>, highlights: Vec<Style>,
rainbow_length: usize,
} }
impl From<Value> for Theme { impl From<Value> for Theme {
@ -253,12 +254,20 @@ impl<'de> Deserialize<'de> for Theme {
} }
} }
#[allow(clippy::type_complexity)]
fn build_theme_values( fn build_theme_values(
mut values: Map<String, Value>, mut values: Map<String, Value>,
) -> (HashMap<String, Style>, Vec<String>, Vec<Style>, Vec<String>) { ) -> (
HashMap<String, Style>,
Vec<String>,
Vec<Style>,
usize,
Vec<String>,
) {
let mut styles = HashMap::new(); let mut styles = HashMap::new();
let mut scopes = Vec::new(); let mut scopes = Vec::new();
let mut highlights = Vec::new(); let mut highlights = Vec::new();
let mut rainbow_length = 0;
let mut warnings = Vec::new(); let mut warnings = Vec::new();
@ -277,6 +286,27 @@ fn build_theme_values(
styles.reserve(values.len()); styles.reserve(values.len());
scopes.reserve(values.len()); scopes.reserve(values.len());
highlights.reserve(values.len()); highlights.reserve(values.len());
for (i, style) in values
.remove("rainbow")
.and_then(|value| match palette.parse_style_array(value) {
Ok(styles) => Some(styles),
Err(err) => {
warnings.push(err);
None
}
})
.unwrap_or_else(default_rainbow)
.into_iter()
.enumerate()
{
let name = format!("rainbow.{i}");
styles.insert(name.clone(), style);
scopes.push(name);
highlights.push(style);
rainbow_length += 1;
}
for (name, style_value) in values { for (name, style_value) in values {
let mut style = Style::default(); let mut style = Style::default();
if let Err(err) = palette.parse_style(&mut style, style_value) { if let Err(err) = palette.parse_style(&mut style, style_value) {
@ -289,9 +319,19 @@ fn build_theme_values(
highlights.push(style); highlights.push(style);
} }
(styles, scopes, highlights, warnings) (styles, scopes, highlights, rainbow_length, warnings)
} }
fn default_rainbow() -> Vec<Style> {
vec![
Style::default().fg(Color::Red),
Style::default().fg(Color::Yellow),
Style::default().fg(Color::Green),
Style::default().fg(Color::Blue),
Style::default().fg(Color::Cyan),
Style::default().fg(Color::Magenta),
]
}
impl Theme { impl Theme {
/// To allow `Highlight` to represent arbitrary RGB colors without turning it into an enum, /// To allow `Highlight` to represent arbitrary RGB colors without turning it into an enum,
/// we interpret the last 256^3 numbers as RGB. /// we interpret the last 256^3 numbers as RGB.
@ -382,6 +422,10 @@ impl Theme {
}) })
} }
pub fn rainbow_length(&self) -> usize {
self.rainbow_length
}
fn from_toml(value: Value) -> (Self, Vec<String>) { fn from_toml(value: Value) -> (Self, Vec<String>) {
if let Value::Table(table) = value { if let Value::Table(table) = value {
Theme::from_keys(table) Theme::from_keys(table)
@ -392,12 +436,14 @@ impl Theme {
} }
fn from_keys(toml_keys: Map<String, Value>) -> (Self, Vec<String>) { fn from_keys(toml_keys: Map<String, Value>) -> (Self, Vec<String>) {
let (styles, scopes, highlights, load_errors) = build_theme_values(toml_keys); let (styles, scopes, highlights, rainbow_length, load_errors) =
build_theme_values(toml_keys);
let theme = Self { let theme = Self {
styles, styles,
scopes, scopes,
highlights, highlights,
rainbow_length,
..Default::default() ..Default::default()
}; };
(theme, load_errors) (theme, load_errors)
@ -541,6 +587,21 @@ impl ThemePalette {
} }
Ok(()) Ok(())
} }
fn parse_style_array(&self, value: Value) -> Result<Vec<Style>, String> {
let mut styles = Vec::new();
for v in value
.as_array()
.ok_or_else(|| format!("Could not parse value as an array: '{value}'"))?
{
let mut style = Style::default();
self.parse_style(&mut style, v.clone())?;
styles.push(style);
}
Ok(styles)
}
} }
impl TryFrom<Value> for ThemePalette { impl TryFrom<Value> for ThemePalette {

View File

@ -0,0 +1,20 @@
[
(function_definition)
(compound_statement)
(subshell)
(test_command)
(subscript)
(parenthesized_expression)
(array)
(expansion)
(command_substitution)
] @rainbow.scope
[
"(" ")"
"((" "))"
"${" "$("
"{" "}"
"[" "]"
"[[" "]]"
] @rainbow.bracket

View File

@ -0,0 +1,29 @@
[
(preproc_params)
(preproc_defined)
(argument_list)
(attribute_specifier)
(ms_declspec_modifier)
(declaration_list)
(parenthesized_declarator)
(parenthesized_expression)
(abstract_parenthesized_declarator)
(array_declarator)
(compound_statement)
(initializer_list)
(compound_literal_expression)
(enumerator_list)
(field_declaration_list)
(parameter_list)
(for_statement)
(macro_type_specifier)
(subscript_expression)
(subscript_designator)
(cast_expression)
] @rainbow.scope
[
"(" ")"
"{" "}"
"[" "]"
] @rainbow.bracket

View File

@ -0,0 +1,13 @@
[
(list_lit)
(map_lit)
(vec_lit)
(anon_fn_lit)
] @rainbow.scope
[
"(" ")"
"#"
"{" "}"
"[" "]"
] @rainbow.bracket

View File

@ -0,0 +1 @@
; inherits: scheme

View File

@ -0,0 +1,49 @@
[
; c
(preproc_params)
(preproc_defined)
(argument_list)
(attribute_specifier)
(ms_declspec_modifier)
(declaration_list)
(parenthesized_declarator)
(parenthesized_expression)
(abstract_parenthesized_declarator)
(array_declarator)
(compound_statement)
(initializer_list)
(compound_literal_expression)
(enumerator_list)
(field_declaration_list)
(parameter_list)
(for_statement)
; (macro_type_specifier) - not part of cpp
(subscript_expression)
(subscript_designator)
(cast_expression)
; cpp
(decltype)
(explicit_function_specifier)
(template_parameter_list)
(template_argument_list)
(parameter_list)
(argument_list)
(structured_binding_declarator)
(noexcept)
(throw_specifier)
(static_assert_declaration)
(condition_clause)
(for_range_loop)
(new_declarator)
(delete_expression "[" "]")
(lambda_capture_specifier)
(sizeof_expression)
] @rainbow.scope
[
"(" ")"
"{" "}"
"[" "]"
"<" ">"
] @rainbow.bracket

View File

@ -0,0 +1,15 @@
[
(keyframe_block_list)
(block)
(attribute_selector)
(feature_query)
(parenthesized_query)
(selector_query)
(parenthesized_value)
(arguments)
] @rainbow.scope
[
"{" "}"
"(" ")"
] @rainbow.bracket

View File

@ -0,0 +1,28 @@
[
(export_clause)
(named_imports)
(statement_block)
(for_statement)
(for_in_statement)
(switch_body)
(catch_clause "(" ")")
(parenthesized_expression)
(object)
(object_pattern)
(array)
(array_pattern)
(subscript_expression)
(template_substitution)
(arguments)
(class_body)
(formal_parameters)
(computed_property_name)
] @rainbow.scope
[
"(" ")"
"${" "{" "}"
"[" "]"
] @rainbow.bracket
(regex "/" @rainbow.bracket) @rainbow.scope

View File

@ -0,0 +1,24 @@
[
(block)
(interpolation)
(list)
(tuple)
(bitstring)
(map)
; short-hand function captures like &(&1 + &2)
(unary_operator
operator: "&")
(arguments "(" ")")
(access_call)
(sigil)
] @rainbow.scope
[
"(" ")"
"%"
"{" "}"
"[" "]"
"<<" ">>"
"#{"
"|"
] @rainbow.bracket

View File

@ -0,0 +1,24 @@
[
; ()
(arguments "(" ")")
(parenthesized_expression)
(function_type)
; #{}
(record)
(map)
; {}
(map_update)
(tuple)
; <<>>
(bitstring)
; []
(list)
] @rainbow.scope
[
"#"
"{" "}"
"(" ")"
"[" "]"
"<<" ">>"
] @rainbow.bracket

View File

@ -0,0 +1,32 @@
[
(target_group)
(unqualified_imports)
(tuple)
(list)
(function)
(function_parameters)
(todo)
(tuple)
(list)
(anonymous_function)
(block)
(case)
(record_update)
(arguments)
(record_pattern_arguments)
(tuple_pattern)
(list_pattern)
(type_definition)
(data_constructor_arguments)
(tuple_type)
(function_parameter_types)
(type_arguments)
(type_parameters)
] @rainbow.scope
[
"(" ")"
"[" "]"
"{" "}"
"#"
] @rainbow.bracket

View File

@ -0,0 +1,33 @@
[
(import_spec_list)
(const_declaration)
(var_declaration)
(type_parameter_list)
(parameter_list)
(type_declaration)
(parenthesized_type)
(type_arguments)
(array_type)
(implicit_length_array_type)
(slice_type)
(field_declaration_list)
(interface_type)
(map_type)
(block)
(expression_switch_statement)
(type_switch_statement)
(select_statement)
(parenthesized_expression)
(argument_list)
(index_expression)
(slice_expression)
(type_assertion_expression)
(type_conversion_expression)
(literal_value)
] @rainbow.scope
[
"(" ")"
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -0,0 +1,13 @@
[
(doctype)
(erroneous_end_tag)
] @rainbow.scope
([
(element)
(script_element)
(style_element)
] @rainbow.scope
(#set! rainbow.include-children))
["<" ">" "<!" "</" "/>"] @rainbow.bracket

View File

@ -0,0 +1,35 @@
[
(cast_expression)
(inferred_parameters)
(dimensions_expr)
(parenthesized_expression)
(array_access)
(argument_list)
(type_arguments)
(dimensions)
(block)
(switch_block)
(catch_clause)
(resource_specification)
(for_statement)
(enhanced_for_statement)
(annotation_argument_list)
(element_value_array_initializer)
(module_body)
(enum_body)
(type_parameters)
(class_body)
(constructor_body)
(annotation_type_body)
(annotation_type_element_declaration)
(interface_body)
(array_initializer)
(formal_parameters)
] @rainbow.scope
[
"(" ")"
"{" "}"
"[" "]"
"<" ">"
] @rainbow.bracket

View File

@ -0,0 +1 @@
; inherits: ecma

View File

@ -0,0 +1,9 @@
[
(object)
(array)
] @rainbow.scope
[
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -0,0 +1,9 @@
; inherits: ecma
[
(jsx_expression)
] @rainbow.scope
(jsx_opening_element ["<" ">"] @rainbow.bracket) @rainbow.scope
(jsx_closing_element ["</" ">"] @rainbow.bracket) @rainbow.scope
(jsx_self_closing_element ["<" "/>"] @rainbow.bracket) @rainbow.scope

View File

@ -0,0 +1,17 @@
[
(formals)
(parenthesized_expression)
(attrset_expression)
(let_attrset_expression)
(rec_attrset_expression)
(inherit_from)
(interpolation)
(list_expression)
] @rainbow.scope
[
"${"
"{" "}"
"(" ")"
"[" "]"
] @rainbow.bracket

View File

@ -0,0 +1,30 @@
[
(future_import_statement)
(import_from_statement)
(with_clause)
(parameters)
(parenthesized_list_splat)
(argument_list)
(tuple_pattern)
(list_pattern)
(subscript)
(list)
(set)
(tuple)
(dictionary)
(dictionary_comprehension)
(set_comprehension)
(list_comprehension)
(generator_expression)
(parenthesized_expression)
(interpolation)
(format_expression)
] @rainbow.scope
[
"(" ")"
"{" "}"
"[" "]"
] @rainbow.bracket
; (string ["{{" "}}"] @rainbow.bracket) @rainbow.scope

View File

@ -0,0 +1 @@
; inherits: scheme

View File

@ -0,0 +1,17 @@
[
(lookahead_assertion)
(character_class)
(anonymous_capturing_group)
(named_capturing_group)
(non_capturing_group)
(count_quantifier)
(character_class_escape)
] @rainbow.scope
[
"(?" "(?:"
"(?<" ">"
"(" ")"
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -0,0 +1,28 @@
[
(begin_block)
(end_block)
(singleton_method)
(block_parameters)
(parenthesized_statements)
(element_reference)
(argument_list "(" ")")
(block)
(destructured_left_assignment)
(interpolation)
(string_array)
(symbol_array)
(regex)
(array)
(hash)
(method_parameters)
] @rainbow.scope
[
"#{"
"{" "}"
"(" ")"
"%w(" "%i("
"[" "]"
"|"
"/"
] @rainbow.bracket

View File

@ -0,0 +1,60 @@
[
; {/}
(declaration_list)
(field_declaration_list)
(field_initializer_list)
(enum_variant_list)
(block)
(match_block)
(use_list)
(struct_pattern)
; (/)
(ordered_field_declaration_list)
(arguments)
(parameters)
(tuple_type)
(tuple_expression)
(tuple_pattern)
(tuple_struct_pattern)
(unit_type)
(unit_expression)
(visibility_modifier)
(parenthesized_expression)
(token_repetition_pattern)
; </>
(type_parameters)
(type_arguments)
(bracketed_type)
(for_lifetimes)
; [/]
(array_type)
(array_expression)
(index_expression)
(slice_pattern)
; attributes #[]
(attribute_item)
(inner_attribute_item)
; macros
(token_tree_pattern)
(macro_definition)
; closures
(closure_parameters)
] @rainbow.scope
; attributes like `#[serde(rename_all = "kebab-case")]`
(attribute arguments: (token_tree) @rainbow.scope)
[
"#"
"[" "]"
"(" ")"
"{" "}"
"<" ">"
"|"
] @rainbow.bracket

View File

@ -0,0 +1,12 @@
[
(list)
(vector)
(byte_vector)
] @rainbow.scope
[
"#(" "#vu8("
"(" ")"
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -0,0 +1,3 @@
; inherits: css
(parameters) @rainbow.scope

View File

@ -0,0 +1 @@
; inherits: python

View File

@ -0,0 +1,12 @@
[
(table_array_element)
(table)
(array)
(inline_table)
] @rainbow.scope
[
"[[" "]]"
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -0,0 +1,2 @@
; inherits: typescript
; inherits: jsx

View File

@ -0,0 +1,19 @@
; inherits: ecma
[
(import_require_clause)
(enum_body)
(lookup_type)
(parenthesized_type)
(object_type)
(type_parameters)
(index_signature)
(array_type)
(tuple_type)
] @rainbow.scope
(type_arguments ["<" ">"] @rainbow.bracket) @rainbow.scope
[
"{|" "|}"
] @rainbow.bracket

View File

@ -0,0 +1,29 @@
[
(processing_instructions)
(cdata_sect)
(xml_decl)
(doctype_decl)
(element_decl)
(element_choice)
(element_seq)
(mixed)
(attlist_decl)
(notation_type)
(enumeration)
(ge_decl)
(pe_decl)
(notation_decl)
] @rainbow.scope
((element) @rainbow.scope
(#set! rainbow.include-children))
[
"<?" "?>"
"<" ">"
"</" "/>"
"<!"
"(" ")"
")*"
"[" "]"
] @rainbow.bracket

View File

@ -0,0 +1,9 @@
[
(flow_sequence)
(flow_mapping)
] @rainbow.scope
[
"[" "]"
"{" "}"
] @rainbow.bracket

View File

@ -36,6 +36,7 @@ pub mod tasks {
let grammar = syntax_config.grammar; let grammar = syntax_config.grammar;
LanguageData::compile_indent_query(grammar, config)?; LanguageData::compile_indent_query(grammar, config)?;
LanguageData::compile_textobject_query(grammar, config)?; LanguageData::compile_textobject_query(grammar, config)?;
LanguageData::compile_rainbow_query(grammar, config)?;
} }
println!("Query check succeeded"); println!("Query check succeeded");