helix-editor/helix
Syntax highlighting
Helix uses tree-sitter for incremental parsing and a set of .scm query files for highlighting, indentation, text objects, and locals. Since 25.07 the highlighter has been the tree-house crate — a Helix-maintained tree-sitter wrapper that keeps the highlighter in lockstep with editor needs.
Pipeline
graph LR
Toml[languages.toml] --> Loader[helix_core::config<br/>default_lang_loader]
Loader --> LangData[LanguageData]
Open[Document open] --> Detect[detect_language by extension/shebang]
Detect --> LangData
LangData --> Compile[compile_syntax_config]
Compile --> Grammar[helix_loader::grammar::get_language]
Grammar --> Tree[tree-sitter parse]
Apply[Document::apply] --> Edit[InputEdit]
Edit --> Tree
Tree --> Iter[QueryIter via tree-house highlighter]
Iter --> Events[HighlightEvent stream]
Events --> Render[ui::editor render with theme]Configuration
Per-language configuration lives in languages.toml at the repo root. The schema is the Configuration struct in helix-core/src/syntax/config.rs:
[[language]]blocks: name, scope, file-types, shebangs, comment tokens, indent style, language servers, formatter, debugger, soft-wrap defaults.[[grammar]]blocks: name +source = { git = "…", rev = "…" }(orlocal) + optionalsubpath.
The default languages.toml ships ~180 languages and grammars. Bundled queries live under runtime/queries/<lang>/ — there are 331 language directories.
Query file types
Each language can ship up to six query files in runtime/queries/<lang>/:
| File | Purpose |
|---|---|
highlights.scm |
Names of nodes get translated into highlight scopes (theme keys). |
injections.scm |
Embedded languages (markdown code blocks, Rust doc comments). |
locals.scm |
Variable scoping for "local" highlights — definitions, references, scopes. |
indents.scm |
Tree-sitter-driven indentation rules. |
textobjects.scm |
Function/class/parameter/comment/test text objects. |
tags.scm |
Symbol indexing for tags (used by some pickers). |
rainbow.scm |
Rainbow brackets when editor.rainbow-brackets = true. |
cargo xtask query-check validates every file in CI.
Loader
syntax::Loader (helix-core/src/syntax.rs) is the central registry. It owns a Vec<LanguageData> plus indexes by language name, scope, file-type pattern, and shebang interpreter. Each LanguageData lazily compiles its SyntaxConfig, indent query, textobject query, tag query, and rainbow query on first use — repeat lookups hit OnceCell.
The loader is wrapped in Arc<ArcSwap<Loader>> on Editor::syn_loader so reloading via :reload-config is atomic for in-flight reads.
Highlighting
Tree-sitter parse trees are stored on Syntax (helix-core/src/syntax.rs). When a Transaction is applied, Document::apply translates the rope edit into a tree-sitter InputEdit and asks the parser to incrementally re-parse — usually in microseconds.
Rendering uses tree-house's highlighter module: it walks the tree against the language's highlights.scm query and produces a stream of HighlightEvents. The event stream is consumed in helix-term/src/ui/document.rs, which translates each highlight scope into a Style via the active Theme.
Themes
A theme is a TOML file mapping highlight scopes to styles. Loaded by helix-view/src/theme.rs:
"keyword" = { fg = "magenta" }
"keyword.control" = { fg = "magenta", modifiers = ["bold"] }
"function.method" = { fg = "blue" }Themes can inherits = "another-theme" for layered overrides. The loader walks the inheritance chain and merges. Custom themes go in ~/.config/helix/themes/. There are 200+ bundled themes in runtime/themes/, validated by cargo xtask theme-check.
Scope resolution is "longest match wins": looking up function.method.builtin falls back to function.method, then function, then the editor default. This mirrors tree-sitter's own scope model.
Injections
A markdown file with a fenced code block in Rust gets the Rust grammar injected for that range. The mapping is declared in runtime/queries/markdown/injections.scm. 25.07 added markdown injection into Rust doc comments (/// and //!), so doc-comment links and code blocks render with full markdown highlighting.
Performance notes
Syntaxholds the previous tree across edits so re-parses are O(edit size), not O(file size).- Query iteration uses
InactiveQueryCursorfromtree-house, reusing cursor allocations across runs. - Highlights for off-screen content are computed lazily as the user scrolls.
Per-language extras
- Comment tokens drive
ctrl-ctoggle commenting (helix-core/src/comment.rs). - Indent queries drive auto-indent on newline (combined with the legacy heuristic; see
helix-core/src/indent.rs). - Auto-pair table can be customized per language via
[language.auto-pairs]inlanguages.toml.
See also
- packages/helix-core —
Syntax,LanguageData, query types. - features/themes — full theme reference.
- The user-facing book/src/themes.md.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.