Adding Rainbow Bracket Queries
-Helix uses rainbows.scm
tree-sitter query files to provide rainbow bracket
-functionality.
Tree-sitter queries are documented in the tree-sitter online documentation. -If you're writing queries for the first time, be sure to check out the section -on syntax highlighting queries and on query syntax.
-Rainbow queries have two captures: @rainbow.scope
and @rainbow.bracket
.
-@rainbow.scope
should capture any node that increases the nesting level
-while @rainbow.bracket
should capture any bracket nodes. Put another way:
-@rainbow.scope
switches to the next rainbow color for all nodes in the tree
-under it while @rainbow.bracket
paints captured nodes with the current
-rainbow color.
For an example, let's add rainbow queries for the tree-sitter query (TSQ)
-language itself. These queries will go into a
-runtime/queries/tsq/rainbows.scm
file in the repository root.
First we'll add the @rainbow.bracket
captures. TSQ only has parentheses and
-square brackets:
["(" ")" "[" "]"] @rainbow.bracket
-
-The ordering of the nodes within the alternation (square brackets) is not -taken into consideration.
---Note: Why are these nodes quoted? Most syntax highlights capture text -surrounded by parentheses. These are named nodes and correspond to the -names of rules in the grammar. Brackets are usually written in tree-sitter -grammars as literal strings, for example:
--{ - // ... - arguments: seq("(", repeat($.argument), ")"), - // ... -} -
Nodes written as literal strings in tree-sitter grammars may be captured -in queries with those same literal strings.
-
Then we'll add @rainbow.scope
captures. The easiest way to do this is to
-view the grammar.js
file in the tree-sitter grammar's repository. For TSQ,
-that file is here. As we scroll down the grammar.js
, we
-see that the (alternation)
, (L36) (group)
(L57), (named_node)
(L59),
-(predicate)
(L87) and (wildcard_node)
(L97) nodes all contain literal
-parentheses or square brackets in their definitions. These nodes are all
-direct parents of brackets and happen to also be the nodes we want to change
-to the next rainbow color, so we capture them as @rainbow.scope
.
[
- (group)
- (named_node)
- (wildcard_node)
- (predicate)
- (alternation)
-] @rainbow.scope
-
-This strategy works as a rule of thumb for most programming and configuration -languages. Markup languages can be trickier and may take additional -experimentation to find the correct nodes to use for scopes and brackets.
-The :tree-sitter-subtree
command shows the syntax tree under the primary
-selection in S-expression format and can be a useful tool for determining how
-to write a query.
Properties
-The rainbow.include-children
property may be applied to @rainbow.scope
-captures. By default, all @rainbow.bracket
captures must be direct descendant
-of a node captured with @rainbow.scope
in a syntax tree in order to be
-highlighted. The rainbow.include-children
property disables that check and
-allows @rainbow.bracket
captures to be highlighted if they are direct or
-indirect descendants of some node captured with @rainbow.scope
.
For example, this property is used in the HTML rainbow queries.
-For a document like <a>link</a>
, the syntax tree is:
(element ; <a>link</a>
- (start_tag ; <a>
- (tag_name)) ; a
- (text) ; link
- (end_tag ; </a>
- (tag_name))) ; a
-
-If we want to highlight the <
, >
and </
nodes with rainbow colors, we
-capture them as @rainbow.bracket
:
["<" ">" "</"] @rainbow.bracket
-
-And we capture (element)
as @rainbow.scope
because (element)
nodes nest
-within each other: they increment the nesting level and switch to the next
-color in the rainbow.
(element) @rainbow.scope
-
-But this combination of @rainbow.scope
and @rainbow.bracket
will not
-highlight any nodes. <
, >
and </
are children of the (start_tag)
and
-(end_tag)
nodes. We can't capture (start_tag)
and (end_tag)
as
-@rainbow.scope
because they don't nest other elements. We can fix this case
-by removing the requirement that <
, >
and </
are direct descendants of
-(element)
using the rainbow.include-children
property.
((element) @rainbow.scope
- (#set! rainbow.include-children))
-
-With this property set, <
, >
, and </
will highlight with rainbow colors
-even though they aren't direct descendents of the (element)
node.
rainbow.include-children
is not necessary for the vast majority of programming
-languages. It is only necessary when the node that increments the nesting level
-(changes rainbow color) is not the direct parent of the bracket node.