Open-Source Wikis

/

Helix

/

Features

/

Syntax highlighting

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 = "…" } (or local) + optional subpath.

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

  • Syntax holds the previous tree across edits so re-parses are O(edit size), not O(file size).
  • Query iteration uses InactiveQueryCursor from tree-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-c toggle 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] in languages.toml.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Syntax highlighting – Helix wiki | Factory