Tree-sitter syntax highlighting for TUI code fences.
The eval / code fences the model emits are colored by parsing them with the
bundled tree-sitter grammars — the SAME com.blockether/tree-sitter-language-pack
the structural editors use — and painting each node by the grammar's OWN
highlights.scm capture scheme. That makes the classification accurate (a ;
inside a string is not a comment, a number inside a symbol is not a number)
and GENERAL: Clojure, Python, JavaScript, JSON, … every fence we render is
colored off each grammar's canonical highlight rules.
The heavy lifting — parse, a real tree-sitter query interpreter (field-scoped
captures, alternations, #match?/#eq? predicates), per-byte capture
labeling, ANSI run coalescing — lives in the pack's JVM-native Highlighter
(Java, on the hot path), NOT in Clojure. This namespace is a thin edge: it
maps a fence :lang to a grammar, hands the pack our capture→SGR theme, and
caches the result. The SGR codes we pick are the ones render/ansi-code->fg
already maps to theme fg slots (string/number/keyword/special/comment plus
function→warning-fg and type→success-fg), so no painter change is needed
and the escapes stay zero-width (column alignment on verbatim fences is
untouched).
Fail-open: if the native pack isn't loadable (e.g. a bare unit-test JVM without the platform lib on the classpath) every entry point returns nil and the caller falls back to plain, uncolored text.
Tree-sitter syntax highlighting for TUI code fences. The eval / code fences the model emits are colored by *parsing* them with the bundled tree-sitter grammars — the SAME `com.blockether/tree-sitter-language-pack` the structural editors use — and painting each node by the grammar's OWN `highlights.scm` capture scheme. That makes the classification accurate (a `;` inside a string is not a comment, a number inside a symbol is not a number) and GENERAL: Clojure, Python, JavaScript, JSON, … every fence we render is colored off each grammar's canonical highlight rules. The heavy lifting — parse, a real tree-sitter query interpreter (field-scoped captures, alternations, `#match?`/`#eq?` predicates), per-byte capture labeling, ANSI run coalescing — lives in the pack's JVM-native `Highlighter` (Java, on the hot path), NOT in Clojure. This namespace is a thin edge: it maps a fence `:lang` to a grammar, hands the pack our capture→SGR theme, and caches the result. The SGR codes we pick are the ones `render/ansi-code->fg` already maps to theme fg slots (string/number/keyword/special/comment plus function→warning-fg and type→success-fg), so no painter change is needed and the escapes stay zero-width (column alignment on verbatim fences is untouched). Fail-open: if the native pack isn't loadable (e.g. a bare unit-test JVM without the platform lib on the classpath) every entry point returns nil and the caller falls back to plain, uncolored text.
Bound true by the renderer while laying out a LIVE / streaming bubble. When set
(and the kill switch below is on) highlight takes the incremental streaming
path — a memoized settled prefix + a standalone last line — instead of
re-parsing the whole growing fence every tick. Finalized bubbles render with
this false, so their colouring is byte-identical to a full parse.
Bound true by the renderer while laying out a LIVE / streaming bubble. When set (and the kill switch below is on) `highlight` takes the incremental streaming path — a memoized settled prefix + a standalone last line — instead of re-parsing the whole growing fence every tick. Finalized bubbles render with this false, so their colouring is byte-identical to a full parse.
(grammar-for lang)Tree-sitter grammar name for a fence lang, or nil if we don't colorize it.
Tree-sitter grammar name for a fence `lang`, or nil if we don't colorize it.
(highlight grammar source)ANSI-colorize source as tree-sitter grammar, returning the colored string
(same newline structure as the input, ready to str/split-lines), or nil
when the grammar is unknown / the native lib is unavailable / parsing fails.
Callers treat nil as "render plain".
While a bubble streams (*live?* bound true) the growing fence is colorized
incrementally — the settled prefix is memoized and only the last, still-typed
line is re-parsed per tick — instead of re-parsing the whole growing fence every
tick. Finalized bubbles use the exact full-source path, so their colouring is
byte-identical to a full parse.
ANSI-colorize `source` as tree-sitter `grammar`, returning the colored string (same newline structure as the input, ready to `str/split-lines`), or nil when the grammar is unknown / the native lib is unavailable / parsing fails. Callers treat nil as "render plain". While a bubble streams (`*live?*` bound true) the growing fence is colorized incrementally — the settled prefix is memoized and only the last, still-typed line is re-parsed per tick — instead of re-parsing the whole growing fence every tick. Finalized bubbles use the exact full-source path, so their colouring is byte-identical to a full parse.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |