# Helix User Guide

Helix is a modal text editor for the terminal, written in Rust. Its editing model is
heavily inspired by [Kakoune](https://github.com/mawww/kakoune) and
[Neovim](https://github.com/neovim/neovim): you **select first, then act**. Helix ships
with multiple-selection editing, built-in Language Server Protocol (LSP) support, smart
incremental syntax highlighting via tree-sitter, and a debugger client — all configured
through plain TOML files, with no plugins or external dependencies required to get started.

This guide takes you from installation through everyday editing, multi-cursor workflows,
language-server features, configuration, and a complete keybinding and command reference.

> [!NOTE]
> The Helix binary is named **`hx`**. A few package managers (notably Arch's `extra`
> repository) install it as `helix` instead. If `hx` is not found after installation, try
> `helix`.

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [Installation](#2-installation)
3. [Core Concepts](#3-core-concepts)
4. [Everyday Editing](#4-everyday-editing)
5. [Multiple Selections](#5-multiple-selections)
6. [Search and Replace](#6-search-and-replace)
7. [Textobjects and Surround](#7-textobjects-and-surround)
8. [Working with Files, Buffers, and Splits](#8-working-with-files-buffers-and-splits)
9. [Pickers and Fuzzy Finding](#9-pickers-and-fuzzy-finding)
10. [Language Server Features](#10-language-server-features)
11. [The Command Line](#11-the-command-line)
12. [Shell Integration](#12-shell-integration)
13. [Registers and Macros](#13-registers-and-macros)
14. [Configuration](#14-configuration)
15. [Key Remapping](#15-key-remapping)
16. [Themes](#16-themes)
17. [Configuring Languages and Language Servers](#17-configuring-languages-and-language-servers)
18. [Workspace Trust](#18-workspace-trust)
19. [Migrating from Vim](#19-migrating-from-vim)
20. [Troubleshooting](#20-troubleshooting)
21. [Frequently Asked Questions](#21-frequently-asked-questions)
22. [Reference](#22-reference)

---

## 1. Quick Start

If you just want to start editing immediately, here is the shortest path.

> [!TIP]
> Helix ships with an interactive tutorial. Run `hx --tutor` (or `:tutor` from inside the
> editor) for a hands-on introduction. It is the single best way to learn the editing
> model, and most new users finish it in well under an hour.

### Install, then open a file

=== "macOS"

    ```sh
    brew install helix
    hx myfile.txt
    ```

=== "Linux (Fedora/RHEL)"

    ```sh
    sudo dnf install helix
    hx myfile.txt
    ```

=== "Windows"

    ```sh
    winget install Helix.Helix
    hx myfile.txt
    ```

### The five things to know first

| You want to…                | Do this                                                         |
| --------------------------- | -------------------------------------------------------------- |
| Type text                   | Press `i` to enter **insert mode**, then type. `Esc` returns to normal mode. |
| Move around                 | In normal mode, use `h` `j` `k` `l` (or arrow keys) and `w`/`b` for words. |
| Save                        | Type `:w` then `Enter`.                                         |
| Quit                        | Type `:q` then `Enter` (`:wq` to save and quit).                |
| Open another file           | Press `Space` then `f` to open the file picker.                 |

> [!IMPORTANT]
> Helix is **modal**. When you launch it you are in **normal mode**, where letter keys run
> commands instead of inserting text. To type literal characters you must first enter
> **insert mode** with `i`, `a`, `o`, or similar. If keys seem to "do strange things," you
> are almost certainly in normal mode — press `Esc` and try `i`.

### Verify your setup

```sh
hx --health
```

```text
Config file: default
Language file: default
Log file: ~/.cache/helix/helix.log
Runtime directories: ~/.config/helix/runtime
...
```

The health check reports where Helix looks for runtime files, your config, and which
language servers and grammars are available. Run it any time something is not working as
expected.

---

## 2. Installation

The recommended way to install Helix is through your operating system's package manager.
For the latest nightly features you can [build from source](#building-from-source).

> [!NOTE]
> To take full advantage of Helix you should also install the **language servers** for the
> languages you use (for example `rust-analyzer` for Rust, `gopls` for Go,
> `typescript-language-server` for TypeScript). See
> [Configuring Languages and Language Servers](#17-configuring-languages-and-language-servers)
> and the [Language Server Configurations wiki](https://github.com/helix-editor/helix/wiki/Language-Server-Configurations).

### Package managers

=== "Linux"

    | Distribution    | Command                                              | Notes |
    | --------------- | ---------------------------------------------------- | ----- |
    | Debian 13+      | `sudo apt install hx`                                | Older systems: follow Ubuntu/Mint below. |
    | Ubuntu / Mint   | Install the `.deb` from the [releases page](https://github.com/helix-editor/helix/releases/latest) | |
    | Fedora / RHEL   | `sudo dnf install helix`                              | |
    | Arch (extra)    | `sudo pacman -S helix`                                | Run as `helix`, not `hx`. `helix-git` (AUR) builds master. |
    | NixOS           | `helix` attribute in nixpkgs, or the project flake   | `nix develop` for a dev shell. |
    | Flatpak         | `flatpak install flathub com.helix_editor.Helix`     | Run: `flatpak run com.helix_editor.Helix`. |
    | Snap            | `snap install --classic helix`                       | Installs as both `helix` and `hx`. Ensure `/snap/bin` is in `PATH`. |
    | Homebrew (Linux)| `brew install helix`                                 | |

=== "macOS"

    | Method        | Command                          | Notes |
    | ------------- | -------------------------------- | ----- |
    | Homebrew      | `brew install helix`             | Latest release. |
    | Homebrew HEAD | `brew install --HEAD helix`      | Latest nightly. |
    | MacPorts      | `sudo port install helix`        | |

=== "Windows"

    | Method     | Command                                          |
    | ---------- | ------------------------------------------------ |
    | Winget     | `winget install Helix.Helix`                     |
    | Scoop      | `scoop install helix`                            |
    | Chocolatey | `choco install helix`                            |
    | Packably   | `packl install helix`                            |
    | MSYS2      | `pacman -S mingw-w64-ucrt-x86_64-helix`          |

### Pre-built binaries

Download a tarball from the [GitHub Releases page](https://github.com/helix-editor/helix/releases).
It contains an `hx` binary and a `runtime` directory.

1. Add `hx` to your `$PATH`.
2. Copy the `runtime` directory to a location Helix searches — a typical Linux/macOS
   location is `~/.config/helix/runtime`.

```sh
# Example for a Linux/macOS tarball
mkdir -p ~/.config/helix
cp -r runtime ~/.config/helix/runtime
```

> [!TIP]
> Run `hx --health` to see exactly which runtime directories Helix searches. You can
> override the default location by setting the `HELIX_RUNTIME` environment variable.

The Linux [AppImage](https://appimage.org/) is another self-contained option:

```sh
chmod +x helix-*.AppImage
mkdir -p "$HOME/.local/bin"
mv helix-*.AppImage "$HOME/.local/bin/hx"   # ensure ~/.local/bin is in PATH
```

### Building from source

Requirements:

- The [Rust toolchain](https://www.rust-lang.org/tools/install)
- [Git](https://git-scm.com/)
- A C++14-compatible compiler (GCC or Clang) to build the tree-sitter grammars

```sh
git clone https://github.com/helix-editor/helix
cd helix
cargo install --path helix-term --locked
```

For an optimized build tuned to your CPU:

```sh
cargo install \
   --profile opt \
   --config 'build.rustflags=["-C", "target-cpu=native"]' \
   --path helix-term \
   --locked
```

Either command creates the `hx` executable and compiles the tree-sitter grammars into the
local `runtime` folder.

> [!IMPORTANT]
> When building from source you must point Helix at its runtime files. On Linux/macOS,
> either export `HELIX_RUNTIME` or create a symlink:
> ```sh
> export HELIX_RUNTIME=~/src/helix/runtime          # add to ~/.bashrc
> # or
> ln -Tsf $PWD/runtime ~/.config/helix/runtime
> ```
> On Windows, set `HELIX_RUNTIME` via `setx HELIX_RUNTIME "%userprofile%\src\helix\runtime"`
> or create a directory junction in `%appdata%\helix\`.

> [!NOTE]
> If you use the `musl-libc` standard library, set `RUSTFLAGS="-C target-feature=-crt-static"`
> during the build so tree-sitter grammars load correctly. To skip grammar building entirely,
> set `HELIX_DISABLE_AUTO_GRAMMAR_BUILD`. You can fetch and build grammars later with
> `hx --grammar fetch` and `hx --grammar build`.

After building, validate the installation with `hx --health`.

---

## 3. Core Concepts

Helix's power comes from a small set of consistent ideas. Understanding them up front makes
everything else feel natural.

### Modes

Helix is a **modal editor** — different modes interpret your keystrokes differently.

| Mode             | Enter with        | Purpose                                              |
| ---------------- | ----------------- | --------------------------------------------------- |
| **Normal**       | `Esc` (default)   | Navigation and editing commands. The default mode.  |
| **Insert**       | `i` (and friends) | Type text directly into the document.               |
| **Select / extend** | `v`            | Extend selections as you move, then act on them.    |

In addition, several **minor modes** are entered from normal mode for grouped commands:
[view](#view-mode) (`z`), [goto](#goto-mode) (`g`), [match](#match-mode) (`m`),
[window](#window-mode) (`Ctrl-w`), and [space](#space-mode) (`Space`).

### Selection-first editing

Inspired by Kakoune, Helix follows the **`selection → action`** model: you select *what* you
want to act on (a word, a line, a paragraph) and *then* apply the action (delete, change,
yank). This is the reverse of Vim's verb-then-object grammar.

A **cursor is just a single-width selection**. Whenever you move, you are really moving a
selection — which is why every movement immediately shows you exactly what an action will
affect.

### Multiple selections

Multiple selections are a first-class, everyday tool — not an advanced feature. Instead of
"find and replace all," the idiomatic Helix approach is to *select every instance at once*
(one selection per match) and then edit them all simultaneously. See
[Multiple Selections](#5-multiple-selections).

### Motions

Motions move the cursor or modify selections — `w` to the next word, `f` to find a
character, `gg` to the top of the file. Because Helix is selection-first, motions in normal
mode *replace* the selection, while the same motions in select mode *extend* it.

---

## 4. Everyday Editing

This section covers the bread-and-butter keys you will use constantly. The
[Reference](#22-reference) contains the exhaustive tables; what follows is the working set.

### Moving around

| Key                   | Moves to                                  |
| --------------------- | ----------------------------------------- |
| `h` `j` `k` `l`       | Left, down, up, right (arrow keys also work) |
| `w` / `b` / `e`       | Next word start / previous word start / next word end |
| `W` / `B` / `E`       | Same, but for WHITESPACE-delimited "WORDs" |
| `f<char>` / `t<char>` | Find / find-till the next `<char>` (not confined to the current line) |
| `F<char>` / `T<char>` | Find / find-till the previous `<char>`    |
| `Alt-.`               | Repeat the last `f`/`t`/`m`/`[`/`]` motion |
| `Home` / `End`        | Start / end of line                        |
| `<n>G` or `<n>gg`     | Go to line number `<n>`                     |
| `Ctrl-d` / `Ctrl-u`   | Half page down / up (moves cursor too)      |
| `Ctrl-f` / `Ctrl-b`   | Full page down / up                         |

> [!NOTE]
> Unlike Vim, `f`, `F`, `t`, and `T` are **not** confined to the current line — they search
> across line boundaries.

### Entering insert mode

| Key | Inserts…                                  |
| --- | ----------------------------------------- |
| `i` | Before the selection                      |
| `a` | After the selection (append)              |
| `I` | At the first non-blank of the line        |
| `A` | At the end of the line                    |
| `o` | On a new line below                        |
| `O` | On a new line above                        |

Press `Esc` to return to normal mode. Changes are grouped into a single undo step per
insert-mode session.

### Making changes

| Key       | Action                                                    |
| --------- | -------------------------------------------------------- |
| `d`       | Delete selection (yanks it to the default register)      |
| `c`       | Change selection (delete and enter insert mode)          |
| `Alt-d` / `Alt-c` | Delete / change **without** yanking              |
| `r<char>` | Replace each selected character with `<char>`           |
| `R`       | Replace selection with yanked text                       |
| `~`       | Toggle case; `` ` `` to lowercase, `` Alt-` `` to uppercase |
| `y` / `p` / `P` | Yank / paste after / paste before                  |
| `>` / `<` | Indent / unindent                                        |
| `=`       | Format selection (requires an LSP)                       |
| `u` / `U` | Undo / redo                                               |
| `Alt-u` / `Alt-U` | Move backward / forward through edit history     |
| `.`       | Repeat the last insert                                    |
| `J`       | Join lines inside the selection                          |
| `Ctrl-c`  | Toggle comments on the selected lines                    |
| `Ctrl-a` / `Ctrl-x` | Increment / decrement the number under the cursor |

> [!TIP]
> The "delete a word" muscle memory from Vim (`dw`) becomes `wd` in Helix: select the word
> first (`w`), then delete (`d`). Likewise `cw` → `wc` (or `ec`). See
> [Migrating from Vim](#19-migrating-from-vim) for a full mapping.

### A first editing example

To change the word `foo` under your cursor to `bar`:

1. `w` (or `e`) to select the word.
2. `c` to change it — Helix deletes `foo` and enters insert mode.
3. Type `bar`.
4. `Esc` to return to normal mode.

---

## 5. Multiple Selections

Multiple selections are *the* defining Helix workflow. Master them and large edits become
trivial.

### Creating selections

| Key                | Effect                                                            |
| ------------------ | ---------------------------------------------------------------- |
| `s`                | **Select** all regex matches inside the current selection(s)     |
| `S`                | **Split** the selection into sub-selections on regex matches     |
| `Alt-s`            | Split selection on newlines (one selection per line)             |
| `C` / `Alt-C`      | Copy a cursor to the next / previous line (add cursor below/above) |
| `%`                | Select the entire file                                            |
| `x`                | Select the current line; press again to extend to the next line  |
| `K` / `Alt-K`      | Keep / remove selections matching a regex                        |
| `,`                | Collapse to just the **primary** selection                       |
| `Alt-,`            | Remove the primary selection                                     |
| `(` / `)`          | Rotate which selection is primary (backward / forward)           |
| `Alt-(` / `Alt-)`  | Rotate the *contents* of the selections                          |
| `&`                | Align selections into columns                                    |
| `_`                | Trim whitespace from selections                                  |

### The canonical "select all, edit all" workflow

To rename every occurrence of `count` to `total` across a file:

1. `%` — select the whole file.
2. `s` — open a regex prompt for selecting matches.
3. Type `count` and press `Enter` — now every match is its own selection.
4. `c` — change all selections at once; type `total`.
5. `Esc`, then `,` to collapse back to a single cursor.

> [!TIP]
> Use `s` to *narrow within* a selection and `S` to *split* a selection. Combine with `Alt-s`
> to put a cursor on every line, then `A` to append at the end of every line simultaneously —
> a fast way to add a trailing character (like `;` or `,`) to many lines.

> [!NOTE]
> The status line shows the primary selection index out of the total number of active
> selections (for example `2/14`), so you always know how many cursors are live.

---

## 6. Search and Replace

Helix has no dedicated `:substitute` command — search-and-replace is expressed through
[multiple selections](#5-multiple-selections).

### Searching

| Key   | Action                                                          |
| ----- | -------------------------------------------------------------- |
| `/`   | Search forward for a regex pattern                             |
| `?`   | Search backward                                                |
| `n` / `N` | Select the next / previous match                          |
| `*`   | Use the current selection as the search pattern, auto-wrapping word boundaries with `\b` |
| `Alt-*` | Use the current selection as the search pattern verbatim     |

Search operates on the `/` register by default. The search prompt accepts full regular
expressions. With `editor.search.smart-case` enabled (the default), a lowercase pattern is
case-insensitive while a pattern containing an uppercase letter is case-sensitive.

### Replacing across a selection

To replace `foo` with `bar` inside the current selection:

```text
sfoo<ret>cbar<esc>,
```

- `s` opens a regex prompt and selects every match inside the selection.
- `foo<ret>` finalizes the matches (a cursor on each).
- `c` changes them; type `bar`.
- `<esc>` returns to normal mode; `,` keeps only the primary selection.

To do this for the **whole file**, prefix with `%` to select everything first:

```text
%sfoo<ret>cbar<esc>,
```

### Workspace-wide search

Press `Space` then `/` to run a **global search** across the workspace folder. Results open
in a fuzzy picker. After you jump to a result, press `Space` then `'` to reopen the same
results list.

> [!TIP]
> The global search picker uses regex (not fuzzy matching). Press `Enter` without typing a
> filter to reuse the contents of the search register — for example `*` `Space-/` `Enter`
> searches for the word currently under the cursor.

---

## 7. Textobjects and Surround

### Textobjects

Textobjects let you select structured pieces of text — a word, a paragraph, or, with
tree-sitter, a function or class.

- `mi<object>` — select **inside** the object
- `ma<object>` — select **around** the object

| Key after `mi`/`ma` | Selects                  |
| ------------------- | ------------------------ |
| `w` / `W`           | Word / WORD              |
| `p`                 | Paragraph                |
| `(`, `[`, `'`, …    | The specified surround pair |
| `m`                 | The closest surround pair |
| `f`                 | Function                 |
| `t`                 | Type / class             |
| `a`                 | Argument / parameter     |
| `c`                 | Comment                  |
| `T`                 | Test                     |
| `x`                 | (X)HTML element          |

> [!NOTE]
> The structural textobjects (`f`, `t`, `a`, `c`, `T`, `x`) require an active **tree-sitter**
> grammar *and* a textobject query file for the language. Coverage varies by language — see
> the [language support matrix](#language-support).

You can also *navigate* by textobject using the [unimpaired](#unimpaired) bindings: `]f`/`[f`
for next/previous function, `]t`/`[t` for next/previous type, and so on.

### Surround

Helix has built-in surround support similar to vim-surround:

| Key sequence                     | Action                                  |
| -------------------------------- | --------------------------------------- |
| `ms<char>` (after selecting)     | Add surround characters to the selection |
| `mr<from><to>`                   | Replace the closest surround pair        |
| `md<char>`                       | Delete the closest surround pair         |

Surround works with multiple selections too. To change every `(use)` to `[use]`:

1. `%` to select the whole file.
2. `s`, type `use`, `Enter` to put a selection on each match.
3. `mr([` to replace the parentheses with square brackets.

---

## 8. Working with Files, Buffers, and Splits

### Buffers

Buffers are in-memory representations of open files. You can have many open at once.

| Action                | Key / Command                          |
| --------------------- | -------------------------------------- |
| Open a file           | `:open <path>` (`:o`, `:e`) or `Space f` |
| Next / previous buffer| `gn` / `gp`, or `:buffer-next` / `:buffer-previous` |
| Switch buffers (picker) | `Space b`                            |
| New scratch buffer    | `:new`                                 |
| Close current buffer  | `:buffer-close` (`:bc`)                |
| Last accessed file    | `ga`                                   |

### Saving and quitting

| Command         | Aliases        | Action                                            |
| --------------- | -------------- | ------------------------------------------------- |
| `:write`        | `:w`           | Save to disk (optional path argument)             |
| `:write!`       | `:w!`          | Save, creating directories as needed              |
| `:update`       | `:u`           | Save only if the buffer was modified              |
| `:write-all`    | `:wa`          | Save all buffers                                  |
| `:quit`         | `:q`           | Close the current view                            |
| `:quit!`        | `:q!`          | Close, discarding unsaved changes                 |
| `:write-quit`   | `:wq`, `:x`    | Save and close                                    |
| `:write-quit-all` | `:wqa`, `:xa` | Save all and close all views                     |
| `:reload`       | `:rl`          | Discard changes and reload from disk              |

### Splits (windows)

Press `Ctrl-w` to enter [window mode](#window-mode), then:

| Key      | Action                                |
| -------- | ------------------------------------- |
| `v`      | Vertical split (right)                |
| `s`      | Horizontal split (below)              |
| `h/j/k/l`| Move focus between splits             |
| `H/J/K/L`| Swap splits in a direction            |
| `q`      | Close the current split               |
| `o`      | Close all other splits                |

You can also open files directly into a split from the command line: `:vsplit <path>`
(`:vs`) or `:hsplit <path>` (`:hs`, `:sp`). Launch Helix with `--vsplit` or `--hsplit` to
open multiple files side by side from the shell.

---

## 9. Pickers and Fuzzy Finding

Pickers are interactive selection windows. Most are reached from [space mode](#space-mode).

| Picker                         | Key       |
| ------------------------------ | --------- |
| File picker (workspace root)   | `Space f` |
| File picker (working directory)| `Space F` |
| Buffer picker                  | `Space b` |
| Global search                  | `Space /` |
| Document symbols (LSP/TS)      | `Space s` |
| Workspace symbols (LSP/TS)     | `Space S` |
| Diagnostics (document)         | `Space d` |
| Diagnostics (workspace)        | `Space D` |
| Jumplist                       | `Space j` |
| Changed files (VCS)            | `Space g` |
| Command palette                | `Space ?` |
| Reopen last picker             | `Space '` |

### Navigating and filtering

Within a picker, `Tab`/`Shift-Tab` (or arrow keys, or `Ctrl-n`/`Ctrl-p`) move between
entries, `Enter` opens the selection, and `Ctrl-s` / `Ctrl-v` open it in a horizontal /
vertical split. `Ctrl-t` toggles a preview. `Esc` closes the picker.

Most pickers use [fzf-style fuzzy matching](https://github.com/junegunn/fzf?tab=readme-ov-file#search-syntax).
When a picker has multiple columns you can target one column by prefixing its name with `%`
(abbreviated to any prefix). For example, in the global search picker:

```text
helix %p .toml !lang
```

searches for "helix" within files whose **path** ends in `.toml` but does not contain
"lang".

> [!TIP]
> Insert register contents into a picker query with `Ctrl-r` followed by a register name —
> for example `Ctrl-r` `.` inserts the current selection, and `Ctrl-r` `%` inserts the
> current file path.

---

## 10. Language Server Features

Helix has built-in LSP support. Install the language server for your language (see the
[wiki](https://github.com/helix-editor/helix/wiki/Language-Server-Configurations)), make
sure it is on your `$PATH`, and Helix uses it automatically for matching files.

| Feature                         | Key       | Command                       |
| ------------------------------- | --------- | ----------------------------- |
| Hover documentation             | `Space k` | `hover`                       |
| Go to definition                | `gd`      | `goto_definition`             |
| Go to type definition           | `gy`      | `goto_type_definition`        |
| Go to references                | `gr`      | `goto_reference`              |
| Go to implementation            | `gi`      | `goto_implementation`         |
| Rename symbol                   | `Space r` | `rename_symbol`               |
| Code action                     | `Space a` | `code_action`                 |
| Document symbols                | `Space s` | `lsp_or_syntax_symbol_picker` |
| Workspace symbols               | `Space S` | `lsp_or_syntax_workspace_symbol_picker` |
| Format selection                | `=`       | `format_selections`           |
| Autocomplete (manual trigger)   | `Ctrl-x` (insert mode) | `completion`     |
| Next / previous diagnostic      | `]d` / `[d` | `goto_next_diag` / `goto_prev_diag` |

> [!NOTE]
> Mappings marked **(LSP)** in the [keymap reference](#keymap-reference) require an active
> language server, and those marked **(TS)** require a tree-sitter grammar for the file type.

Completion pops up automatically as you type (configurable). In the completion menu, `Tab` /
`Shift-Tab` cycle entries, `Enter` accepts, and `Ctrl-c` rejects.

Useful LSP commands from the command line:

| Command          | Action                                                     |
| ---------------- | ---------------------------------------------------------- |
| `:lsp-restart`   | Restart the language server(s) for the current file        |
| `:lsp-stop`      | Stop the language server(s) for the current file           |
| `:lsp-workspace-command` | Open the workspace command picker                  |

### Debugging (DAP)

Helix includes a Debug Adapter Protocol client. Debug commands live under `Space G`
(experimental): `Space Gl` launches a debug target, `Space Gb` toggles a breakpoint,
`Space Gc` continues, `Space Gi`/`Space Go`/`Space Gn` step in/out/over. You can also start a
session from the command line with `:debug-start` (`:dbg`).

---

## 11. The Command Line

Press `:` to open the command line and run a [typable command](#typable-command-reference)
like `:write` or `:open`. The command line supports quoting, flags, and expansions.

### Quoting

Arguments are split on spaces and tabs. Wrap an argument containing spaces in single quotes
or backticks to keep it together:

```text
:open 'a b.txt'
```

Double quotes behave the same but additionally **expand** their contents (see below). On
Unix you can also escape a space with a backslash: `:open a\ b.txt`.

### Flags

Flags modify command behavior, for example `:sort --reverse` (or `-r`). Type `-` to see
completions for the current command's flags. Use `--` to mark the end of flags so following
arguments are treated literally: `:open -- -a.txt`.

### Expansions

Anything beginning with `%` is an **expansion** — Helix replaces it before running the
command. The general form is `%[<kind>]<open><contents><close>`, where the delimiters can be
`()`, `[]`, `{}`, `<>`, or the single characters `'`, `"`, `|`.

With no `<kind>`, the expansion is a **variable**:

| Variable                     | Expands to                                            |
| ---------------------------- | ----------------------------------------------------- |
| `%{cursor_line}`             | Primary cursor line number (1-based)                  |
| `%{cursor_column}`           | Primary cursor column (grapheme clusters, 1-based)    |
| `%{buffer_name}`             | Relative path of the current document                 |
| `%{file_path_absolute}`      | Absolute path of the current document                 |
| `%{selection}`              | Contents of the primary selection                     |
| `%{selection_line_start}` / `%{selection_line_end}` | Primary selection start / end line     |
| `%{current_working_directory}` | Current working directory                           |
| `%{workspace_directory}`     | Nearest ancestor containing `.git`, `.svn`, `.jj`, or `.helix` |
| `%{language}`                | Language name of the current document                 |
| `%{line_ending}`             | The document's line-ending string                     |

Other expansion kinds:

- **Shell** — `%sh{...}` runs the contents through your shell and inserts the output.
  Example: `:echo %sh{date}`.
- **Unicode** — `%u{...}` inserts a codepoint. Example: `:echo %u{25CF}` prints `●`.
- **Register** — `%reg{a}` inserts the contents of register `a`.

```text
:echo %sh{git blame -L %{cursor_line},+1 %{buffer_name}}
```

> [!CAUTION]
> Expansions are only evaluated when you press `Enter`. To use a literal `%` in a shell
> command, double it: `:echo %sh{date -u +'%%Y-%%m-%%d'}`.

> [!NOTE]
> A few commands pass their argument straight to the shell and do not interpret quotes
> (though expansions still apply): `:insert-output`, `:append-output`, `:pipe`, `:pipe-to`,
> and `:run-shell-command`.

---

## 12. Shell Integration

Helix can pipe selections through external commands directly from normal mode.

| Key      | Action                                                                  |
| -------- | ---------------------------------------------------------------------- |
| `\|`     | Pipe each selection through a command, **replacing** it with the output |
| `Alt-\|` | Pipe each selection into a command, ignoring output                     |
| `!`      | Run a command, inserting its output **before** each selection           |
| `Alt-!`  | Run a command, appending its output **after** each selection            |
| `$`      | Pipe each selection into a command; keep selections where it returned 0 |

For example, to sort and de-duplicate selected lines, pipe them through `sort -u` with `|`.
To filter selections to only those that match a pattern, use `$` with `grep -q pattern`.

The equivalent command-line forms are `:pipe`, `:pipe-to`, `:insert-output`,
`:append-output`, and `:run-shell-command` (`:sh`, `:!`).

> [!TIP]
> The shell used for these commands is the `editor.shell` setting — `["sh", "-c"]` on Unix
> and `["cmd", "/C"]` on Windows by default. Override it in your config if you prefer a
> different shell.

---

## 13. Registers and Macros

### Registers

Registers store text and other data, much like a multi-slot clipboard. Select a register
with `"` before an action — `"ay` yanks to register `a`, `"op` pastes from register `o`.

Default registers used when none is specified:

| Register | Contains              |
| -------- | --------------------- |
| `/`      | Last search           |
| `:`      | Last executed command |
| `"`      | Last yanked text      |
| `@`      | Last recorded macro   |

Special registers:

| Register | When read                              | When written                          |
| -------- | -------------------------------------- | ------------------------------------- |
| `_`      | Returns nothing                        | Discards everything (a "black hole")  |
| `#`      | Selection indices (`1`, `2`, …)        | Not writable                          |
| `.`      | Contents of the current selections     | Not writable                          |
| `%`      | Name of the current file               | Not writable                          |
| `+`      | System clipboard                       | Yanks to the system clipboard         |
| `*`      | Primary (X11/Wayland) clipboard        | Yanks to the primary clipboard        |

> [!TIP]
> Use the system clipboard directly via space mode: `Space y` yanks to the clipboard,
> `Space p` / `Space P` paste from it, and `Space R` replaces selections with its contents.

### Macros

| Key       | Action                                             |
| --------- | -------------------------------------------------- |
| `Q`       | Start / stop recording a macro to a register       |
| `q`       | Replay a recorded macro from the selected register |

Macros are experimental. To record into register `a`: `"aQ`, perform your edits, then `Q`
again to stop. Replay with `"aq`.

---

## 14. Configuration

Helix is configured with a `config.toml` file in your config directory:

- **Linux / macOS:** `~/.config/helix/config.toml`
- **Windows:** `%AppData%\helix\config.toml`

> [!TIP]
> Open your config instantly with `:config-open`. After editing, apply changes with
> `:config-reload` (no restart needed). On Unix you can also reload by sending `USR1`:
> `pkill -USR1 hx`.

A typical starter config:

```toml
theme = "onedark"

[editor]
line-number = "relative"
mouse = false
cursorline = true
color-modes = true
bufferline = "multiple"

[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"

[editor.file-picker]
hidden = false

[editor.indent-guides]
render = true
```

### Common everyday settings

| Setting              | What it does                                                   | Default |
| -------------------- | ------------------------------------------------------------- | ------- |
| `theme`              | Color theme name (top-level key, not under `[editor]`)        | —       |
| `editor.line-number`| `absolute` or `relative` line numbers                          | `"absolute"` |
| `editor.mouse`       | Enable mouse support                                           | `true`  |
| `editor.cursorline`  | Highlight the line(s) the cursor is on                         | `false` |
| `editor.scrolloff`   | Lines of padding kept around the cursor when scrolling         | `5`     |
| `editor.bufferline`  | Show a buffer bar: `never`, `always`, or `multiple`            | `"never"` |
| `editor.color-modes` | Color the mode indicator differently per mode                 | `false` |
| `editor.true-color`  | Force truecolor if your terminal isn't auto-detected           | `false` |
| `editor.auto-format` | Format on save (also needs `auto-format` in `languages.toml`) | `true`  |
| `editor.auto-save.after-delay.enable` | Auto-save after a delay                       | `false` |
| `editor.cursor-shape.{normal,insert,select}` | Cursor shape per mode (`block`, `bar`, `underline`, `hidden`) | `"block"` |

> [!NOTE]
> The complete, every-key configuration reference — all `[editor.*]` subsections, statusline
> elements, gutters, soft-wrap, inline diagnostics, and more — lives in the **Helix Admin
> Guide**. This section covers the settings most users reach for first.

### Project-local configuration

Place a `config.toml` and/or `languages.toml` inside a `.helix/` directory at the root of a
project. Those settings are merged on top of your global config and the built-in defaults,
so you can tune behavior per repository.

```text
my-project/
└── .helix/
    ├── config.toml
    └── languages.toml
```

> [!IMPORTANT]
> Loading project-local config and starting language servers can execute code defined by the
> repository. By default Helix protects you with [Workspace Trust](#18-workspace-trust) — you
> will be prompted before these features run in a new workspace.

You can also run Helix with a one-off config file: `hx -c path/to/custom-config.toml`.

---

## 15. Key Remapping

Helix supports one-way key remapping through `config.toml`. There are three kinds of things
you can bind a key to:

- **Static commands** — built-in commands like `move_char_left` (see the
  [static command reference](#static-command-reference)).
- **Typable commands** — anything you can run from `:`, like `:write`.
- **Macros** — a sequence of keys, written as a string starting with `@`.

```toml
[keys.normal]
C-s = ":w"                                   # Ctrl-s to save
C-o = ":open ~/.config/helix/config.toml"    # open your config
a = "move_char_left"                          # rebind a single key
"C-S-esc" = "extend_line"                     # Ctrl-Shift-Escape
g = { a = "code_action" }                     # 'ga' shows code actions
"ret" = ["open_below", "normal_mode"]         # run multiple commands in order
"A-x" = "@x<A-d>"                             # a macro: select line, delete without yank

[keys.insert]
j = { k = "normal_mode" }                     # 'jk' exits insert mode
```

### Modifiers and special keys

Modifiers use the prefixes `C-` (Ctrl), `S-` (Shift), and `A-` (Alt); combine with a dash,
e.g. `C-S-esc`. The Super/Windows/Command key is `Meta-`, `Cmd-`, or `Win-` (requires a
terminal supporting the enhanced keyboard protocol).

Special key names include `space`, `ret` (Enter), `esc`, `tab`, `backspace`, `del`, `ins`,
`home`, `end`, `pageup`, `pagedown`, `left`/`right`/`up`/`down`, and `lt`/`gt` for `<`/`>`.
Disable a key by binding it to `no_op`.

> [!NOTE]
> Within a macro string, wrap modifier keys in angle brackets — `<A-x>`, `<C-x>` — to
> distinguish them from the literal letters `A` or `C`. Also, `-` cannot follow a modifier;
> write `Alt` + `-` as `A-minus`.

### Defining your own minor modes

You can nest bindings to create custom minor modes:

```toml
# A new minor mode bound to '+'
[keys.normal."+"]
m = ":run-shell-command make"
c = ":run-shell-command cargo build"
t = ":run-shell-command cargo test"
```

---

## 16. Themes

Set a theme at the top of `config.toml`, or switch at runtime with `:theme <name>`:

```toml
theme = "catppuccin_mocha"
```

You can configure separate light and dark themes; on terminals that report a light/dark
preference, Helix switches automatically:

```toml
[theme]
dark = "catppuccin_frappe"
light = "catppuccin_latte"
# fallback = "catppuccin_frappe"   # used if the terminal expresses no preference
```

### Creating your own theme

Create `~/.config/helix/themes/mytheme.toml` (or `%AppData%\helix\themes\` on Windows) and
reference it as `theme = "mytheme"`. Each line styles one scope:

```toml
"ui.background" = { bg = "#1e1e2e" }
"keyword" = { fg = "mauve", modifiers = ["bold"] }
"ui.text" = "#cdd6f4"

[palette]
mauve = "#cba6f7"
```

Colors are CSS hex strings (`#RGB` or `#RRGGBB`) or names from the `[palette]`. You can
extend an existing theme with `inherits = "boo_berry"`.

> [!NOTE]
> The names `default` and `base16_default` are reserved built-ins and cannot be overridden.
> Helix does not support transparency (no alpha channel). The full list of themeable scopes
> (syntax and UI) is documented in the **Helix Admin Guide**.

---

## 17. Configuring Languages and Language Servers

Language-specific behavior — which language server to use, indentation, formatters, file-type
detection — is set in `languages.toml`. There are three locations, merged in order of
increasing precedence:

1. Built-in defaults (shipped with Helix).
2. Your config directory: `~/.config/helix/languages.toml`.
3. Project-local: `<project>/.helix/languages.toml`.

### Overriding a language

```toml
# ~/.config/helix/languages.toml
[[language]]
name = "rust"
auto-format = false
indent = { tab-width = 4, unit = "    " }
```

Commonly used `[[language]]` keys:

| Key                 | Description                                                       |
| ------------------- | --------------------------------------------------------------- |
| `name`              | Language name (must match a known language)                      |
| `file-types`        | Extensions or globs that select this language                    |
| `auto-format`       | Format this language on save                                     |
| `comment-tokens`    | Comment token(s), e.g. `"//"` or `["//", "///"]`                 |
| `indent`            | `{ unit = "  ", tab-width = 2 }`                                 |
| `language-servers`  | Which servers handle this language                               |
| `formatter`         | External formatter command (takes stdin, writes stdout)         |
| `roots`             | Marker files used for LSP root detection (e.g. `Cargo.toml`)     |

### Configuring a language server

```toml
[language-server.mylang-lsp]
command = "mylang-lsp"
args = ["--stdio"]
config = { provideFormatter = true }
environment = { "ENV1" = "value1" }

[[language]]
name = "mylang"
language-servers = ["mylang-lsp"]
```

A language can use multiple servers, and you can enable or disable individual features per
server with `only-features` / `except-features`:

```toml
[[language]]
name = "typescript"
language-servers = [
  { name = "efm-lsp-prettier", only-features = ["format"] },
  "typescript-language-server",
]
```

### File-type detection

`file-types` accepts plain extensions and `glob` tables (matched against the full path,
always using `/` as the separator even on Windows):

```toml
file-types = ["toml", { glob = "Makefile" }, { glob = ".github/workflows/*.yaml" }]
```

Globs take priority over extension matches.

### Tree-sitter grammars

Grammars are declared in `[[grammar]]` sections and fetched/built with
`hx --grammar fetch` and `hx --grammar build`. To limit which grammars are processed, set a
top-level `use-grammars` key **before** any `[[language]]` or `[[grammar]]` section:

```toml
use-grammars = { only = ["rust", "c", "cpp"] }
# or
use-grammars = { except = ["yaml", "json"] }
```

> [!TIP]
> Change a single buffer's language on the fly with `:set-language <name>` (`:lang`). Run
> `:lang` with no argument to see the current language.

---

## 18. Workspace Trust

Because LSP and project-local configuration can execute code, Helix gates them behind a
**workspace trust** mechanism. No workspace is trusted by default.

- When you open a file in a new, undecided workspace, Helix prompts you about trust.
- Choosing **Never** excludes the workspace so you are not prompted again.
- `:workspace-trust` trusts the current workspace; `:workspace-untrust` revokes it.

Trusted and excluded workspaces are stored (newline-delimited) in
`~/.local/share/helix/trusted_workspaces` and `.../excluded_workspaces`.

> [!CAUTION]
> You can restore the old, unguarded behavior — loading every `.helix/config.toml` and
> starting language servers without permission — by setting `editor.insecure = true`. Only do
> this if you understand the code-execution risk.

---

## 19. Migrating from Vim

The biggest adjustment is the **`selection → action`** order. In Vim you say "delete a word"
(`dw`); in Helix you "select a word, then delete" (`wd`). Here are the most common
translations:

| Task                          | Vim                       | Helix                                  |
| ----------------------------- | ------------------------- | -------------------------------------- |
| Delete a word                 | `dw`                      | `wd`                                   |
| Change a word                 | `cw`                      | `wc` or `ec`                           |
| Delete a character            | `x`                       | `d` (or `;d`)                          |
| Delete an entire line         | `dd`                      | `xd`                                   |
| Copy a line                   | `yy`                      | `Xy`                                   |
| Go to last line               | `G`                       | `ge`                                   |
| Go to line start / end        | `0` / `$`                 | `gh` / `gl`                            |
| First non-blank               | `^`                       | `gs`                                   |
| Jump to matching bracket      | `%`                       | `mm`                                   |
| Select whole file             | `ggVG`                    | `%`                                    |
| Comment lines                 | `gc`                      | `Space c`                              |
| Autocomplete                  | `Ctrl-p`                  | `Ctrl-x`                               |
| Global replace                | `:%s/foo/bar/g`           | `%sfoo<ret>cbar<esc>,`                 |
| Replace in selection          | `:s/foo/bar/g`            | `sfoo<ret>cbar<esc>,`                  |
| Reload file                   | `:e`                      | `:reload`                              |
| Run shell command             | `:!cmd`                   | `:sh cmd` (or `!cmd` to insert output) |

> [!NOTE]
> Helix has no block-selection mode. Use multiple cursors instead: add cursors on lines below
> with `C`, then move them together. There are no named bookmarks; save a location to the
> jumplist with `Ctrl-s` and return via `Ctrl-o` / `Ctrl-i` or the jumplist picker
> (`Space j`).

---

## 20. Troubleshooting

The following entries combine Helix's documented behavior with real issues reported by the
community.

### Error: keys seem to insert random commands instead of text

**Cause:** You are in normal mode, where letter keys run commands.
**Solution:** Press `Esc` to ensure you are in normal mode, then press `i` to enter insert
mode before typing.
**Prevention:** Watch the mode indicator on the status line (`NOR`, `INS`, `SEL`).

### Error: `hx: command not found`

**Cause:** The binary is not on your `$PATH`, or your package manager installed it as
`helix` (notably Arch's `extra` repository).
**Solution:** Try running `helix`. Otherwise add the install location to `$PATH`. Verify with
`hx --health` (or `helix --health`).
**Prevention:** When using pre-built binaries or AppImages, install `hx` into a directory
already on your `PATH` such as `~/.local/bin`.

### Error: syntax highlighting or indentation is missing

**Cause:** The tree-sitter grammar for the language isn't built, or runtime files aren't
found.
**Solution:** Run `hx --health <language>` to check. Fetch and build grammars with
`hx --grammar fetch && hx --grammar build`, and confirm `HELIX_RUNTIME` points to a valid
`runtime` directory.
**Prevention:** When building from source, always configure the runtime directory (see
[Building from source](#building-from-source)).

### Error: language server features (`gd`, hover, completion) do nothing

**Cause:** No language server is installed/on `PATH`, or the workspace is untrusted.
**Solution:** Install the appropriate server and ensure it is on `$PATH`. Run `hx --health`
to confirm Helix detects it. Trust the workspace if prompted (`:workspace-trust`). Restart
the server with `:lsp-restart`.
**Prevention:** Consult the
[Language Server Configurations wiki](https://github.com/helix-editor/helix/wiki/Language-Server-Configurations).

### Error: some keybindings don't work in my terminal

**Cause:** Your terminal intercepts certain key combinations, or lacks support for the
enhanced keyboard protocol (this affects `Shift-Tab`, Super-key bindings, and some Alt
combinations).

> [!WARNING]
> A known long-standing example is **`Alt`/`Opt` + `_` not working on macOS**
> ([#2280](https://github.com/helix-editor/helix/issues/2280)). This is generally a
> terminal-level key-handling limitation rather than a Helix bug.

**Solution:** Check your terminal's key mappings for conflicts and, where available, enable
the enhanced/Kitty keyboard protocol. See the
[Terminal Support wiki](https://github.com/helix-editor/helix/wiki/Terminal-Support).
**Prevention:** Prefer a terminal with good protocol support (e.g. Kitty, WezTerm, recent
Alacritty/foot) for the smoothest binding experience.

### Error: the editor crashed or panicked

**Cause:** Certain edge cases have produced panics — for example navigating the jumplist
after `:reload-all` ([#13149](https://github.com/helix-editor/helix/issues/13149)) or
specific selection/change interactions
([#12582](https://github.com/helix-editor/helix/issues/12582)). Several such cases have been
fixed in recent releases.
**Solution:** Update to the latest release or nightly. If it still reproduces, capture the
log (`hx -v` for more verbosity, or `:log-open`) and file an issue with steps to reproduce.
**Prevention:** Keep Helix current; many crash fixes ship in each release.

### Error: opening a directory misbehaves

**Cause:** Passing a directory to `hx` opens the file picker / explorer; some platform edge
cases have been reported ([#14785](https://github.com/helix-editor/helix/issues/14785)).
**Solution:** Open a specific file, or use `Space f` from within Helix. Update to the latest
version.

### Where is the log file?

Open it with `:log-open`, or start Helix with a custom path: `hx --log /tmp/helix.log` and
`tail -f /tmp/helix.log` in another terminal. Increase verbosity with repeated `-v` flags
(`hx -vv`).

---

## 21. Frequently Asked Questions

**Q: Do I need to install plugins to be productive?**
No. LSP, tree-sitter syntax highlighting, multiple cursors, fuzzy pickers, and a debugger
client are all built in. A formal plugin system is planned but not required for everyday use.

**Q: How do I learn the editing model quickly?**
Run `hx --tutor` (or `:tutor`). It is an interactive, hands-on tutorial and the fastest way
to internalize selection-first editing.

**Q: How do I save and quit?**
`:w` saves, `:q` quits, `:wq` (or `:x`) does both. `:wqa` saves all buffers and closes all
views.

**Q: Why don't `:%s/foo/bar/` and other `:substitute`-style commands exist?**
Helix expresses replacement through multiple selections: `%sfoo<ret>cbar<esc>,`. See
[Search and Replace](#6-search-and-replace).

**Q: How do I copy to the system clipboard?**
Use space-mode clipboard commands: `Space y` to yank, `Space p`/`Space P` to paste. Or yank
to the `+` register directly (`"+y`).

**Q: How do I change the theme without editing my config?**
Run `:theme <name>` and use `Tab` to browse available themes interactively.

**Q: Where do my config files go?**
`~/.config/helix/config.toml` and `languages.toml` on Linux/macOS;
`%AppData%\helix\` on Windows. Project-local overrides go in a `.helix/` folder.

**Q: How do I reload my config without restarting?**
`:config-reload`. On Unix you can also send `USR1`: `pkill -USR1 hx`.

**Q: Can I use Helix like a non-modal editor?**
Insert mode includes a few movement and editing keys (arrows, `Ctrl-w` to delete a word) for
newcomers, but Helix is designed around modal editing and you will get the best experience by
learning it. You can disable the insert-mode arrow keys once comfortable.

**Q: How do I add a trailing character to many lines at once?**
`x` to select a line (repeat to extend), or `%` for the whole file, then `Alt-s` to split on
newlines (a cursor per line), then `A`, type the character, `Esc`.

**Q: How do I see every command and its keybinding?**
Open the command palette with `Space ?`, or consult the [Reference](#22-reference) below.

**Q: What languages are supported?**
Several hundred, via tree-sitter grammars, with language-server support for most mainstream
languages. See the [language support matrix](#language-support).

**Q: My Alt/Shift/Super keybindings don't register — is Helix broken?**
Usually not. This is a terminal key-handling limitation. Enable the enhanced keyboard
protocol in your terminal where possible, and check the Terminal Support wiki.

---

## 22. Reference

### Command-line flags

`hx [FLAGS] [files]` — open files by passing paths. A path may include a position:
`file.rs:10:2` opens at line 10, column 2; `+N file` opens at line N; `+` opens at the last
line.

| Flag                    | Description                                                   |
| ----------------------- | ----------------------------------------------------------- |
| `-h`, `--help`          | Print help                                                   |
| `-V`, `--version`       | Print version                                                |
| `--tutor`               | Open the interactive tutorial                                |
| `--health [LANG]`       | Print health info (optionally for one language)             |
| `-g`, `--grammar fetch` | Fetch tree-sitter grammars                                   |
| `-g`, `--grammar build` | Build tree-sitter grammars                                   |
| `-c`, `--config <PATH>` | Use a specific config file                                   |
| `--log <PATH>`          | Write the log to a specific path                             |
| `-w`, `--working-dir <PATH>` | Set the initial working directory                       |
| `--vsplit`              | Open files in vertical splits                                |
| `--hsplit`              | Open files in horizontal splits                              |
| `--strict`              | Enforce strict parsing (fail on unknown config)             |
| `-v`                    | Increase verbosity (repeatable: `-vv`, `-vvv`)              |
| `--`                    | Treat all following arguments as file paths                  |

### Keymap reference

Bindings marked **(LSP)** require a language server; **(TS)** require a tree-sitter grammar.

#### Movement (normal mode)

| Key | Command | Key | Command |
| --- | ------- | --- | ------- |
| `h` `Left` | move left | `l` `Right` | move right |
| `j` `Down` | move down (visual line) | `k` `Up` | move up (visual line) |
| `w` / `b` / `e` | next/prev word start, next word end | `W` / `B` / `E` | same for WORDs |
| `f` / `t` | find / till next char | `F` / `T` | find / till previous char |
| `<n>G`, `<n>gg` | go to line `<n>` | `Alt-.` | repeat last motion |
| `Ctrl-u` / `Ctrl-d` | half page up / down | `Ctrl-b` / `Ctrl-f` | page up / down |
| `Ctrl-i` / `Ctrl-o` | jump forward / backward | `Ctrl-s` | save selection to jumplist |
| `Home` / `End` | line start / end | | |

#### Changes (normal mode)

| Key | Command | Key | Command |
| --- | ------- | --- | ------- |
| `r` | replace char | `R` | replace with yanked |
| `i` / `a` | insert before / after | `I` / `A` | insert at line start / end |
| `o` / `O` | open line below / above | `.` | repeat last insert |
| `u` / `U` | undo / redo | `Alt-u` / `Alt-U` | earlier / later in history |
| `y` / `p` / `P` | yank / paste after / before | `"<reg>` | select register |
| `>` / `<` | indent / unindent | `=` | format (LSP) |
| `d` / `Alt-d` | delete / delete no-yank | `c` / `Alt-c` | change / change no-yank |
| `Ctrl-a` / `Ctrl-x` | increment / decrement | `Ctrl-c` | toggle comments |
| `~` / `` ` `` / `` Alt-` `` | toggle / lower / upper case | `J` | join lines |
| `Q` / `q` | record / replay macro | | |

#### Selection manipulation

| Key | Command | Key | Command |
| --- | ------- | --- | ------- |
| `s` | select regex matches | `S` | split on regex |
| `Alt-s` | split on newlines | `&` | align in columns |
| `_` | trim whitespace | `;` | collapse to cursor |
| `Alt-;` | flip cursor/anchor | `,` / `Alt-,` | keep / remove primary |
| `C` / `Alt-C` | add cursor below / above | `(` / `)` | rotate primary back / forward |
| `Alt-(` / `Alt-)` | rotate contents back / forward | `%` | select whole file |
| `x` / `X` | extend line below / to bounds | `Alt-x` | shrink to line bounds |
| `K` / `Alt-K` | keep / remove matching regex | `J` | join lines |
| `Alt-o` / `Alt-i` | expand / shrink syntax node (TS) | `Alt-p` / `Alt-n` | prev / next sibling (TS) |

#### Minor-mode entry keys (normal mode)

| Key | Enters | Key | Enters |
| --- | ------ | --- | ------ |
| `v` | select/extend mode | `g` | goto mode |
| `m` | match mode | `:` | command mode |
| `z` / `Z` | view / sticky view mode | `Ctrl-w` | window mode |
| `Space` | space mode | | |

#### Goto mode (`g`)

| Key | Goes to | Key | Goes to |
| --- | ------- | --- | ------- |
| `g` | file start (or line `<n>`) | `e` | file end |
| `h` / `l` | line start / end | `s` | first non-whitespace |
| `d` (LSP) | definition | `y` (LSP) | type definition |
| `r` (LSP) | references | `i` (LSP) | implementation |
| `t` / `c` / `b` | window top / center / bottom | `a` / `m` | last accessed / modified file |
| `n` / `p` | next / previous buffer | `.` | last modification |
| `f` | file/URL under selection | `w` | jump to a two-char label |

#### Space mode (`Space`) — pickers and LSP

| Key | Action | Key | Action |
| --- | ------ | --- | ------ |
| `f` / `F` | file picker (root / cwd) | `b` | buffer picker |
| `j` | jumplist picker | `g` | changed-file picker |
| `s` / `S` | document / workspace symbols | `d` / `D` | document / workspace diagnostics |
| `k` (LSP) | hover docs | `r` (LSP) | rename symbol |
| `a` (LSP) | code action | `h` (LSP) | select symbol references |
| `/` | global search | `?` | command palette |
| `y` / `Y` | yank to clipboard / main to clipboard | `p` / `P` | paste clipboard after / before |
| `R` | replace from clipboard | `'` | last picker |
| `c` / `C` | comment / block-comment | `w` | window mode |

#### View mode (`z` / sticky `Z`)

| Key | Action | Key | Action |
| --- | ------ | --- | ------ |
| `z`/`c` | center line | `t` / `b` | align top / bottom |
| `j` / `k` | scroll down / up | `Ctrl-d` / `Ctrl-u` | half page down / up |

#### Match mode (`m`)

| Key | Action |
| --- | ------ |
| `m` | go to matching bracket (TS) |
| `s<char>` | surround add |
| `r<from><to>` | surround replace |
| `d<char>` | surround delete |
| `a<object>` / `i<object>` | select around / inside textobject |

#### Window mode (`Ctrl-w`)

| Key | Action | Key | Action |
| --- | ------ | --- | ------ |
| `v` / `s` | vertical / horizontal split | `q` / `o` | close / close others |
| `h/j/k/l` | move between splits | `H/J/K/L` | swap splits |
| `w` | next window | | |

#### Insert-mode keys

| Key | Action | Key | Action |
| --- | ------ | --- | ------ |
| `Esc` | normal mode | `Ctrl-x` | autocomplete |
| `Ctrl-r` | insert register | `Ctrl-w` / `Alt-Backspace` | delete previous word |
| `Alt-d` | delete next word | `Ctrl-u` / `Ctrl-k` | delete to line start / end |
| `Ctrl-s` | commit undo checkpoint | `Tab` / `Shift-Tab` | smart-tab / insert tab |

#### Unimpaired (bracket) motions

| Key | Goes to | Key | Goes to |
| --- | ------- | --- | ------- |
| `]d` / `[d` (LSP) | next / prev diagnostic | `]f` / `[f` (TS) | next / prev function |
| `]t` / `[t` (TS) | next / prev type | `]a` / `[a` (TS) | next / prev argument |
| `]c` / `[c` (TS) | next / prev comment | `]T` / `[T` (TS) | next / prev test |
| `]p` / `[p` | next / prev paragraph | `]g` / `[g` | next / prev change |
| `]Space` / `[Space` | add line below / above | | |

### Typable command reference

Run these from the command line (`:`). Aliases are shown after the canonical name.

| Command | Aliases | Description |
| ------- | ------- | ----------- |
| `:quit` | `:q` | Close the current view |
| `:quit!` | `:q!` | Force close, discarding changes |
| `:open` | `:o`, `:edit`, `:e` | Open a file |
| `:write` | `:w` | Write changes to disk (optional path) |
| `:write!` | `:w!` | Write, creating directories |
| `:write-quit` | `:wq`, `:x` | Write and close the view |
| `:write-quit-all` | `:wqa`, `:xa` | Write all and close all views |
| `:write-all` | `:wa` | Write all buffers |
| `:quit-all` | `:qa` | Close all views |
| `:update` | `:u` | Write only if modified |
| `:new` | `:n` | Create a new scratch buffer |
| `:reload` | `:rl` | Discard changes, reload from disk |
| `:reload-all` | `:rla` | Reload all documents |
| `:buffer-close` | `:bc`, `:bclose` | Close the current buffer |
| `:buffer-next` / `:buffer-previous` | `:bn` / `:bp` | Next / previous buffer |
| `:format` | `:fmt` | Format with formatter or LSP |
| `:vsplit` / `:hsplit` | `:vs` / `:hs`, `:sp` | Open file in vertical / horizontal split |
| `:goto` | `:g` | Go to a line number |
| `:theme` | | Change the theme (shows current if no name) |
| `:set-option` | `:set` | Set a config option at runtime |
| `:toggle-option` | `:toggle` | Toggle a config option |
| `:get-option` | `:get` | Read a config option's value |
| `:set-language` | `:lang` | Set the buffer's language |
| `:config-open` / `:config-reload` | | Open / reload your config |
| `:config-open-workspace` | | Open the workspace config |
| `:log-open` | | Open the Helix log file |
| `:sort` | | Sort ranges in the selection (`--reverse` to flip) |
| `:reflow` | | Hard-wrap selected lines to a width |
| `:indent-style` | | Set indentation (`t` for tabs, or 1–16 spaces) |
| `:line-ending` | | Set line ending (`crlf` / `lf`) |
| `:encoding` | | Set the file encoding |
| `:earlier` / `:later` | `:ear` / `:lat` | Jump back / forward in edit history |
| `:clipboard-yank` / `:clipboard-paste-after` | | System-clipboard yank / paste |
| `:lsp-restart` / `:lsp-stop` | | Restart / stop language servers |
| `:lsp-workspace-command` | | Open the workspace command picker |
| `:pipe` / `:pipe-to` | `:\|` | Pipe selections to a shell command |
| `:insert-output` / `:append-output` | | Run a command, insert / append output |
| `:run-shell-command` | `:sh`, `:!` | Run a shell command |
| `:tutor` | | Open the tutorial |
| `:change-current-directory` | `:cd` | Change the working directory |
| `:show-directory` | `:pwd` | Show the working directory |
| `:move` | `:mv` | Move the buffer and its file to a new path |
| `:read` | `:r` | Read a file into the buffer |
| `:set-register` / `:clear-register` | | Set / clear a register |
| `:character-info` | `:char` | Info about the character under the cursor |
| `:workspace-trust` / `:workspace-untrust` | | Trust / untrust the current workspace |
| `:cquit` | `:cq` | Quit with an exit code |
| `:redraw` | | Re-render the whole UI |
| `:echo` / `:noop` | | Print to the statusline / do nothing |

> [!NOTE]
> This is the everyday subset. Every command also appears in the in-editor **command
> palette** (`Space ?`), which always reflects your exact version, including
> debugger (`:debug-*`) and tree-sitter inspection (`:tree-sitter-*`) commands.

### Static command reference

Static commands are the building blocks you bind keys to (see
[Key Remapping](#15-key-remapping)). They number in the hundreds; below is an
orientation by category. For the complete list with current default bindings, open the
command palette (`Space ?`) or see the source `static_commands!` macro in
[`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs).

| Category            | Representative commands                                                       |
| ------------------- | ---------------------------------------------------------------------------- |
| Movement            | `move_char_left/right`, `move_next_word_start`, `move_prev_word_end`, `goto_line` |
| Extension (select)  | `extend_char_left/right`, `extend_next_word_start`, `extend_to_line_bounds`   |
| Sub-word movement   | `move_next_sub_word_start`, `move_prev_sub_word_end` (unbound by default)     |
| Changes             | `delete_selection`, `change_selection`, `replace`, `undo`, `redo`, `indent`  |
| Selection           | `select_regex`, `split_selection`, `keep_selections`, `align_selections`     |
| Syntax (TS)         | `expand_selection`, `shrink_selection`, `select_next_sibling`, `match_brackets` |
| Search              | `search`, `search_next`, `global_search`, `search_selection`                 |
| Clipboard/registers | `yank`, `yank_to_clipboard`, `paste_after`, `select_register`, `insert_register` |
| LSP                 | `goto_definition`, `hover`, `code_action`, `rename_symbol`, `signature_help` |
| Pickers             | `file_picker`, `buffer_picker`, `command_palette`, `jumplist_picker`         |
| Windows             | `vsplit`, `hsplit`, `jump_view_left`, `swap_view_down`, `wclose`             |
| Shell               | `shell_pipe`, `shell_insert_output`, `shell_keep_pipe`, `suspend`            |
| Debugger (DAP)      | `dap_launch`, `dap_toggle_breakpoint`, `dap_continue`, `dap_step_in`         |
| Misc                | `no_op`, `increment`, `decrement`, `record_macro`, `replay_macro`, `goto_word` |

### Language support

Helix supports several hundred languages through tree-sitter, with per-language capabilities
that vary across **syntax highlighting**, **tree-sitter textobjects**, **auto-indent**, **code
navigation tags**, **rainbow brackets**, and **default language servers**. A few examples:

| Language | Highlight | Textobjects | Auto-indent | Default LSP |
| -------- | :-------: | :---------: | :---------: | ----------- |
| Rust     | ✓ | ✓ | ✓ | `rust-analyzer` |
| C / C++  | ✓ | ✓ | ✓ | `clangd` |
| Go       | ✓ | ✓ | ✓ | `gopls` |
| Python   | ✓ | ✓ | ✓ | `pylsp` / `ruff` |
| TypeScript | ✓ | ✓ | ✓ | `typescript-language-server` |
| Bash     | ✓ | ✓ | ✓ | `bash-language-server` |

To see the full, version-accurate matrix for your build, consult the generated language
support page in the Helix book, or run `hx --health <language>` for a specific language.

---

_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._
