This document covers the three tree-sitter query files that drive syntax highlighting and language injection for Weaveback source files.
See grammar.adoc for the grammar that these queries operate on, and editors.adoc for how they are installed into Helix and Neovim.
Syntax highlighting (highlights.scm)
The highlight query maps grammar nodes to standard tree-sitter capture names that editors translate into colours.
Builtin macro names
Builtin macros are distinguished from user-defined macros by matching
macro_name against a regex of known names. They receive the @keyword
capture so editors can highlight them with the keyword colour.
The full list of builtins matched here corresponds to the builtins
implemented in weaveback-macro:
| Builtin | Purpose |
|---|---|
|
Define a macro (plain, Rhai, Python) |
|
Set a variable |
|
Conditional |
|
File inclusion |
|
Inline expression evaluation |
|
Current file path |
|
Promote to parent scope |
|
Read environment variable (opt-in) |
|
Python variable bridge |
|
Rhai variable bridge |
|
String case-conversion helpers |
Priority: builtins before user macros
Tree-sitter applies highlight captures in query order. The builtin-keyword
query comes first; the user-macro query (@function.macro) follows. Because
the builtin query has a #match? predicate, an unknown name that does not
match the regex falls through to @function.macro.
Variable, block, comment, and escape captures
Variable interpolation splits into three sub-captures so editors can
colour the %( and ) delimiters distinctly from the name.
// <<ts-highlights-all>>=
; tree-sitter-weaveback/queries/highlights.scm
; --- Keywords (builtin macro names) ----------------------------------------
(macro_call
name: (macro_name) @keyword
(#match? @keyword
"^%(def|rhaidef|pydef|set|if|equal|include|import|eval|here|export|env|pyset|pyget|rhaiset|rhaiget|rhaiexpr|capitalize|decapitalize|convert_case|to_snake_case|to_camel_case|to_pascal_case|to_screaming_case)$"))
; --- User-defined macro calls -----------------------------------------------
(macro_call
name: (macro_name) @function.macro)
; --- Variable interpolation -------------------------------------------------
(variable
"%(" @punctuation.special
name: (identifier) @variable
")" @punctuation.special)
; --- Block delimiters -------------------------------------------------------
(block_open) @punctuation.bracket
(block_close) @punctuation.bracket
; --- Comments ---------------------------------------------------------------
(line_comment) @comment
(block_comment) @comment
; --- Escaped special --------------------------------------------------------
(escaped_special) @string.escape
// @
Assembly
// <<@file queries/highlights.scm>>=
// <<ts-highlights-all>>
// @
Language injection (injections.scm)
Language injection lets editors apply a second grammar inside a node from
the primary grammar. The injection query captures the block argument of
%rhaidef and %pydef calls and tells the editor to apply the rhai or
python grammar to its text content.
The body is the last argument of %rhaidef / %pydef — in practice
always a %{…%} block. The %{ and %} delimiters will appear as
noise inside the sub-parser, which is acceptable: editors render the
block body with Rhai or Python highlighting regardless.
|
Note
|
Both Rhai and monty (the Python back-end) are sandboxed runtimes with no filesystem or network access. Language injection here is purely for visual benefit; it does not affect execution. |
// <<ts-injections-all>>=
; tree-sitter-weaveback/queries/injections.scm
;
; Inject host-language grammars into scripted macro bodies.
; The body is the last argument of %rhaidef / %pydef — in practice
; always wrapped in a %{...%} block. We capture the block node so
; editors render its text content with the appropriate sub-grammar.
; The %{ and %} delimiters will appear as noise in the sub-parser,
; which is acceptable.
; Rhai inside %rhaidef bodies
((macro_call
name: (macro_name) @_name
arg: (argument
(block) @injection.content))
(#eq? @_name "%rhaidef")
(#set! injection.language "rhai"))
; Python inside %pydef bodies
((macro_call
name: (macro_name) @_name
arg: (argument
(block) @injection.content))
(#eq? @_name "%pydef")
(#set! injection.language "python"))
// @
Assembly
// <<@file queries/injections.scm>>=
// <<ts-injections-all>>
// @
AsciiDoc injection fragment (editors/helix/asciidoc-injections.scm)
This fragment is appended by the install scripts to the AsciiDoc query
file of Helix and Neovim. It injects the weaveback grammar into
[source,weaveback] listing blocks in AsciiDoc documents, so that
weaveback macro syntax inside literate code examples is highlighted.
The query matches a section_block node containing an element_attr
whose second attribute value matches weaveback, with an adjacent
listing_block. The listing_block_body is captured as
@injection.content and the injected language is set to weaveback.
// <<ts-asciidoc-inj-all>>=
; tree-sitter-weaveback: asciidoc injection
;
; install.py appends this block to ~/.config/helix/runtime/queries/asciidoc/injections.scm
; ── [source,weaveback] listing blocks ─────────────────────────────────────────────
((section_block
(element_attr
(element_attr_marker)
(attr_value) @_lang
(element_attr_marker))
(listing_block
(listing_block_start_marker)
(listing_block_body) @injection.content
(listing_block_end_marker)))
(#match? @_lang "weaveback")
(#set! injection.language "weaveback"))
// @
Assembly
// <<@file editors/helix/asciidoc-injections.scm>>=
// <<ts-asciidoc-inj-all>>
// @