Workspace for syntax coloring with a clean split between:
- syntax analysis (
highlight-spans) - style selection (
theme-engine) - output adapters (
render-ansi,theme-engine-ffi,tsbundler)
This lets one parser/theme pipeline support multiple outputs:
- ANSI/VT terminal rendering
- native C paint engines
- future GUI/web adapters
This project turns source code into style-ready data in two stages:
- Parse and classify code tokens into semantic capture names (
keyword,comment,number, etc.). - Map those names to concrete visual styles (RGB + bold/italic/underline).
The key benefit is decoupling parser logic from theme logic, so each can evolve independently.
crates/
highlight-spans/ # Tree-sitter -> spans + attr table
theme-engine/ # capture name -> style resolution + built-in theme loader
themes/ # embedded JSON theme assets
render-ansi/ # styled ranges -> ANSI/VT escape output
theme-engine-ffi/ # C ABI wrapper around theme-engine, highlight-spans, and render-ansi
tsbundler/ # zedit-oriented C API, built as the `irisutils` shared library
include/
zedit_ts.h # C header for the tsbundler (`irisutils`) API
tsbundler/ # prebuilt `irisutils` binaries per platform (see rebuild-release.sh)
examples/ # sample source inputs used during highlighting work
rebuild-release.sh # cross-compiles release builds and refreshes tsbundler/ binaries
Purpose:
- Convert source text into
(attr_id, start_byte, end_byte)spans. Supported grammars: ObjectScript (playground, routine, UDL), SQL, Python, Markdown, MDX, XML, JSON, YAML, CSS, HTML, JavaScript, JSDoc, Regex, TOML, Diff, and Rust. - Return an attribute table mapping
attr_id -> capture_name. - Treat
mdxas a temporary alias to SQL highlighting (for InterSystems MDX content). - Highlight XML host documents with ObjectScript injection inside
<Implementation>content. - Apply each grammar's injection query (embedded SQL/HTML/JavaScript in ObjectScript,
<script>/<style>in HTML, fenced code and inline Markdown, JSDoc and regex in JavaScript, Rust in Rust macro bodies), nested up to three levels deep. - Highlight unified diffs, injecting the file's own grammar (derived from the
---/+++filename extension) into hunk lines while keeping the diff's added/removed background. - Crate README
Depends on:
tree-sitter-objectscript-playground = "1.11.0"tree-sitter-objectscript-routine = "1.11.0"tree-sitter-objectscript = "1.11.0"(UDL)tree-sitter-python = "0.25.0"tree-sitter-md = "0.5.3"tree-sitter-json = "0.24.8"tree-sitter-yaml = "0.7.2"tree-sitter-xml = "0.7.0"tree-sitter-css = "0.25.0",tree-sitter-html = "0.23.2",tree-sitter-javascript = "0.25.0",tree-sitter-jsdoc = "0.25.0"tree-sitter-regex = "0.25.0",tree-sitter-toml-ng = "0.7.0"tree-sitter-rust = "0.24.2"tree-sitter-diff(git,tree-sitter-grammars/tree-sitter-difftagv0.2.0)tree-sitter-highlight = "0.27.0"tree-sitter = "0.27.0"- bundled SQL grammar from
DerekStride/tree-sitter-sql(vendor/tree-sitter-sql/src/*,vendor/tree-sitter-sql/queries/highlights.scm)
Purpose:
- Resolve capture names to concrete styles:
fg/bgRGBbold,italic,underline
- Resolve UI-role styles (
statusline,tab_active,selection, etc.). - Provide theme default terminal fg/bg for OSC 10/11 integration.
- Normalize capture keys (
@commentandcommentboth resolve). - Support fallback (
comment.documentation -> comment -> normal). - Include built-in themes:
- Tokyo Night:
tokyonight-night,tokyonight-storm,tokyonight-moon,tokyonight-day,tokyonight-dark,tokyonight-light - Catppuccin:
catppuccin-latte,catppuccin-frappe,catppuccin-macchiato,catppuccin-mocha - Studio:
studio-default,aviel - Solarized:
solarized-dark,solarized-light
- Tokyo Night:
- Crate README
Purpose:
- Convert highlighted byte spans into ANSI/VT escaped text.
- Provide line-oriented APIs (
Vec<String>) for terminal rendering. - Provide incremental VT patching with configurable terminal origin offsets (
row,col). - Provide bridge-friendly auto mode selection (
vt_patch_bridge) when origin is omitted. - Compute incremental patch columns using grapheme/display-width logic (wide Unicode and tabs).
- Provide OSC helpers for terminal default fg/bg updates from theme values.
- Keep renderer logic separate from parsing and theme selection.
- Crate README
Purpose:
- Expose the full syntax-color pipeline to C hosts via a stable FFI layer.
- Load themes, run highlighting, and render ANSI/VT output from C.
- Provide reusable incremental and single-line patch renderers for terminal UIs.
- Preserve the existing theme-only entry points for style lookup and terminal default colors.
- Crate README
Purpose:
- Provide the C API used by the zedit editor (header:
include/zedit_ts.h). - Build as a shared library named
irisutils(libirisutils.so,libirisutils.dylib,irisutils.dll). - Enumerate bundled languages/themes, activate a theme as a dense table of
zedit_attr_telements, and fill per-character attribute buffers for full parses and incremental edits. - Crate README
source code
-> highlight-spans
-> attrs: [{id, capture_name}]
-> spans: [{attr_id, start_byte, end_byte, background_attr_id}]
-> theme-engine
-> style per capture_name
-> renderer (ANSI or C painter)
use highlight_spans::highlight_structures::{Grammar, SpanHighlighter};
use theme_engine::theme_structures::Theme;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut highlighter = SpanHighlighter::new()?;
let result = highlighter.highlight(b"set x = 42", Grammar::ObjectScript)?;
let theme = Theme::from_json_str(r#"{
"styles": {
"normal": { "fg": { "r": 220, "g": 220, "b": 220 } },
"number": { "fg": { "r": 255, "g": 180, "b": 120 } }
}
}"#)?;
for span in &result.spans {
let capture = &result.attrs[span.attr_id].capture_name;
let style = theme.resolve(capture);
// A renderer applies `style` to source[span.start_byte..span.end_byte].
println!("{capture}: {style:?}");
}
Ok(())
}The crates don't re-export their types at the root; import them from their modules
(highlight_spans::highlight_structures, theme_engine::theme_structures, theme_engine::common,
render_ansi::common, render_ansi::ansi_structures).
Primary documentation currently lives in the crate READMEs:
cargo testPrebuilt irisutils libraries are committed under tsbundler/ for:
macos/arm64,macos/x86linux/arm64,linux/x86windows(x86_64irisutils.dll+irisutils.dll.lib)
To regenerate them, run ./rebuild-release.sh. It requires
cargo-zigbuild for the Linux targets,
cargo-xwin for the Windows targets, and the
matching Rust targets installed via rustup target add. The script assumes it runs on an
Apple Silicon Mac (the host cargo build --release output is copied to macos/arm64).
MIT — see LICENSE.