# Helix Admin & Architecture Guide

This guide is the comprehensive technical reference for Helix — the modal terminal text
editor written in Rust. It is written for administrators, packagers, power users, and
developers who need to understand how Helix is structured, deploy and configure it precisely,
harden it, and extend or contribute to it.

Where the **Helix User Guide** explains *how to use* the editor, this guide explains *how it
works*: the multi-crate workspace architecture, the complete configuration surface, the
runtime-file model, the workspace-trust security boundary, and the internals a contributor
needs.

- **Project:** Helix (`hx`)
- **Version:** 25.7.1
- **License:** MPL-2.0
- **Language / edition:** Rust, edition 2021
- **Minimum Supported Rust Version (MSRV):** 1.90
- **Repository:** <https://github.com/helix-editor/helix>
- **Homepage:** <https://helix-editor.com>

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture Overview](#2-architecture-overview)
3. [Crate Reference](#3-crate-reference)
4. [Core Data Model](#4-core-data-model)
5. [Rendering and UI Layer](#5-rendering-and-ui-layer)
6. [Event System and Hooks](#6-event-system-and-hooks)
7. [LSP and DAP Integration](#7-lsp-and-dap-integration)
8. [System Requirements](#8-system-requirements)
9. [Build and Installation for Operators](#9-build-and-installation-for-operators)
10. [Runtime File Resolution](#10-runtime-file-resolution)
11. [Configuration Mastery](#11-configuration-mastery)
12. [Language and Grammar Configuration](#12-language-and-grammar-configuration)
13. [Theming Reference](#13-theming-reference)
14. [Security Analysis](#14-security-analysis)
15. [Operations](#15-operations)
16. [Code Quality and Conventions](#16-code-quality-and-conventions)
17. [Testing Strategy](#17-testing-strategy)
18. [Potential Improvements](#18-potential-improvements)
19. [Contributing](#19-contributing)
20. [Quick Reference](#20-quick-reference)

---

## 1. Executive Summary

Helix is a single self-contained binary (`hx`) plus a `runtime` directory of tree-sitter
grammars and queries. It has **no plugin runtime, no embedded scripting language, and no
network services**. All "smart" behavior — syntax highlighting, code navigation, completion,
diagnostics, debugging — is delivered either by compiled-in tree-sitter grammars or by
out-of-process **language servers** and **debug adapters** that Helix speaks to over stdio.

The codebase is a **Rust Cargo workspace of 14 crates** organized as a clean dependency
stack: functional core editing primitives at the bottom, an imperative editor/view layer in
the middle, and a terminal frontend at the top, with protocol clients (LSP, DAP) and support
crates alongside. This layering is the single most important fact for understanding,
packaging, or extending Helix.

Operationally, Helix is low-risk: it runs entirely as the invoking user, opens no sockets,
and gates its only code-execution surfaces (project-local config and language-server startup)
behind a **workspace-trust** prompt that is *off by default for untrusted workspaces*.

| Attribute             | Value                                                            |
| --------------------- | --------------------------------------------------------------- |
| Distribution unit     | `hx` binary + `runtime/` directory                              |
| Process model         | Single process, runs as the user; spawns LSP/DAP child processes |
| Network surface       | None (LSP/DAP communicate over stdio by default)                |
| Persistence           | Config files, log file, jumplist/trust lists on disk            |
| Configuration         | TOML (`config.toml`, `languages.toml`), with project-local merge |
| Extensibility (today) | Language servers, debug adapters, tree-sitter grammars, themes  |
| Code-execution gates  | Workspace trust (LSP + local config)                            |

---

## 2. Architecture Overview

Helix is built as a layered Cargo workspace. The dependency direction flows upward: lower
crates know nothing about higher ones.

```
                         ┌───────────────────────────────────────────┐
   User ── terminal ───▶ │ helix-term  (terminal frontend, event loop)│
                         │   commands.rs · keymap.rs · ui/* · main()  │
                         └───────────────┬───────────────────────────┘
                                         │ uses
              ┌──────────────────────────┴──────────────────────────┐
              ▼                                                       ▼
   ┌────────────────────┐                              ┌──────────────────────────┐
   │ helix-view         │  imperative shell:           │ helix-tui                │
   │ Editor · Document  │  open docs, view tree,        │ TUI primitives (Surface, │
   │ View · registers   │  config, LSP registry         │ Rect, widgets, backend)  │
   └─────────┬──────────┘                              └──────────────────────────┘
             │ uses                         uses ▲                ▲
             ▼                                   │                │
   ┌────────────────────┐   ┌──────────────┐  ┌─┴────────┐  ┌────┴───────┐
   │ helix-core         │   │ helix-lsp    │  │ helix-dap│  │ helix-vcs  │
   │ Rope · Selection   │   │ LSP client   │  │ DAP clnt │  │ git/diff   │
   │ Transaction·Syntax │   └──────┬───────┘  └────┬─────┘  └────────────┘
   └─────────┬──────────┘          │               │
             │              ┌──────┴──────┐  ┌──────┴───────┐
             │              │helix-lsp-   │  │helix-dap-    │
             │              │types        │  │types         │
             │              └─────────────┘  └──────────────┘
             ▼
   ┌────────────────────────────────────────────────────────────────┐
   │ Foundations: helix-stdx (std extensions) · helix-event (events) │
   │ helix-loader (fetch/build/load runtime) · helix-parsec (parser  │
   │ combinators) · xtask (dev task runner)                          │
   └────────────────────────────────────────────────────────────────┘
```

The design intent (documented in the project's own `architecture.md`) is that `helix-core`
is **purely functional** — operations return new copies rather than mutating in place — while
`helix-view` is the **imperative shell** that ties documents, views, syntax, history, and
language servers together. `helix-term` is the concrete terminal frontend and event loop. The
core is "heavily based on [CodeMirror 6](https://codemirror.net/6/docs/)."

> [!NOTE]
> The `helix-view` layer was originally intended to be frontend-agnostic; today it is tied to
> the terminal UI. A future custom GPU renderer (mentioned by the maintainers) would build on
> the same `view`/`core` split.

---

## 3. Crate Reference

The workspace members, in dependency order from foundation to frontend. The `default-members`
is `helix-term` (so a bare `cargo build` builds the editor).

| Crate              | Role |
| ------------------ | ---- |
| `helix-stdx`       | Extensions to the Rust standard library (path canonicalization, etc.), in the spirit of rust-analyzer's `stdx`. |
| `helix-core`       | Core editing primitives, **functional**: `Rope`, `Selection`/`Range`, `Transaction`, `Syntax`, history, snippets, increment/decrement, indentation. |
| `helix-event`      | Primitives for defining and dispatching editor events and registering hooks (sync hooks and debounced `AsyncHook`s). |
| `helix-loader`     | Fetching, building, and loading external resources — tree-sitter grammars and runtime files; runtime-directory resolution. |
| `helix-parsec`     | Small parser-combinator library used internally (e.g. for command-line and snippet parsing). |
| `helix-lsp-types`  | Language Server Protocol type definitions. |
| `helix-lsp`        | The LSP **client** — talks to language servers over stdio. |
| `helix-dap-types`  | Debug Adapter Protocol type definitions. |
| `helix-dap`        | The DAP **client** — talks to debug adapters. |
| `helix-vcs`        | Version-control integration: git diff gutters and change tracking (worker-based diffing). |
| `helix-tui`        | TUI primitives — `Surface`, `Rect`, widgets, terminal backends. Forked from `tui-rs`, inspired by Cursive. |
| `helix-view`       | The imperative editor shell: `Editor`, `Document`, `View`, registers, the view tree, config, and the language-server registry. |
| `helix-term`       | The terminal frontend: `main()`, the `Application` event loop, `commands.rs` (every action), `keymap.rs` (key→command), and the `ui/` components. |
| `xtask`            | Ad-hoc dev task runner (e.g. `cargo xtask docgen` regenerates the command/language docs). |

> [!TIP]
> When orienting yourself in the source, `helix-term/src/commands.rs` is the highest-value
> file — it defines every command tied to a keybinding. `helix-term/src/keymap.rs` maps keys
> to those commands, and `helix-term/src/ui/` holds the rendered components.

### Workspace build profiles

Defined in the root `Cargo.toml`:

| Profile        | Inherits | Notable settings                                       | Use |
| -------------- | -------- | ------------------------------------------------------ | --- |
| `release`      | —        | `lto = "thin"`                                          | Standard release |
| `opt`          | release  | `lto = "fat"`, `codegen-units = 1`, `strip`, `opt-level = 3` | Maximum-performance distribution build |
| `integration`  | test     | `opt-level = 2` for helix-core/tui/term                 | Faster integration-test runs |

---

## 4. Core Data Model

These are the primitives in `helix-core` that everything else is built on. Understanding them
explains many of Helix's user-visible behaviors.

### Rope

Buffer text is represented as a **`Rope`** (re-exported from the
[ropey](https://github.com/cessen/ropey) library). Ropes are cheap to clone, which lets Helix
take inexpensive snapshots of document state — the basis for undo history and concurrent
views.

### Selection and Range

Multiple selections are a core primitive, not an add-on. A document's selection is a
**`Selection`** containing one or more **`Range`s**. Each `Range` has a moving **`head`** and
an immovable **`anchor`**. A plain cursor is a single-width range where head and anchor
coincide. This is why every Helix command operates naturally on N selections at once.

### Transaction

Edits are expressed as an OT-like **`Transaction`** — a single coherent change applied to a
rope. Transactions:

- can be **inverted** to produce an undo;
- allow selections and marks to be **mapped** through them, translating positions into the
  post-edit text state.

`Transaction::change` / `Transaction::change_by_selection` is the primary interface for
generating text edits.

### Syntax

**`Syntax`** is the interface to tree-sitter ASTs, powering incremental syntax highlighting,
structural textobjects, indentation heuristics, and the `]f`/`[t`-style navigation. Grammar
loading and the highlight engine are provided via the `tree-house` dependency (a tree-sitter
integration) plus the per-language query files in the `runtime` directory.

> [!IMPORTANT]
> The functional core means most operations return new values rather than mutating. This is
> what makes snapshots, undo, and multi-view consistency tractable — but it also means
> contributors must thread new state through rather than editing in place.

---

## 5. Rendering and UI Layer

The UI is composed of **`Component`s** (widgets), found mostly in `helix-term/src/ui`. Key
abstractions (from `helix-view` and `helix-tui`):

| Abstraction  | Responsibility |
| ------------ | -------------- |
| `Document`   | Ties together the `Rope`, per-view `Selection`s, `Syntax`, `History`, language server state — the full representation of an open file. |
| `View`       | An open split: holds the displayed document ID plus gutter, status line, diagnostics, and the inner text area. Multiple views can show the same document (hence selections are stored per `ViewId`). |
| `Editor`     | Global state: all open documents, the tree of view splits, configuration, and the language-server registry. |
| `Surface`    | A buffer that widgets draw into; rendered to the screen each cycle. |
| `Rect`       | An x/y/width/height region of a `Surface` constraining where a `Component` may render. |
| `Component`  | A widget. Some (e.g. `Popup`, `Overlay`) take child components. |
| `Layer`      | A `Vec<Component>` managed by the `Compositor`. |
| `Compositor` | Renders each layer in push order, so components stack — this is how a picker draws over the editor, a popup over a picker, and so on. |
| `Info`       | The autoinfo box that shows available bindings while you wait on a prefix key like `g` or `m`. |

The render loop lives in `helix-term`: `main()` constructs an `Application` that runs the
event loop; on each top-level render call the `Compositor` paints the layer stack onto the
`Surface`.

---

## 6. Event System and Hooks

The `helix-event` crate defines the editor's internal event mechanism. Events cover document
open/change/close, language-server start/stop, and more.

- Define events with the `events!` macro.
- Register **synchronous** hooks with `register_hook!`.
- Dispatch editor-wide events to hooks with `helix_event::dispatch`.
- Use **`AsyncHook`** for cancellable, **debounced** work that should run a short time after
  an event settles (the basis for idle-triggered behaviors like completion and diagnostics
  refresh, governed by `editor.idle-timeout`).

This event/hook system is the closest thing Helix has to an internal extension point today,
and is expected to underpin a future plugin system.

---

## 7. LSP and DAP Integration

### Language servers (LSP)

`helix-lsp` is a client that launches each configured language server as a **child process**
and communicates over stdio using the types in `helix-lsp-types`. The `Editor` holds a
registry of running servers. Multiple languages can share one server instance (e.g.
`typescript-language-server` serves JavaScript, JSX, TSX, and TypeScript by default).

Per-language and per-server behavior is configured in `languages.toml` (see
[Language and Grammar Configuration](#12-language-and-grammar-configuration)). Feature
routing (`only-features` / `except-features`) lets operators compose several servers — for
example a dedicated formatter server plus a primary analysis server.

### Debug adapters (DAP)

`helix-dap` is a Debug Adapter Protocol client (types in `helix-dap-types`). Debugging is
driven from the `Space G` minor mode or the `:debug-start` / `:debug-remote` commands and is
marked experimental.

> [!NOTE]
> LSP and DAP are external programs that Helix executes. They are a code-execution surface and
> are therefore gated by [workspace trust](#14-security-analysis). Operators packaging Helix
> do **not** bundle language servers; users install them separately and place them on `$PATH`.

---

## 8. System Requirements

### Runtime

| Requirement       | Detail |
| ----------------- | ------ |
| OS                | Linux, macOS, Windows (and other Unix-likes) |
| Terminal          | Any reasonably modern terminal. For full keybinding fidelity (Super key, `Shift-Tab`, some Alt combos), a terminal supporting the enhanced/Kitty keyboard protocol is recommended. |
| Runtime files     | The `runtime/` directory (grammars + queries + themes + tutor) must be discoverable (see [Runtime File Resolution](#10-runtime-file-resolution)). |
| Language servers  | Optional, per language; must be on `$PATH`. |
| Truecolor         | Auto-detected; can be forced with `editor.true-color = true`. |

### Build

| Requirement | Detail |
| ----------- | ------ |
| Rust        | The Rust toolchain; MSRV **1.90**. Helix follows Firefox's MSRV policy and keeps it intentionally low for downstream packaging. |
| Git         | Required. |
| C++ compiler | C++14-compatible (GCC or Clang) to build tree-sitter grammars. |
| musl note   | With `musl-libc`, set `RUSTFLAGS="-C target-feature=-crt-static"` so grammars load. |

> [!IMPORTANT]
> When bumping the MSRV, three places must change together: `workspace.package.rust-version`
> in the root `Cargo.toml`, `env.MSRV` in `.github/workflows/build.yml`, and
> `toolchain.channel` in `rust-toolchain.toml`.

---

## 9. Build and Installation for Operators

### Reproducible vs. optimized builds

```sh
# Reproducible (locked dependencies)
cargo install --path helix-term --locked

# Optimized for the local CPU
cargo install \
   --profile opt \
   --config 'build.rustflags=["-C", "target-cpu=native"]' \
   --path helix-term \
   --locked
```

Both produce `hx` and build the grammars into the local `runtime/` folder.

### Grammar control at build time

| Mechanism                              | Effect |
| -------------------------------------- | ------ |
| `HELIX_DISABLE_AUTO_GRAMMAR_BUILD`     | Skip fetching/building grammars during the build. |
| `hx --grammar fetch` / `--grammar build` | Fetch/build grammars later, into the user runtime dir. |
| `use-grammars = { only = [...] }` in `languages.toml` | Restrict which grammars are processed. |

### Packaging guidance

For distribution packages, set `HELIX_DEFAULT_RUNTIME` **at build time** to the final
install location of the runtime files so the shipped `hx` finds them out of the box:

```sh
export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime
cargo build --profile opt --locked
cp -r runtime "$BUILD_DIR/usr/lib/helix/"
cp target/opt/hx "$BUILD_DIR/usr/bin/hx"
```

### Building the Debian package

```sh
cargo install cargo-deb
cargo deb -- --locked      # output in target/debian/
```

The resulting `.deb` bundles shell completions (bash/fish/zsh), the `.desktop` file, the
icon, and a launcher that wires up the runtime.

> [!WARNING]
> A `cargo deb` run may print `warning: Failed to find dependency specification` for some
> grammar files — this is expected and harmless.

---

## 10. Runtime File Resolution

Helix searches multiple runtime directories **in priority order**; the first match for a
given filename wins:

1. `runtime/` sibling of `$CARGO_MANIFEST_DIR` (development/testing only).
2. `runtime/` under the OS-dependent Helix **user config** directory.
3. `$HELIX_RUNTIME`.
4. The distribution fallback set at **compile time** via `HELIX_DEFAULT_RUNTIME`.
5. `runtime/` next to the `hx` executable.

| Platform | Config / runtime base |
| -------- | --------------------- |
| Linux / macOS | `~/.config/helix/` (runtime at `~/.config/helix/runtime/`) |
| Windows  | `%AppData%\helix\` |

Validate resolution with `hx --health`. For source builds, either export `HELIX_RUNTIME` or
symlink the source `runtime/` into the config dir; on Windows use a directory junction
(`New-Item -ItemType Junction` or `mklink /D`).

> [!CAUTION]
> If syntax highlighting or indentation is missing, the cause is almost always an unresolved
> runtime directory or unbuilt grammar. `hx --health <language>` pinpoints which.

---

## 11. Configuration Mastery

Configuration is TOML. The user file is `~/.config/helix/config.toml`
(`%AppData%\helix\config.toml` on Windows). A **project-local** `.helix/config.toml` merges
on top of the user file and built-in defaults. Apply changes at runtime with
`:config-reload` or, on Unix, `pkill -USR1 hx`. A one-off file can be passed with `hx -c`.

> [!NOTE]
> The `theme` key and the `[keys.*]` remapping tables are top-level (not under `[editor]`).
> Key remapping is documented in the User Guide; this section is the exhaustive **option**
> reference.

### `[editor]`

| Key | Description | Default |
|-----|-------------|---------|
| `scrolloff` | Lines of padding kept around the screen edge when scrolling | `5` |
| `mouse` | Enable mouse mode | `true` |
| `mouse-yank-register` | Register used for mouse yanks | `*` |
| `middle-click-paste` | Middle-click paste support | `true` |
| `default-yank-register` | Default register for yank/paste | `"` |
| `scroll-lines` | Lines scrolled per wheel step | `3` |
| `shell` | Shell for external commands | Unix `["sh","-c"]` / Win `["cmd","/C"]` |
| `line-number` | `absolute` or `relative` | `"absolute"` |
| `cursorline` | Highlight cursor line(s) | `false` |
| `cursorcolumn` | Highlight cursor column(s) | `false` |
| `continue-comments` | Continue comment token on new line inside a comment | `true` |
| `gutters` | Gutters to show (`diagnostics`, `diff`, `line-numbers`, `spacer`) | `["diagnostics","spacer","line-numbers","spacer","diff"]` |
| `auto-completion` | Auto popup of completion | `true` |
| `path-completion` | Filepath completion | `true` |
| `auto-format` | Format on save (also needs language `auto-format`) | `true` |
| `idle-timeout` | ms after last keypress before idle timers fire | `250` |
| `completion-timeout` | ms after typing before completions show (5 = instant) | `250` |
| `preview-completion-insert` | Apply completion instantly when selected | `true` |
| `completion-trigger-len` | Min word length to trigger autocompletion | `2` |
| `completion-replace` | Completions replace the whole word | `false` |
| `auto-info` | Show info boxes | `true` |
| `true-color` | Force truecolor | `false` |
| `undercurl` | Force undercurl support | `false` |
| `rulers` | Columns to draw rulers at | `[]` |
| `bufferline` | `always`, `never`, or `multiple` | `"never"` |
| `color-modes` | Color mode indicator per mode | `false` |
| `text-width` | Max line length (for `:reflow`, soft-wrap) | `80` |
| `workspace-lsp-roots` | Dirs treated as LSP roots (set in `.helix/config.toml`) | `[]` |
| `default-line-ending` | `native`, `lf`, `crlf`, `ff`, `cr`, `nel` | `"native"` |
| `insert-final-newline` | Insert trailing newline on write if missing | `true` |
| `atomic-save` | Atomic file writes (prevents data loss; may confuse watchers) | `true` |
| `trim-final-newlines` | Remove extra trailing newlines on write | `false` |
| `trim-trailing-whitespace` | Trim trailing whitespace on write | `false` |
| `popup-border` | `popup`, `menu`, `all`, or `none` | `"none"` |
| `indent-heuristic` | `simple`, `tree-sitter`, or `hybrid` | `"hybrid"` |
| `jump-label-alphabet` | Characters used for two-char jump labels | `"abc…xyz"` |
| `end-of-line-diagnostics` | Min severity rendered at end of line (`disable` to off) | `"hint"` |
| `clipboard-provider` | Clipboard backend (see below) | platform-specific |
| `editor-config` | Read `.editorconfig` files | `true` |
| `rainbow-brackets` | Rainbow matching brackets (needs `rainbows.scm`) | `false` |
| `kitty-keyboard-protocol` | `enabled`, `disabled`, or `auto` | `"auto"` |
| `insecure` | Disable workspace-trust gating (see [Security](#14-security-analysis)) | `false` |

### `[editor.clipboard-provider]`

Either a built-in name — `pasteboard` (macOS), `wayland`, `x-clip`, `x-sel`, `win32-yank`,
`termux`, `tmux`, `windows`, `termcode`, `none` — or a custom command set:

```toml
[editor.clipboard-provider.custom]
yank  = { command = "cat", args = ["test.txt"] }
paste = { command = "tee", args = ["test.txt"] }
# optional: primary-yank / primary-paste
```

Custom commands communicate the clipboard contents over stdin/stdout.

### `[editor.statusline]`

Three regions (left / center / right). Sub-keys:

| Key | Default |
|-----|---------|
| `left` | `["mode","spinner","file-name","read-only-indicator","file-modification-indicator"]` |
| `center` | `[]` |
| `right` | `["diagnostics","selections","register","position","file-encoding"]` |
| `separator` | `"│"` |
| `mode.normal` / `mode.insert` / `mode.select` | `"NOR"` / `"INS"` / `"SEL"` |
| `diagnostics` | `["warning","error"]` |
| `workspace-diagnostics` | `["warning","error"]` |

Available elements: `mode`, `spinner`, `file-name`, `file-absolute-path`, `file-base-name`,
`current-working-directory`, `file-modification-indicator`, `file-encoding`,
`file-line-ending`, `file-indent-style`, `read-only-indicator`, `total-line-numbers`,
`file-type`, `diagnostics`, `workspace-diagnostics`, `selections`, `primary-selection-length`,
`position`, `position-percentage`, `separator`, `spacer`, `version-control`, `register`.

### `[editor.lsp]`

| Key | Description | Default |
|-----|-------------|---------|
| `enable` | Master switch for LSP | `true` |
| `display-messages` | Show `window/showMessage` below statusline | `true` |
| `display-progress-messages` | Show LSP progress messages | `false` |
| `auto-signature-help` | Auto popup signature help | `true` |
| `auto-document-highlight` | Highlight symbol references at cursor | `false` |
| `display-inlay-hints` | Show inlay hints | `false` |
| `inlay-hints-length-limit` | Max displayed inlay-hint length | unset |
| `display-color-swatches` | Show color swatches | `true` |
| `display-signature-help-docs` | Docs under signature help | `true` |
| `snippets` | Snippet completions (needs `:lsp-restart` to toggle) | `true` |
| `goto-reference-include-declaration` | Include declaration in references | `true` |

### `[editor.cursor-shape]`

Per-mode shape — `block`, `bar`, `underline`, or `hidden`. Defaults: `normal`/`insert`/`select`
all `"block"`. (Only the primary cursor can change shape, a terminal limitation.)

### `[editor.file-picker]`

| Key | Default |
|-----|---------|
| `hidden` | `true` |
| `follow-symlinks` | `true` |
| `deduplicate-links` | `true` |
| `parents` | `true` |
| `ignore` | `true` |
| `git-ignore` | `true` |
| `git-global` | `true` |
| `git-exclude` | `true` |
| `max-depth` | unset |

Helix also reads `.ignore`, `~/.ignore`, a workspace `.helix/ignore`, and a global
`~/.config/helix/ignore`.

### `[editor.file-explorer]`

Same key set as the file picker but with defaults tuned to **show** most files (`hidden`,
`ignore`, `git-*` default to `false`), plus `flatten-dirs` (default `true`).

### `[editor.buffer-picker]`

| Key | Description | Default |
|-----|-------------|---------|
| `start-position` | Initially selected buffer (`current` / `previous`) | `current` |

### `[editor.auto-pairs]`

`true`/`false`, or a table mapping open→close characters. Default pairs:
`() {} [] '' "" `` `` ``. Can also be set per language in `languages.toml`.

### `[editor.auto-save]`

| Key | Description | Default |
|-----|-------------|---------|
| `focus-lost` | Save when focus leaves Helix (needs terminal focus events) | `false` |
| `after-delay.enable` | Save after a delay since last edit | `false` |
| `after-delay.timeout` | Delay in ms | `3000` |

### `[editor.search]`

| Key | Description | Default |
|-----|-------------|---------|
| `smart-case` | Case-insensitive unless pattern has uppercase | `true` |
| `wrap-around` | Wrap after the last match | `true` |

### `[editor.whitespace]`

`render` is `all`, `none`, or a per-character table (`space`, `nbsp`, `nnbsp`, `tab`,
`newline`). `characters` overrides the glyphs used. Toggle live with
`:set whitespace.render all`.

### `[editor.indent-guides]`

| Key | Description | Default |
|-----|-------------|---------|
| `render` | Draw indent guides | `false` |
| `character` | Guide glyph | `"│"` |
| `skip-levels` | Indent levels to skip | `0` |

### `[editor.gutters]`

`layout` is a vector of gutter components, default
`["diagnostics","spacer","line-numbers","spacer","diff"]`. Sub-sections:
`gutters.line-numbers` (`min-width`, default `3`), `gutters.diagnostics` (unused),
`gutters.diff` (colors from theme `diff.plus`/`minus`/`delta`; no options), `gutters.spacer`
(unused).

### `[editor.soft-wrap]`

| Key | Description | Default |
|-----|-------------|---------|
| `enable` | Enable soft wrapping | `false` |
| `max-wrap` | Max free space at line end | `20` |
| `max-indent-retain` | Max indentation carried to wrapped lines | `40` |
| `wrap-indicator` | Text before wrapped lines | `"↪ "` |
| `wrap-at-text-width` | Wrap at `text-width` instead of viewport | `false` |

### `[editor.smart-tab]`

| Key | Description | Default |
|-----|-------------|---------|
| `enable` | Tab runs `move_parent_node_end` when non-whitespace is to the left | `true` |
| `supersede-menu` | smart-tab takes precedence over menu cycling | `false` |

### `[editor.inline-diagnostics]`

| Key | Description | Default |
|-----|-------------|---------|
| `cursor-line` | Min severity shown inline on the cursor line (`disable` to off) | `"warning"` |
| `other-lines` | Min severity shown inline on other lines | `"disable"` |
| `prefix-len` | Horizontal bars before the text | `1` |
| `max-wrap` | As `soft-wrap.max-wrap` for diagnostics | `20` |
| `max-diagnostics` | Max diagnostics rendered inline per line | `10` |

Severity values: `error`, `warning`, `info`, `hint`.

### `[editor.word-completion]`

| Key | Description | Default |
|-----|-------------|---------|
| `enable` | Complete words from open buffers | `true` |
| `trigger-length` | Word chars before triggering | `7` |

---

## 12. Language and Grammar Configuration

Language behavior lives in `languages.toml`, merged across three locations (built-in → user
config dir → project `.helix/`).

### `[[language]]` keys

| Key | Description |
|-----|-------------|
| `name` | Language name |
| `language-id` | LSP language id |
| `scope` | TextMate-style scope, e.g. `source.rust` |
| `injection-regex` | Pattern for language-injection matching |
| `file-types` | Extensions and/or `glob` tables |
| `shebangs` | Interpreters from the shebang line |
| `roots` | Marker files for LSP root selection |
| `auto-format` | Format on save |
| `diagnostic-severity` | Minimum severity to display |
| `comment-tokens` / `block-comment-tokens` | Line / block comment tokens |
| `indent` | `{ unit, tab-width }` |
| `language-servers` | Servers for this language (with optional feature filters) |
| `grammar` | Tree-sitter grammar name (defaults to `name`) |
| `formatter` | External formatter (stdin→stdout) |
| `soft-wrap` / `text-width` / `rulers` | Per-language overrides |
| `path-completion` / `word-completion` / `rainbow-brackets` | Per-language overrides |
| `workspace-lsp-roots` | Stop the LSP root search early |
| `persistent-diagnostic-sources` | Sources whose positions Helix tracks internally |

### Project and LSP root selection

- The **workspace root** is found once by walking up from the working directory to the first
  directory containing `.git`, `.svn`, `.jj`, or `.helix` (else the cwd).
- **Root markers** (`roots`) are searched starting at the **file**, using the **topmost**
  marker up to the workspace root.
- `workspace-lsp-roots` (set in `$PROJECT/.helix/config.toml`) stops the search early for
  nested-root projects.
- A server's `required-root-patterns` is **validation after** root selection — if none match,
  the server is not started.

### File-type detection

`file-types` accepts strings (extension match) and `glob` tables (full-path match, always
`/`-separated). Globs take priority over extensions.

### `[language-server.<name>]` keys

| Key | Description |
|-----|-------------|
| `command` | Binary name/path (must be in `$PATH`) |
| `args` | Arguments |
| `config` | Initialization options |
| `timeout` | Max request time in seconds (default `20`) |
| `environment` | Env vars for the server |
| `required-root-patterns` | Globs that must exist for the server to start |

A language may list multiple servers; `only-features` / `except-features` route the supported
features. Feature priority follows the array order, except `diagnostics`, `code-action`,
`completion`, `document-symbols`, and `workspace-symbols`, which merge across all enabled
servers. The full feature list: `format`, `goto-declaration`, `goto-definition`,
`goto-type-definition`, `goto-reference`, `goto-implementation`, `signature-help`, `hover`,
`document-highlight`, `completion`, `code-action`, `document-links`, `workspace-command`,
`document-symbols`, `workspace-symbols`, `diagnostics`, `pull-diagnostics`, `rename-symbol`,
`inlay-hints`, `document-colors`, `call-hierarchy`.

### `[[grammar]]` and grammar selection

```toml
[[grammar]]
name = "mylang"
source = { git = "https://github.com/example/mylang", rev = "<commit>", subpath = "optional" }
```

Fetch/build with `hx --grammar fetch` / `hx --grammar build`. A top-level
`use-grammars = { only = [...] }` or `{ except = [...] }` (declared **before** any
`[[language]]`/`[[grammar]]`) limits which grammars are processed.

> [!TIP]
> Helix ships query files for **several hundred** languages (the `runtime/queries/<lang>/`
> directories), each potentially providing `highlights.scm`, `indents.scm`, `textobjects.scm`,
> `injections.scm`, `locals.scm`, and `rainbows.scm`. Structural textobjects and tree-sitter
> navigation only work for languages whose `textobjects.scm` exists.

---

## 13. Theming Reference

Themes are TOML files in `~/.config/helix/themes/` (or `%AppData%\helix\themes\`). Set with
`theme = "<name>"`, or split light/dark:

```toml
[theme]
dark = "catppuccin_frappe"
light = "catppuccin_latte"
# fallback = "catppuccin_frappe"
```

### Style syntax

```toml
key = { fg = "#ffffff", bg = "#000000", underline = { color = "#ff0000", style = "curl" }, modifiers = ["bold","italic"] }
```

- **Colors:** CSS hex (`#RGB`/`#RRGGBB`) or a `[palette]` name. The default palette is the
  terminal's 16 colors (`black`, `red`, …, `white`, plus `light-*`). No alpha/transparency.
- **Modifiers:** `bold`, `dim`, `italic`, `underlined` (deprecated), `slow_blink`,
  `rapid_blink`, `reversed`, `hidden`, `crossed_out`.
- **Underline styles:** `line`, `curl`, `dashed`, `dotted`, `double_line`.
- **Inheritance:** `inherits = "<theme>"`.
- **Rainbow brackets:** a `rainbow = [...]` list of styles.

> [!NOTE]
> When matching a syntax highlight, the **longest** matching key wins (e.g. `function.builtin`
> beats `function`). `default` and `base16_default` are reserved built-in names.

### Scope families

**Syntax scopes** mirror tree-sitter highlight names and follow Sublime/TextMate naming —
top-level families include `type` (`builtin`/`parameter`/`enum.variant`), `constant`
(`numeric.integer/float`, `character.escape`, `builtin.boolean`), `string`
(`regexp`, `special.path/url/symbol`), `comment` (`line.documentation`,
`block.documentation`, `unused`), `variable` (`mutable`, `builtin`, `parameter`,
`other.member.private`), `keyword` (`control.conditional/repeat/import/return/exception`,
`operator`, `directive`, `function`, `storage.type/modifier`), `function`
(`builtin`/`method`/`macro`/`special`), `tag`, `namespace`, `label`, `punctuation`
(`delimiter`/`bracket`/`special`), `operator`, `special`, `markup`
(`heading.1..6`, `list`, `bold`, `italic`, `link.*`, `quote`, `raw.inline/block`), and `diff`
(`plus`/`minus`/`delta` with `gutter` variants).

**Interface scopes** theme the editor chrome — `ui.background`, `ui.cursor.*`, `ui.gutter`,
`ui.linenr(.selected)`, `ui.statusline(.normal/insert/select/inactive/separator)`,
`ui.bufferline.*`, `ui.popup(.info)`, `ui.picker.header.*`, `ui.window`, `ui.help`,
`ui.text(.focus/inactive/info/directory/symlink)`, `ui.virtual.*`
(`ruler`/`whitespace`/`indent-guide`/`inlay-hint`/`wrap`/`jump-label`), `ui.menu(.selected/scroll)`,
`ui.selection(.primary)`, `ui.cursorline.*`, `ui.cursorcolumn.*`, plus diagnostic scopes
(`warning`, `error`, `info`, `hint`, their `.diagnostic.inline` variants, and
`diagnostic.*`), and `tabstop` for snippet placeholders.

---

## 14. Security Analysis

Helix's threat surface is small and well-defined. It runs as the invoking user, opens no
network sockets, and has no embedded scripting runtime. The notable surfaces are below.

### Code execution via workspace features (the primary boundary)

Two features can lead to running code defined by a repository:

1. **Project-local configuration** — `.helix/config.toml` and `.helix/languages.toml` can
   specify formatters, language-server commands, and other behavior.
2. **Language servers** — starting a server executes an external binary against project files.

Helix mitigates this with **Workspace Trust**:

- No workspace is trusted by default.
- Opening a file in an undecided workspace prompts the user.
- `Never` excludes the workspace permanently from prompts.
- `:workspace-trust` / `:workspace-untrust` manage the current workspace.
- Trust/exclude lists live in `~/.local/share/helix/trusted_workspaces` and
  `.../excluded_workspaces`.

> [!CAUTION]
> Setting `editor.insecure = true` **disables** this protection — every `.helix/` config is
> loaded and language servers start without prompting. Do not enable it on machines that open
> untrusted repositories.

### Shell expansions and command execution

The command line supports `%sh{...}` expansions and shell commands (`:sh`, `:pipe`, `!`,
`|`). These run with the user's `editor.shell`. They execute only when the user invokes them,
but keybindings and project config could in principle pre-stage such commands — another reason
the trust boundary matters.

### File writing

`atomic-save` (default `true`) writes files atomically to prevent corruption on interruption.
Operators relying on file watchers/hot-reload should be aware atomic writes (rename-in-place)
can confuse some watchers; disable per the trade-off if needed.

### Clipboard providers

Custom clipboard providers run external commands for yank/paste. Treat them as trusted
configuration; a malicious `clipboard-provider.custom` command would run on every clipboard
operation.

### Defense-in-depth recommendations

- Keep `editor.insecure` unset.
- Review `.helix/` directories before trusting unfamiliar repositories.
- Install language servers from trusted sources and pin versions where possible.
- For debugging untrusted code, run inside a container or VM (DAP executes the target).

---

## 15. Operations

### Day-to-day operator commands

| Task | How |
| ---- | --- |
| Health check | `hx --health` (or `hx --health <language>`) |
| Open log | `:log-open`, or launch with `hx --log /path` and `tail -f` |
| Increase log verbosity | `hx -v` (repeatable: `-vv`, `-vvv`); `HELIX_LOG_LEVEL` for integration tests |
| Reload config | `:config-reload` or `pkill -USR1 hx` (Unix) |
| Restart a language server | `:lsp-restart` (or `:lsp-stop`) |
| Set/inspect options live | `:set <key> <value>`, `:toggle <key>`, `:get <key>` |
| Change working directory | `:cd <path>` (`:pwd` to show) |

### Log file locations

The log file path is reported by `hx --health` (typically under the OS cache directory, e.g.
`~/.cache/helix/helix.log`). Override with `--log`.

### Upgrades

Helix is a single binary plus a `runtime/` directory. Upgrade via your package manager, or
rebuild from source. After upgrading a source build, rebuild grammars if the grammar set
changed (`hx --grammar fetch && hx --grammar build`). Many crash fixes ship per release, so
staying current is the main reliability lever.

### Backup and state

User-relevant state on disk:

| Path | Contents |
| ---- | -------- |
| `~/.config/helix/config.toml`, `languages.toml` | User configuration |
| `~/.config/helix/themes/` | User themes |
| `~/.config/helix/runtime/` | User runtime (grammars/queries/themes), if used |
| `~/.local/share/helix/trusted_workspaces`, `excluded_workspaces` | Workspace-trust decisions |
| `~/.cache/helix/helix.log` (typical) | Log file |

---

## 16. Code Quality and Conventions

| Aspect | Convention |
| ------ | ---------- |
| Language | Rust, edition 2021, MSRV 1.90 |
| Formatting | `rustfmt` (`rustfmt.toml` at repo root) |
| Workspace | 14-crate Cargo workspace; layered dependency stack (core → view → term) |
| Core style | Functional — operations return new values rather than mutating in place |
| Errors | `anyhow::Result` at boundaries (e.g. arg parsing), `thiserror` for typed errors |
| Concurrency | `tokio` async runtime; `parking_lot` locks; `arc-swap` for hot-swappable config |
| Key dependencies | `ropey` (rope), `nucleo` (fuzzy matcher for pickers), `tree-house`/tree-sitter (syntax), `slotmap` (arena IDs), `toml` (config), `termina` (terminal), `globset` (ignore globs), `etcetera` (config dirs) |
| Generated docs | Command and language tables are generated via `cargo xtask docgen` |
| Logging | `log` crate macros (`log::info!`, `warn!`, `error!`); verbosity via `-v` |

> [!TIP]
> Some book pages (the `:command` list and language-support matrix) are **generated** from the
> code with `cargo xtask docgen`. When adding commands or languages, regenerate them rather
> than hand-editing.

---

## 17. Testing Strategy

| Test type | Command | Notes |
| --------- | ------- | ----- |
| Unit + doc tests | `cargo test --workspace` | All packages |
| Integration tests (helix-term) | `cargo integration-test` | Helpers in `helix-term/tests/test/helpers.rs`; set `HELIX_LOG_LEVEL=debug` for logs |
| Build/test speed | `integration` profile (opt-level 2 for core/tui/term) | Faster integration runs |

Integration tests exercise editor commands end-to-end (see
`helix-term/tests/test/commands`). Contributors are strongly encouraged to add integration
tests for new behavior, using existing tests as templates.

> [!WARNING]
> On macOS, integration tests may fail with `Too many open files (os error 24)`. Raise the
> limit first: `ulimit -n 10240`.

---

## 18. Potential Improvements

Observations drawn from the codebase, the project's own documentation, and the community
issue tracker. These are opportunities, not defects in normal use.

- **Plugin system.** Helix has no end-user plugin runtime today; extensibility is limited to
  language servers, debug adapters, grammars, and themes. The `helix-event` hook system and
  documented intentions point toward a future plugin architecture. Diff providers beyond git
  are explicitly noted as "eventually supported by a future plugin system."
- **Frontend-agnostic `view` layer.** `helix-view` was meant to be frontend-agnostic but is
  currently coupled to the terminal UI; decoupling would enable the mooted custom GPU
  renderer.
- **Crash hardening.** The issue tracker shows a recurring class of panics around changeset/
  position math and selection edge cases (e.g.
  [#12582](https://github.com/helix-editor/helix/issues/12582),
  [#9830](https://github.com/helix-editor/helix/issues/9830),
  [#13325](https://github.com/helix-editor/helix/issues/13325)). Many are fixed per release;
  continued fuzzing/property testing of `Transaction` and `Selection` mapping would reduce
  this class further.
- **Terminal key-protocol fragmentation.** Several reported "binding doesn't work" issues
  (e.g. macOS `Alt`/`Opt` [#2280](https://github.com/helix-editor/helix/issues/2280)) stem
  from inconsistent terminal support for modifier keys. Broader enhanced-keyboard-protocol
  adoption upstream and clearer in-app diagnostics would help.
- **Window resizing.** Manual split resizing is a long-standing requested feature
  ([#1176](https://github.com/helix-editor/helix/issues/1176)).
- **Documentation gaps.** The project notes that "not all functionality is fully documented";
  the auto-generated keymap/command tables are the most reliable reference, and `from-vim.md`
  carries TODOs (textobjects/surround/registers coverage).
- **Grammar/textobject coverage.** Structural textobjects and tree-sitter navigation depend on
  per-language `textobjects.scm` files, which exist for only a subset of the supported
  languages — a steady contribution opportunity.

---

## 19. Contributing

- **Guidelines:** `docs/CONTRIBUTING.md`. Good first issues are labeled
  [`E-easy`](https://github.com/helix-editor/helix/labels/E-easy).
- **Internals overview:** `docs/architecture.md` (summarized in this guide).
- **Dev build:** `cargo run` (debug; faster to compile). For faster compiles try the
  [mold](https://github.com/rui314/mold) linker. With rustup, you may need
  `rustup component add rust-analyzer` because `rust-toolchain.toml` pins the MSRV.
- **Print debugging:** use `log::info!`/`warn!`/`error!` and run with `-v` (more `v`s = higher
  verbosity), or `cargo run -- --log foo.log` and `tail -f foo.log`.
- **Generated docs:** run `cargo xtask docgen` after changing commands or languages. Preview
  the book with `mdbook serve book`.
- **API docs:** `cargo doc --open`.
- **High-value files:** `helix-term/src/commands.rs` (all commands),
  `helix-term/src/keymap.rs` (key bindings), `helix-term/src/ui/` (components),
  `helix-core/` (editing primitives).
- **MSRV bumps:** update `Cargo.toml`, `.github/workflows/build.yml`, and
  `rust-toolchain.toml` together; follow Firefox's MSRV policy.

---

## 20. Quick Reference

### Environment variables

| Variable | Purpose |
| -------- | ------- |
| `HELIX_RUNTIME` | Override the runtime directory location |
| `HELIX_DEFAULT_RUNTIME` | **Compile-time** distribution fallback runtime path (packagers) |
| `HELIX_DISABLE_AUTO_GRAMMAR_BUILD` | Skip grammar fetch/build during the build |
| `HELIX_LOG_LEVEL` | Log level for integration tests |
| `RUSTFLAGS="-C target-feature=-crt-static"` | Required for musl builds |

### CLI flags

`hx [FLAGS] [files]` — `-h/--help`, `-V/--version`, `--tutor`, `--health [LANG]`,
`-g/--grammar fetch|build`, `-c/--config <path>`, `--log <path>`, `-w/--working-dir <path>`,
`--vsplit`, `--hsplit`, `--strict`, `-v` (repeatable), `--` (end of flags). File positions:
`file:row:col`, `+N file`, `+ file`.

### Key paths

| Path | Purpose |
| ---- | ------- |
| `~/.config/helix/config.toml` (`%AppData%\helix\config.toml`) | User config |
| `~/.config/helix/languages.toml` | Language config |
| `~/.config/helix/themes/` | User themes |
| `~/.config/helix/runtime/` | User runtime files |
| `<project>/.helix/{config,languages}.toml` | Project-local overrides (trust-gated) |
| `~/.local/share/helix/trusted_workspaces` / `excluded_workspaces` | Trust decisions |

### Crate map (one line each)

`helix-stdx` std extensions · `helix-core` functional editing primitives · `helix-event`
events/hooks · `helix-loader` runtime/grammar loading · `helix-parsec` parser combinators ·
`helix-lsp-types`/`helix-lsp` LSP types/client · `helix-dap-types`/`helix-dap` DAP
types/client · `helix-vcs` git diff · `helix-tui` TUI primitives · `helix-view` editor shell ·
`helix-term` terminal frontend · `xtask` dev tasks.

### Operator checklist

- [ ] `hx --health` reports config, language, log, and runtime paths correctly.
- [ ] Runtime directory resolves (grammars built; syntax highlighting works).
- [ ] Required language servers are installed and on `$PATH`.
- [ ] `editor.insecure` is **unset**; workspace trust prompts behave as expected.
- [ ] Themes/config in `.helix/` reviewed before trusting unfamiliar repos.
- [ ] Backups cover `~/.config/helix/` and `~/.local/share/helix/` trust lists.

---

_Generated June 2026 from helix-editor/helix at d3ec5bc. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
