Helix
Helix
html
Helix
Docs for bleeding edge master can be found at https://docs.helix-editor.com/master.
See the usage section for a quick overview of the editor, keymap section for all available
keybindings and the configuration section for defining custom keybindings, setting
themes, etc. For everything else (e.g., how to install supported language servers), see the
Helix Wiki.
Installing Helix
To install Helix, follow the instructions specific to your operating system. Note that:
▪ To get the latest nightly version of Helix, you need to build from source.
▪ To take full advantage of Helix, install the language servers for your preferred
programming languages. See the wiki for instructions.
Pre-built binaries
Download pre-built binaries from the GitHub Releases page. The tarball contents include
an hx binary and a runtime directory. To set up Helix:
1. Add the hx binary to your system's $PATH to allow it to be used from the
command line.
2. Copy the runtime directory to a location that hx searches for runtime files. A
typical location on Linux/macOS is ~/.config/helix/runtime .
To see the runtime directories that hx searches, run hx --health . If necessary, you can
override the default runtime location by setting the HELIX_RUNTIME environment
variable.
Package managers
▪ Linux
▪ Ubuntu
▪ Fedora/RHEL
▪ Arch Linux extra
▪ NixOS
▪ Flatpak
▪ Snap
▪ AppImage
▪ macOS
▪ Homebrew Core
▪ MacPorts
▪ Windows
▪ Winget
▪ Scoop
▪ Chocolatey
▪ MSYS2
Packaging status
Alpine Linux 3.16 22.03
Alpine Linux 3.17 22.08.1
Alpine Linux 3.18 23.03
Alpine Linux 3.19 23.10
Alpine Linux 3.20 24.03
Alpine Linux 3.21 24.07
Alpine Linux Edge 24.07
ALT Linux p10 24.07
ALT Linux p11 24.07
ALT Sisyphus 24.07
AOSC 24.07
Arch Linux 24.07
Arch Linux 32 i686 24.07
Arch Linux 32 pentium4 24.07
Arch Linux ARM aarch64 24.07
AUR 24.07.r114…
Artix 24.07
Baulk 25.01
Chimera Linux 24.07
Chocolatey 24.7.0
Chromebrew 22.12
EPEL 9 24.07
Fedora 37 23.10
Fedora 38 24.03
Fedora 39 24.07
Fedora 40 24.07
Fedora 41 24.07
Fedora Rawhide 24.07
FreeBSD Ports 25.01
Gentoo 24.07
Homebrew 25.01
LiGurOS stable 24.07
LiGurOS develop 24.07
MacPorts 25.01
Mageia 9 23.05
Mageia cauldron 24.03
Manjaro Stable 24.07
Manjaro Testing 24.07
Manjaro Unstable 24.07
MPR 24.03
MSYS2 clang64 24.07
MSYS2 clangarm64 24.07
MSYS2 mingw 24.07
MSYS2 ucrt64 24.07
nixpkgs stable 21.11 0.5.0
nixpkgs stable 22.05 22.03
nixpkgs stable 22.11 22.08.1
nixpkgs stable 23.05 23.05
nixpkgs stable 23.11 23.10
nixpkgs stable 24.05 24.03
Linux
The following third party repositories are available:
Ubuntu
Add the PPA for Helix:
Fedora/RHEL
When installed from the extra repository, run Helix with helix instead of hx .
For example:
helix --health
to check health
Additionally, a helix-git package is available in the AUR, which builds the master branch.
NixOS
Helix is available in nixpkgs through the helix attribute, the unstable channel usually
carries the latest release.
Helix is also available as a flake in the project root. Use nix develop to spin up a
reproducible development shell. Outputs are cached for each push to master using
Cachix. The flake is configured to automatically make use of this cache assuming the
user accepts the new settings on first use.
If you are using a version of Nix without flakes enabled, install Cachix CLI and use
cachix use helix to configure Nix to use cached outputs when possible.
Flatpak
Helix is available on Flathub:
Snap
Helix is available on Snapcraft and can be installed with:
This will install Helix as both /snap/bin/helix and /snap/bin/hx , so make sure /
snap/bin is in your PATH .
AppImage
Install Helix using the Linux AppImage format. Download the official Helix AppImage
from the latest releases page.
You can optionally add the .desktop file. Helix must be installed in PATH with the name
hx . For example:
mkdir -p "$HOME/.local/bin"
mv helix-*.AppImage "$HOME/.local/bin/hx"
macOS
Homebrew Core
MacPorts
Windows
Install on Windows using Winget, Scoop, Chocolatey or MSYS2.
Winget
Windows Package Manager winget command-line tool is by default available on
Windows 11 and modern versions of Windows 10 as a part of the App Installer. You can
get App Installer from the Microsoft Store. If it's already installed, make sure it is
updated with the latest version.
Scoop
Chocolatey
MSYS2
For 64-bit Windows 8.1 or above:
pacman -S mingw-w64-ucrt-x86_64-helix
Requirements:
Clone the Helix GitHub repository into a directory of your choice. The examples in this
documentation assume installation into either ~/src/ on Linux and macOS, or
%userprofile%\src\ on Windows.
If you are using the musl-libc standard library instead of glibc the following
environment variable must be set during the build to ensure tree-sitter grammars can be
loaded correctly:
RUSTFLAGS="-C target-feature=-crt-static"
This command will create the hx executable and construct the tree-sitter
grammars in the local runtime folder.
The runtime directory is one below the Helix source, so either export a HELIX_RUNTIME
environment variable to point to that directory and add it to your ~/.bashrc or
equivalent:
export HELIX_RUNTIME=~/src/helix/runtime
If the above command fails to create a symbolic link because the file exists either move
~/.config/helix/runtime to a new location or delete it, then run the symlink command
above again.
Windows
Either set the HELIX_RUNTIME environment variable to point to the runtime files using
the Windows setting (search for Edit environment variables for your account ) or
use the setx command in Cmd:
Or, create a symlink in %appdata%\helix\ that links to the source code directory:
Method Command
Method Command
cd %appdata%\helix
Cmd
mklink /D runtime "%userprofile%\src\helix\runtime"
When Helix finds multiple runtime directories it will search through them for files in the
following order:
This order also sets the priority for selecting which file will be used if multiple runtime
directories have files with the same name.
Note to packagers
If you are making a package of Helix for end users, to provide a good out of the box
experience, you should set the HELIX_DEFAULT_RUNTIME environment variable at build
time (before invoking cargo build ) to a directory which will store the final runtime files
after installation. For example, say you want to package the runtime into /usr/lib/
helix/runtime . The rough steps a build script could follow are:
1. export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime
2. cargo build --profile opt --locked
3. cp -r runtime $BUILD_DIR/usr/lib/helix/
4. cp target/opt/hx $BUILD_DIR/usr/bin/hx
This way the resulting hx binary will always look for its runtime directory in /usr/lib/
helix/runtime if the user has no custom runtime in ~/.config/helix or
HELIX_RUNTIME .
To make sure everything is set up as expected you should run the Helix health check:
hx --health
For more information on the health check results refer to Health check.
cp contrib/Helix.desktop ~/.local/share/applications
cp contrib/helix.png ~/.icons # or ~/.local/share/icons
It is recommended to convert the links in the .desktop file to absolute paths to avoid
potential problems:
To use another terminal than the system default, you can modify the .desktop file. For
example, to use kitty :
Using Helix
For a full interactive introduction to Helix, refer to the tutor which can be accessed via
the command hx --tutor or :tutor .
Currently, not all functionality is fully documented, please refer to the key
mappings list.
Modes
Helix is a modal editor, meaning it has different modes for different tasks. The main
modes are:
▪ Normal mode: For navigation and editing commands. This is the default mode.
▪ Insert mode: For typing text directly into the document. Access by typing i in
normal mode.
▪ Select/extend mode: For making selections and performing operations on them.
Access by typing v in normal mode.
Buffers
Buffers are in-memory representations of files. You can have multiple buffers open at
once. Use pickers or commands like :buffer-next and :buffer-previous to open
buffers or switch between them.
Selection-first editing
Inspired by Kakoune, Helix follows the selection → action model. This means that
whatever you are going to act on (a word, a paragraph, a line, etc.) is selected first and
the action itself (delete, change, yank, etc.) comes second. A cursor is simply a single
width selection.
Multiple selections
Also inspired by Kakoune, multiple selections are a core mode of interaction in Helix. For
example, the standard way of replacing multiple instances of a word is to first select all
instances (so there is one selection per instance) and then use the change action ( c ) to
Motions
Motions are commands that move the cursor or modify selections. They're used for
navigation and text manipulation. Examples include w to move to the next word, or f
to find a character. See the Movement section of the keymap for more motions.
Registers
▪ User-defined registers
▪ Default registers
▪ Special registers
In Helix, registers are storage locations for text and other data, such as the result of a
search. Registers can be used to cut, copy, and paste text, similar to the clipboard in
other text editors. Usage is similar to Vim, with " being used to select a register.
User-defined registers
Helix allows you to create your own named registers for storing text, for example:
If a register is selected before invoking a change or delete command, the selection will
be stored in the register and the action will be carried out:
▪ "hc - Store the selection in register h and then change it (delete and enter insert
mode).
▪ "md - Store the selection in register m and delete it.
Default registers
Commands that use registers, like yank ( y ), use a default register if none is specified.
These registers are used as defaults:
/ Last search
Special registers
Some registers have special behavior when read from and written to.
Register
When read When written
character
When yanking multiple selections to the clipboard registers, the selections are joined
with newlines. Pasting from these registers will paste multiple selections if the clipboard
was last yanked to by the Helix session. Otherwise the clipboard contents are pasted as
one selection.
Surround
Helix includes built-in functionality similar to vim-surround. The keymappings have been
inspired from vim-sandwich:
Surround can also act on multiple selections. For example, to change every occurrence of
(use) to [use] :
Multiple characters are currently not supported, but planned for future release.
w Word
W WORD
p Paragraph
f Function
a Argument/parameter
c Comment
T Test
g Change
f , t , etc. need a tree-sitter grammar active for the current document and a
special tree-sitter query file to work properly. Only some grammars currently have
the query file implemented. Contributions are welcome!
For the full reference see the unimpaired section of the key bind documentation.
This feature relies on tree-sitter textobjects and requires the corresponding query
file to work properly.
A function call might be parsed by tree-sitter into a tree like the following.
(call
function: (identifier) ; func
arguments:
(arguments ; (arg1, arg2, arg3)
(identifier) ; arg1
(identifier) ; arg2
(identifier))) ; arg3
Use :tree-sitter-subtree to view the syntax tree of the primary selection. In a more
intuitive tree format:
┌────┐
│call│
┌─────┴────┴─────┐
│ │
┌─────▼────┐ ┌────▼────┐
│identifier│ │arguments│
│ "func" │ ┌────┴───┬─────┴───┐
└──────────┘ │ │ │
│ │ │
┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐
│identifier│ │identifier│ │identifier│
│ "arg1" │ │ "arg2" │ │ "arg3" │
└──────────┘ └──────────┘ └──────────┘
If you have a selection that wraps arg1 (see the tree above), and you use Alt-n , it will
select the next sibling in the syntax tree: arg2 .
// before
func([arg1], arg2, arg3)
// after
func(arg1, [arg2], arg3);
Similarly, Alt-o will expand the selection to the parent node, in this case, the
arguments node.
There is also some nuanced behavior that prevents you from getting stuck on a node
with no sibling. When using Alt-p with a selection on arg1 , the previous child node
will be selected. In the event that arg1 does not have a previous sibling, the selection
will move up the syntax tree and select the previous element. As a result, using Alt-p
with a selection on arg1 will move the selection to the "func" identifier .
Using pickers
Helix has a variety of pickers, which are interactive windows used to select various kinds
of items. These include a file picker, global search picker, and more. Most pickers are
accessed via keybindings in space mode. Pickers have their own keymap for navigation.
If a picker shows multiple columns, you may apply the filter to a specific column by
prefixing the column name with % . Column names can be shortened to any prefix, so
%p , %pa or %pat all mean the same as %path . For example, a query of helix %p
.toml !lang in the global search picker searches for the term "helix" within files with
paths ending in ".toml" but not including "lang".
You can insert the contents of a register using Ctrl-r followed by a register name. For
example, one could insert the currently selected text using Ctrl-r - . , or the directory
of the current file using Ctrl-r - % followed by Ctrl-w to remove the last path section.
The global search picker will use the contents of the search register if you press Enter
without typing a filter. For example, pressing * - Space-/ - Enter will start a global
search for the currently selected text.
Keymap
▪ Normal mode
▪ Movement
▪ Changes
▪ Shell
▪ Selection manipulation
▪ Search
▪ Minor modes
▪ View mode
▪ Goto mode
▪ Match mode
▪ Window mode
▪ Space mode
▪ Popup
▪ Completion Menu
▪ Signature-help Popup
▪ Unimpaired
▪ Insert mode
▪ Select / extend mode
▪ Picker
▪ Prompt
Mappings marked (LSP) require an active language server for the file.
Mappings marked (TS) require a tree-sitter grammar for the file type.
Some terminals' default key mappings conflict with Helix's. If any of the mappings
described on this page do not work as expected, check your terminal's mappings to
ensure they do not conflict. See the wiki for known conflicts.
Normal mode
Normal mode is the default mode when you launch helix. You can return to it from other
modes by pressing the Escape key.
Movement
NOTE: Unlike Vim, f , F , t and T are not confined to the current line.
k , Up Move up move_visual_line_up
Ctrl-f ,
Move page down page_down
PageDown
Changes
"
Select a register to yank to or paste from select_register
<reg>
Shell
Selection manipulation
Comment/uncomment the
Ctrl-c toggle_comments
selections
Search
Search commands all operate on the / register by default. To use a different register,
use "<char> .
Minor modes
These sub-modes are accessible from normal mode and typically switch back to normal
mode after a command.
View mode
View mode is intended for scrolling and manipulating the view without changing the
selection. The "sticky" variant of this mode (accessed by typing Z in normal mode) is
persistent and can be exited using the escape key. This is useful when you're simply
looking over text and not actively editing it.
Ctrl-f ,
Move page down page_down
PageDown
Ctrl-b ,
Move page up page_up
PageUp
Goto mode
Match mode
Please refer to the relevant sections for detailed explanations about surround and
textobjects.
Window mode
This layer is similar to Vim keybindings as Kakoune does not support windows.
h , Ctrl-h ,
Move to left split jump_view_left
Left
j , Ctrl-j ,
Move to split below jump_view_down
Down
l , Ctrl-l ,
Move to right split jump_view_right
Right
Space mode
Comment/uncomment
c toggle_comments
selections
Block comment/uncomment
C toggle_block_comments
selections
Global search displays results in a fuzzy picker, use Space + ' to bring it back up
after opening a file.
Popup
Displays documentation for item under cursor. Remapping currently not supported.
Key Description
Ctrl-u Scroll up
Completion Menu
Displays documentation for the selected completion item. Remapping currently not
supported.
Key Description
Signature-help Popup
Displays the signature of the selected completion item. Remapping currently not
supported.
Key Description
Unimpaired
Insert mode
Accessed by typing i in normal mode.
Insert mode bindings are minimal by default. Helix is designed to be a modal editor, and
this is reflected in the user experience and internal mechanics. Changes to the text are
only saved for undos when escaping from insert mode to normal mode.
New users are strongly encouraged to learn the modal editing paradigm to get
the smoothest experience.
Switch to normal
Escape normal_mode
mode
Commit undo
Ctrl-s commit_undo_checkpoint
checkpoint
Insert a register
Ctrl-r insert_register
content
These keys are not recommended, but are included for new users less familiar with
modal editors.
As you become more comfortable with modal editing, you may want to disable some
insert mode bindings. You can do this by editing your config.toml file.
[keys.insert]
up = "no_op"
down = "no_op"
left = "no_op"
right = "no_op"
pageup = "no_op"
pagedown = "no_op"
home = "no_op"
end = "no_op"
Select mode echoes Normal mode, but changes any movements to extend selections
rather than replace them. Goto motions are also changed to extend, so that vgl , for
example, extends the selection to the end of the line.
Search is also affected. By default, n and N will remove the current selection and select
the next instance of the search term. Toggling this mode before pressing n or N makes
it possible to keep the current selection. Toggling it on and off during your iterative
searching allows you to selectively add search terms to your selections.
Picker
Keys to use within picker. Remapping currently not supported. See the documentation
page on pickers for more info. Prompt keybinds also work in pickers, except where they
conflict with picker keybinds.
Key Description
Prompt
Keys to use within prompt, Remapping currently not supported.
Key Description
Key Description
Commands
▪ Typable commands
▪ Static commands
Typable commands
Typable commands are used from command mode and may take arguments. Command
mode can be activated by pressing : . The built-in typable commands are:
Name Description
:quit! , :q! Force close the current view, ignoring unsaved changes.
:open , :o , :edit , :e Open a file from disk into the current view.
:buffer-close , :bc ,
Close the current buffer.
:bclose
:buffer-close-others ,
Close all buffers but the currently focused one.
:bco , :bcloseother
:buffer-close-
others! , :bco! , Force close all buffers but the currently focused one.
:bcloseother!
:buffer-close-all ,
Close all buffers without quitting.
:bca , :bcloseall
:buffer-next , :bn ,
Goto next buffer.
:bnext
:buffer-previous ,
Goto previous buffer.
:bp , :bprev
Name Description
Set the indentation style for editing. ('t' for tabs or 1-16 for
:indent-style
number of spaces.)
:line-ending Set the document's default line ending. Options: crlf, lf.
:write-quit! , :wq! , Write changes to disk and close the current view forcefully.
:x! Accepts an optional path (:wq! some/path.txt)
:write-quit-all ,
Write changes from all buffers to disk and close all views.
:wqa , :xa
:write-quit-all! , Write changes from all buffers to disk and close all views
:wqa! , :xa! forcefully (ignoring unsaved changes).
Name Description
:primary-clipboard-
Yank main selection into system primary clipboard.
yank
:clipboard-paste-
Paste system clipboard after selections.
after
:clipboard-paste-
Paste system clipboard before selections.
before
:clipboard-paste-
Replace selections with content of system clipboard.
replace
:primary-clipboard-
Paste primary clipboard after selections.
paste-after
:primary-clipboard-
Paste primary clipboard before selections.
paste-before
:show-clipboard-
Show clipboard provider name in status bar.
provider
:change-current-
Change the current working directory.
directory , :cd
Name Description
:show-directory ,
Show the current working directory.
:pwd
:character-info ,
Get info about the character under the primary cursor.
:char
:reload , :rl Discard changes and reload from the source file.
:lsp-workspace-
Open workspace command picker
command
:lsp-stop Stops the language servers that are used by the current doc
:tree-sitter-
Display name of tree-sitter highlight scope under the cursor.
highlight-name
Name Description
:config-open-
Open the workspace config.toml file.
workspace
:run-shell-command ,
Run a shell command
:sh
:reset-diff-change ,
Reset the diff change at the cursor position.
:diffget , :diffg
Name Description
Static Commands
Static commands take no arguments and can be bound to keys. Static commands can
also be executed from the command picker ( <space>? ). The built-in static commands
are:
no_op Do nothing
normal: h ,
move_char_left Move left <left> , insert:
<left>
normal: l ,
move_char_right Move right <right> , insert:
<right>
normal: k , <up> ,
move_visual_line_up Move up
insert: <up>
normal: j ,
move_visual_line_down Move down <down> , insert:
<down>
select: l ,
extend_char_right Extend right
<right>
Move to start of
move_next_word_start normal: w
next word
Move to start of
move_prev_word_start normal: b
previous word
Move to end of
move_next_word_end normal: e
next word
Move to end of
move_prev_word_end
previous word
Move to start of
move_next_long_word_start normal: W
next long word
Move to start of
move_prev_long_word_start previous long normal: B
word
Move to end of
move_next_long_word_end normal: E
next long word
Move to end of
move_prev_long_word_end previous long
word
Move to start of
move_next_sub_word_start
next sub word
Move to start of
move_prev_sub_word_start previous sub
word
Move to end of
move_next_sub_word_end
next sub word
Move to end of
move_parent_node_end normal: <A-e>
the parent node
Move to
move_parent_node_start beginning of the normal: <A-b>
parent node
Extend to start
extend_next_word_start select: w
of next word
Extend to start
extend_prev_word_start of previous select: b
word
Extend to end of
extend_next_word_end select: e
next word
Extend to end of
extend_prev_word_end
previous word
Extend to start
extend_next_long_word_start of next long select: W
word
Extend to start
extend_prev_long_word_start of previous long select: B
word
Extend to end of
extend_next_long_word_end select: E
next long word
Extend to end of
extend_prev_long_word_end
prev long word
Extend to start
extend_next_sub_word_start of next sub
word
Extend to start
extend_prev_sub_word_start of previous sub
word
Extend to end of
extend_next_sub_word_end
next sub word
Extend to end of
extend_prev_sub_word_end
prev sub word
Extend to end of
extend_parent_node_end select: <A-e>
the parent node
Extend to
extend_parent_node_start beginning of the select: <A-b>
parent node
Move to next
find_next_char occurrence of normal: f
char
Extend to next
extend_next_char occurrence of select: f
char
Move till
previous
till_prev_char normal: T
occurrence of
char
Move to
previous
find_prev_char normal: F
occurrence of
char
Extend till
previous
extend_till_prev_char select: T
occurrence of
char
Extend to
previous
extend_prev_char select: F
occurrence of
char
normal: <C-b> ,
Z<C-b> , z<C-b> ,
<pageup> ,
Z<pageup> ,
z<pageup> , select:
page_up Move page up <C-b> , Z<C-b> ,
z<C-b> ,
<pageup> ,
Z<pageup> ,
z<pageup> , insert:
<pageup>
normal: <C-f> ,
Z<C-f> , z<C-f> ,
<pagedown> ,
Z<pagedown> ,
z<pagedown> ,
Move page select: <C-f> ,
page_down
down Z<C-f> , z<C-f> ,
<pagedown> ,
Z<pagedown> ,
z<pagedown> ,
insert:
<pagedown>
normal: <C-u> ,
Z<C-u> , z<C-u> ,
Z<backspace> ,
Move page and z<backspace> ,
page_cursor_half_up
cursor half up select: <C-u> ,
Z<C-u> , z<C-u> ,
Z<backspace> ,
z<backspace>
normal: <C-d> ,
Z<C-d> , z<C-d> ,
Z<space> ,
Move page and
z<space> , select:
page_cursor_half_down cursor half
<C-d> , Z<C-d> ,
down
z<C-d> ,
Z<space> ,
z<space>
Split selections
normal: S , select:
split_selection on regex
S
matches
normal: <A-
Merge
merge_selections minus> , select:
selections
<A-minus>
Merge
normal: <A-_> ,
merge_consecutive_selections consecutive
select: <A-_>
selections
normal: / , Z/ ,
Search for regex
search z/ , select: / ,
pattern
Z/ , z/
normal: n , Zn ,
Select next
search_next zn , select: Zn ,
search match
zn
normal: N , ZN ,
Select previous
search_prev zN , select: ZN ,
search match
zN
Add previous
extend_search_prev search match to select: N
selection
Use current
normal: <A-*> ,
search_selection selection as
select: <A-*>
search pattern
Use current
selection as the
search pattern,
normal: * , select:
search_selection_detect_word_boundaries automatically
*
wrapping with
\b on word
boundaries
Modify current
make_search_word_bounded search to make
it word bounded
Global search in
normal: <space>/ ,
global_search workspace
select: <space>/
folder
Select current
line, if already normal: x , select:
extend_line_below
selected, extend x
to next line
Select current
line, if already
extend_line_above
selected, extend
to previous line
Select current
line, if already
selected, extend
select_line_above
or shrink line
above based on
the anchor
Select current
line, if already
selected, extend
select_line_below
or shrink line
below based on
the anchor
normal: d , select:
delete_selection Delete selection
d
Change
normal: <A-c> ,
change_selection_noyank selection
select: <A-c>
without yanking
Collapse
normal: ; , select:
collapse_selection selection into
;
single cursor
Flip selection
normal: <A-;> ,
flip_selections cursor and
select: <A-;>
anchor
Ensure all
normal: <A-:> ,
ensure_selections_forward selections face
select: <A-:>
forward
normal: <space>f ,
file_picker Open file picker
select: <space>f
Open
normal: <space>S ,
workspace_symbol_picker workspace
select: <space>S
symbol picker
Open
workspace normal: <space>D ,
workspace_diagnostics_picker
diagnostic select: <space>D
picker
normal: <space>' ,
last_picker Open last picker
select: <space>'
normal: <esc> ,
Enter normal
normal_mode select: v , insert:
mode
<esc>
Enter selection
select_mode normal: v
extend mode
Exit selection
exit_select_mode select: <esc>
mode
normal: gd ,
goto_definition Goto definition
select: gd
Goto normal: gD ,
goto_declaration
declaration select: gD
Goto normal: gi ,
goto_implementation
implementation select: gi
Goto line
normal: gg ,
goto_file_start number else file
select: gg
start
normal: <C-w>f ,
Goto files in
<space>wf , select:
goto_file_hsplit selections
<C-w>f ,
(hsplit)
<space>wf
normal: <C-w>F ,
Goto files in
<space>wF , select:
goto_file_vsplit selections
<C-w>F ,
(vsplit)
<space>wF
normal: gr ,
goto_reference Goto references
select: gr
normal: G , select:
goto_line Goto line
G
normal: ge ,
goto_last_line Goto last line
select: ge
normal: gh ,
<home> , select:
goto_line_start Goto line start
gh , insert:
<home>
normal: gl ,
goto_line_end Goto line end
<end> , select: gl
normal: gn ,
goto_next_buffer Goto next buffer
select: gn
Goto newline at
goto_line_end_newline insert: <end>
line end
Extend to line
extend_to_line_start select: <home>
start
Extend to first
extend_to_first_nonwhitespace non-blank in
line
Extend to line
extend_to_line_end select: <end>
end
Extend to line
extend_to_line_end_newline
end
Show signature
signature_help
help
insert: <C-h> ,
Delete previous
delete_char_backward <backspace> ,
char
<S-backspace>
insert: <C-d> ,
delete_char_forward Delete next char
<del>
normal: u , select:
undo Undo change
u
normal: U , select:
redo Redo change
U
Commit
commit_undo_checkpoint changes to new insert: <C-s>
checkpoint
normal: y , select:
yank Yank selection
y
Yank selections
yank_to_primary_clipboard to primary
clipboard
Yank main
normal: <space>Y ,
yank_main_selection_to_clipboard selection to
select: <space>Y
clipboard
Yank main
selection to
yank_main_selection_to_primary_clipboard
primary
clipboard
Replace
selections by normal: <space>R ,
replace_selections_with_clipboard
clipboard select: <space>R
content
Replace
selections by
replace_selections_with_primary_clipboard
primary
clipboard
Paste clipboard
normal: <space>P ,
paste_clipboard_before before
select: <space>P
selections
Paste primary
paste_primary_clipboard_after clipboard after
selections
Paste primary
paste_primary_clipboard_before clipboard before
selections
normal: <gt> ,
indent Indent selection
select: <gt>
Remove
normal: <A-K> ,
remove_selections selections
select: <A-K>
matching regex
Invoke
completion completion insert: <C-x>
popup
normal:
Line comment/
<space><A-c> ,
toggle_line_comments uncomment
select:
selections
<space><A-c>
Block comment/
normal: <space>C ,
toggle_block_comments uncomment
select: <space>C
selections
Rotate
normal: ) , select:
rotate_selections_forward selections
)
forward
Rotate
normal: ( , select:
rotate_selections_backward selections
(
backward
Rotate selection
normal: <A-)> ,
rotate_selection_contents_forward contents
select: <A-)>
forward
Rotate
selections normal: <A-(> ,
rotate_selection_contents_backward
contents select: <A-(>
backward
Reverse
reverse_selection_contents selections
contents
Expand
normal: <A-o> ,
selection to
expand_selection <A-up> , select:
parent syntax
<A-o> , <A-up>
node
Shrink selection
normal: <A-i> ,
to previously
shrink_selection <A-down> , select:
expanded
<A-i> , <A-down>
syntax node
normal: <A-n> ,
Select next
<A-right> , select:
select_next_sibling sibling in the
<A-n> , <A-
syntax tree
right>
Select all
normal: <A-a> ,
select_all_siblings siblings of the
select: <A-a>
current node
normal: <C-i> ,
Jump forward
jump_forward <tab> , select:
on jumplist
<C-i> , <tab>
Save current
normal: <C-s> ,
save_selection selection to
select: <C-s>
jumplist
normal: <C-w>l ,
<space>wl , <C-
w><C-l> , <C-
w><right> ,
<space>w<C-l> ,
Jump to right <space>w<right> ,
jump_view_right
split select: <C-w>l ,
<space>wl , <C-
w><C-l> , <C-
w><right> ,
<space>w<C-l> ,
<space>w<right>
normal: <C-w>h ,
<space>wh , <C-
w><C-h> , <C-
w><left> ,
<space>w<C-h> ,
<space>w<left> ,
jump_view_left Jump to left split
select: <C-w>h ,
<space>wh , <C-
w><C-h> , <C-
w><left> ,
<space>w<C-h> ,
<space>w<left>
normal: <C-w>j ,
<space>wj , <C-
w><C-j> , <C-
w><down> ,
<space>w<C-j> ,
Jump to split <space>w<down> ,
jump_view_down
below select: <C-w>j ,
<space>wj , <C-
w><C-j> , <C-
w><down> ,
<space>w<C-j> ,
<space>w<down>
normal: <C-w>L ,
Swap with right <space>wL , select:
swap_view_right
split <C-w>L ,
<space>wL
normal: <C-w>H ,
Swap with left <space>wH , select:
swap_view_left
split <C-w>H ,
<space>wH
normal: <C-w>K ,
Swap with split <space>wK , select:
swap_view_up
above <C-w>K ,
<space>wK
normal: <C-w>J ,
Swap with split <space>wJ , select:
swap_view_down
below <C-w>J ,
<space>wJ
normal: <C-w>w ,
<space>ww , <C-
w><C-w> ,
Goto next <space>w<C-w> ,
rotate_view
window select: <C-w>w ,
<space>ww , <C-
w><C-w> ,
<space>w<C-w>
Goto previous
rotate_view_reverse
window
normal: <C-w>s ,
<space>ws , <C-
w><C-s> ,
Horizontal <space>w<C-s> ,
hsplit
bottom split select: <C-w>s ,
<space>ws , <C-
w><C-s> ,
<space>w<C-s>
normal: <C-w>ns ,
<space>wns , <C-
w>n<C-s> ,
Horizontal
<space>wn<C-s> ,
hsplit_new bottom split
select: <C-w>ns ,
scratch buffer
<space>wns , <C-
w>n<C-s> ,
<space>wn<C-s>
normal: <C-w>v ,
<space>wv , <C-
w><C-v> ,
Vertical right <space>w<C-v> ,
vsplit
split select: <C-w>v ,
<space>wv , <C-
w><C-v> ,
<space>w<C-v>
normal: <C-w>q ,
<space>wq , <C-
w><C-q> ,
<space>w<C-q> ,
wclose Close window
select: <C-w>q ,
<space>wq , <C-
w><C-q> ,
<space>w<C-q>
normal: <C-w>o ,
<space>wo , <C-
w><C-o> ,
Close windows <space>w<C-o> ,
wonly
except current select: <C-w>o ,
<space>wo , <C-
w><C-o> ,
<space>w<C-o>
normal: Zt , zt ,
align_view_top Align view top
select: Zt , zt
normal: Zc , Zz ,
Align view
align_view_center zc , zz , select:
center
Zc , Zz , zc , zz
normal: Zk , zk ,
Z<up> , z<up> ,
scroll_up Scroll view up
select: Zk , zk ,
Z<up> , z<up>
normal: ms ,
surround_add Surround add
select: ms
Surround normal: mr ,
surround_replace
replace select: mr
normal: md ,
surround_delete Surround delete
select: md
normal: ]T ,
goto_next_test Goto next test
select: ]T
normal:
Launch debug
dap_launch <space>Gl , select:
target
<space>Gl
Restart normal:
dap_restart debugging <space>Gr , select:
session <space>Gr
normal:
Toggle
dap_toggle_breakpoint <space>Gb , select:
breakpoint
<space>Gb
Continue normal:
dap_continue program <space>Gc , select:
execution <space>Gc
normal:
Pause program
dap_pause <space>Gh , select:
execution
<space>Gh
normal:
dap_step_in Step in <space>Gi , select:
<space>Gi
normal:
dap_step_out Step out <space>Go , select:
<space>Go
normal:
dap_next Step to next <space>Gn , select:
<space>Gn
normal:
dap_variables List variables <space>Gv , select:
<space>Gv
normal:
End debug
dap_terminate <space>Gt , select:
session
<space>Gt
normal:
Edit breakpoint
<space>G<C-c> ,
dap_edit_condition condition on
select:
current line
<space>G<C-c>
normal:
Edit breakpoint
<space>G<C-l> ,
dap_edit_log log message on
select:
current line
<space>G<C-l>
normal:
Switch current <space>Gst ,
dap_switch_thread
thread select:
<space>Gst
normal:
Switch stack <space>Gsf ,
dap_switch_stack_frame
frame select:
<space>Gsf
Enable normal:
dap_enable_exceptions exception <space>Ge , select:
breakpoints <space>Ge
Disable normal:
dap_disable_exceptions exception <space>GE , select:
breakpoints <space>GE
Pipe selections
normal: | , select:
shell_pipe through shell
|
command
Pipe selections
into shell normal: <A-|> ,
shell_pipe_to
command select: <A-|>
ignoring output
Append shell
command normal: <A-!> ,
shell_append_output
output after select: <A-!>
selections
Filter selections
normal: $ , select:
shell_keep_pipe with shell
$
predicate
normal: <space>r ,
rename_symbol Rename symbol
select: <space>r
normal: Q , select:
record_macro Record macro
Q
normal: q , select:
replay_macro Replay macro
q
Jump to a two-
goto_word normal: gw
character label
Extend to a two-
extend_to_word select: gw
character label
goto next
goto_next_tabstop snippet
placeholder
goto next
goto_prev_tabstop snippet
placeholder
Language Support
The following languages and Language Servers are supported. To use Language Server
features, you must first configure the appropriate Language Server.
You can check the language support in your installed helix version with hx --health .
Also see the Language Configuration docs and the Adding Languages guide for more
language configuration information.
ada ✓ ✓ ada_language_server
adl ✓ ✓ ✓
agda ✓
amber ✓
astro ✓
awk ✓ ✓ awk-language-server
bash ✓ ✓ ✓ bash-language-server
bass ✓ bass
beancount ✓
bibtex ✓ texlab
bicep ✓ bicep-langserver
bitbake ✓ bitbake-language-server
blade ✓
blueprint ✓ blueprint-compiler
c ✓ ✓ ✓ clangd
c-sharp ✓ ✓ OmniSharp
haskell-language-server-
cabal
wrapper
cairo ✓ ✓ ✓ cairo-language-server
capnp ✓ ✓
cel ✓
circom ✓ circom-lsp
clojure ✓ clojure-lsp
cmake ✓ ✓ ✓ cmake-language-server
comment ✓
common-lisp ✓ ✓ cl-lsp
cpon ✓ ✓
cpp ✓ ✓ ✓ clangd
crystal ✓ ✓ crystalline
vscode-css-language-
css ✓ ✓
server
cue ✓ cuelsp
cylc ✓ ✓ ✓
d ✓ ✓ ✓ serve-d
dart ✓ ✓ ✓ dart
dbml ✓
devicetree ✓
dhall ✓ ✓ dhall-lsp-server
diff ✓
docker-compose-
docker-compose ✓ ✓ ✓ langserver , yaml-
language-server
dockerfile ✓ ✓ docker-langserver
dot ✓ dot-language-server
dtd ✓
dune ✓
earthfile ✓ ✓ ✓ earthlyls
edoc ✓
eex ✓
ejs ✓
elisp ✓
elixir ✓ ✓ ✓ elixir-ls
elm ✓ ✓ elm-language-server
elvish ✓ elvish
env ✓ ✓
erb ✓
esdl ✓
fidl ✓
fish ✓ ✓ ✓
forth ✓ forth-lsp
fortran ✓ ✓ fortls
fsharp ✓ fsautocomplete
gas ✓ ✓
gdscript ✓ ✓ ✓
gemini ✓
gherkin ✓
git-attributes ✓
git-commit ✓ ✓
git-config ✓ ✓
git-ignore ✓
git-rebase ✓
typescript-language-
server , vscode-eslint-
gjs ✓ ✓ ✓
language-server , ember-
language-server
gleam ✓ ✓ gleam
glimmer ✓ ember-language-server
glsl ✓ ✓ ✓ glsl_analyzer
gn ✓
gopls , golangci-lint-
go ✓ ✓ ✓
langserver
godot-resource ✓ ✓
gomod ✓ gopls
gotmpl ✓ gopls
gowork ✓ gopls
gpr ✓ ada_language_server
graphql ✓ ✓ graphql-lsp
groovy ✓
typescript-language-
server , vscode-eslint-
gts ✓ ✓ ✓
language-server , ember-
language-server
hare ✓
haskell-language-server-
haskell ✓ ✓
wrapper
haskell-
✓
persistent
hcl ✓ ✓ ✓ terraform-ls
heex ✓ ✓ elixir-ls
helm ✓ helm_ls
hocon ✓ ✓ ✓
hoon ✓
hosts ✓
vscode-html-language-
html ✓
server , superhtml
hurl ✓ ✓ ✓
hyprlang ✓ ✓ hyprls
idris idris2-lsp
iex ✓
ini ✓
inko ✓ ✓ ✓
janet ✓
java ✓ ✓ ✓ jdtls
typescript-language-
javascript ✓ ✓ ✓
server
jinja ✓
jjdescription ✓
jq ✓ ✓ jq-lsp
jsdoc ✓
vscode-json-language-
json ✓ ✓ ✓
server
json5 ✓
vscode-json-language-
jsonc ✓ ✓
server
jsonnet ✓ jsonnet-language-server
typescript-language-
jsx ✓ ✓ ✓
server
julia ✓ ✓ ✓ julia
just ✓ ✓ ✓
kdl ✓ ✓ ✓
koka ✓ ✓ koka
kotlin ✓ kotlin-language-server
koto ✓ ✓ ✓ koto-ls
latex ✓ ✓ texlab
ld ✓ ✓
ldif ✓
lean ✓ lean
ledger ✓
llvm ✓ ✓ ✓
llvm-mir ✓ ✓ ✓
llvm-mir-yaml ✓ ✓
log ✓
lpf ✓
lua ✓ ✓ ✓ lua-language-server
make ✓ ✓
markdoc ✓ markdoc-ls
markdown.inline ✓
matlab ✓ ✓ ✓
mermaid ✓
meson ✓ ✓ mesonlsp
mint mint
mojo ✓ ✓ ✓ magic
move ✓
msbuild ✓ ✓
nasm ✓ ✓
nestedtext ✓ ✓ ✓
nginx ✓
nickel ✓ ✓ nls
nim ✓ ✓ ✓ nimlangserver
nu ✓ nu
nunjucks ✓
ocaml ✓ ✓ ocamllsp
ocaml-interface ✓ ocamllsp
odin ✓ ✓ ✓ ols
ohm ✓ ✓ ✓
opencl ✓ ✓ ✓ clangd
openscad ✓ openscad-lsp
org ✓
pascal ✓ ✓ pasls
passwd ✓
pem ✓
perl ✓ ✓ ✓ perlnavigator
pest ✓ ✓ ✓ pest-language-server
php ✓ ✓ ✓ intelephense
php-only ✓
pkgbuild-language-server ,
pkgbuild ✓ ✓ ✓
bash-language-server
pkl ✓ ✓
po ✓ ✓
pod ✓
ponylang ✓ ✓ ✓
powershell ✓
prisma ✓ ✓ prisma-language-server
prolog swipl
protobuf ✓ ✓ ✓ bufls , pb
prql ✓
purescript-language-
purescript ✓ ✓
server
ruff , jedi-language-
python ✓ ✓ ✓
server , pylsp
qml ✓ ✓ qmlls
quint ✓ quint-language-server
r ✓ R
racket ✓ ✓ racket
regex ✓
rego ✓ regols
rescript ✓ ✓ rescript-language-server
rmarkdown ✓ ✓ R
robot ✓ robotframework_ls
ron ✓ ✓
rst ✓
ruby ✓ ✓ ✓ solargraph
rust ✓ ✓ ✓ rust-analyzer
sage ✓ ✓
scala ✓ ✓ ✓ metals
scheme ✓ ✓
vscode-css-language-
scss ✓
server
slint ✓ ✓ ✓ slint-lsp
smali ✓ ✓
smithy ✓ cs
sml ✓
snakemake ✓ ✓ pylsp
solidity ✓ ✓ solc
spade ✓ ✓ spade-language-server
spicedb ✓
sql ✓ ✓
sshclientconfig ✓
starlark ✓ ✓
strace ✓
supercollider ✓
svelte ✓ ✓ svelteserver
sway ✓ ✓ ✓ forc
swift ✓ ✓ sourcekit-lsp
t32 ✓
tablegen ✓ ✓ ✓
tact ✓ ✓ ✓
task ✓
tcl ✓ ✓
teal ✓
templ ✓ templ
textproto ✓ ✓ ✓
tfvars ✓ ✓ terraform-ls
thrift ✓
todotxt ✓
toml ✓ ✓ taplo
tsq ✓ ts_query_ls
typescript-language-
tsx ✓ ✓ ✓
server
twig ✓
typescript-language-
typescript ✓ ✓ ✓
server
typespec ✓ ✓ ✓ tsp-server
ungrammar ✓
unison ✓ ✓ ✓
uxntal ✓
v ✓ ✓ ✓ v-analyzer
vala ✓ ✓ vala-language-server
vento ✓
verilog ✓ ✓ svlangserver
vhdl ✓ vhdl_ls
vhs ✓
vue ✓ vue-language-server
wast ✓
wat ✓
webc ✓
wgsl ✓ wgsl_analyzer
wit ✓ ✓
wren ✓ ✓ ✓
xit ✓
xml ✓ ✓
xtc ✓
yaml-language-server ,
yaml ✓ ✓ ✓
ansible-language-server
yuck ✓
zig ✓ ✓ ✓ zls
See also Kakoune's Migrating from Vim and Helix's Migrating from Vim.
Configuration
To override global configuration parameters, create a config.toml file located in your
config directory:
You can easily open the config file by typing :config-open within Helix normal
mode.
Example config:
theme = "onedark"
[editor]
line-number = "relative"
mouse = false
[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "underline"
[editor.file-picker]
hidden = false
You can use a custom configuration file by specifying it with the -c or --config
command line argument, for example hx -c path/to/custom-config.toml . You can
reload the config file by issuing the :config-reload command. Alternatively, on Unix
operating systems, you can reload it by sending the USR1 signal to the Helix process,
such as by using the command pkill -USR1 hx .
Finally, you can have a config.toml local to a project by putting it under a .helix
directory in your repository. Its settings will be merged with the configuration directory
config.toml and the built-in configuration.
Editor
▪ [editor] Section
▪ [editor.statusline] Section
▪ [editor.lsp] Section
▪ [editor.cursor-shape] Section
▪ [editor.file-picker] Section
▪ [editor.auto-pairs] Section
▪ [editor.search] Section
▪ [editor.whitespace] Section
▪ [editor.indent-guides] Section
▪ [editor.gutters] Section
▪ [editor.gutters.line-numbers] Section
▪ [editor.gutters.diagnostics] Section
▪ [editor.gutters.diff] Section
▪ [editor.gutters.spacer] Section
▪ [editor.soft-wrap] Section
▪ [editor.smart-tab] Section
▪ [editor.inline-diagnostics] Section
[editor] Section
middle-
Middle click paste support true
click-paste
preview-
Whether to apply completion
completion- true
item instantly when selected
insert
[editor.clipboard-provider] Section
Helix can be configured either to use a builtin clipboard configuration or to use a
provided command.
For instance, setting it to use OSC 52 termcodes, the configuration would be:
[editor]
clipboard-provider = "termcode"
[editor.clipboard-provider.custom]
yank = { command = "cat", args = ["test.txt"] }
paste = { command = "tee", args = ["test.txt"] }
primary-yank = { command = "cat", args = ["test-primary.txt"] } # optional
primary-paste = { command = "tee", args = ["test-primary.txt"] } # optional
For custom commands the contents of the yank/paste is communicated over stdin/
stdout.
[editor.statusline] Section
Allows configuring the statusline at the bottom of the editor.
[ ... ... LEFT ... ... | ... ... ... CENTER ... ... ... | ... ... RIGHT ...
... ]
[editor.statusline]
left = ["mode", "spinner"]
center = ["file-name"]
right = ["diagnostics", "selections", "position", "file-encoding", "file-
line-ending", "file-type"]
separator = "│"
mode.normal = "NORMAL"
mode.insert = "INSERT"
mode.select = "SELECT"
Key Description
Key Description
workspace-
The number of warnings and/or errors on workspace
diagnostics
primary-selection-
The number of characters currently in primary selection
length
[editor.lsp] Section
display-signature-
Display docs under signature help popup true
help-docs
goto-reference-
Include declaration in the goto references popup. true
include-declaration
1 By default, a progress spinner is shown in the statusline beside the file path.
2 You may also have to activate them in the language server config for them to appear, not just in
Helix. Inlay hints in Helix are still being improved on and may be a little bit laggy/janky under some
circumstances. Please report any bugs you see so we can fix them!
[editor.cursor-shape] Section
Defines the shape of cursor in each mode. Valid values for these options are block ,
bar , underline , or hidden .
Due to limitations of the terminal environment, only the primary cursor can
change shape.
[editor.file-picker] Section
Set options for file picker and global search. Ignoring a file means it is not visible in the
Helix file picker and global search.
follow-
Follow symlinks instead of ignoring them true
symlinks
Ignore files can be placed locally as .ignore or put in your home directory as
~/.ignore . They support the usual ignore and negative ignore (unignore) rules used in
.gitignore files.
Additionally, you can use Helix-specific ignore files by creating a local .helix/ignore file
in the current workspace or a global ignore file located in your Helix config directory:
Example:
[editor.auto-pairs] Section
Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a simple
boolean value, or a specific mapping of pairs of single characters.
[editor]
auto-pairs = false # defaults to `true`
The default pairs are (){}[]''""`` , but these can be customized by setting auto-
pairs to a TOML table:
[editor.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'"' = '"'
'`' = '`'
'<' = '>'
Additionally, this setting can be used in a language config. Unless the editor setting is
false , this will override the editor config in documents with this language.
[[language]]
name = "rust"
[language.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'"' = '"'
'`' = '`'
'<' = '>'
[editor.auto-save] Section
Control auto save behavior.
[editor.search] Section
Search specific options.
wrap-
Whether the search should wrap after depleting the matches true
around
[editor.whitespace] Section
Options for rendering whitespace with visible characters. Use :set whitespace.render
all to temporarily enable visible whitespace.
Example
[editor.whitespace]
render = "all"
# or control each character
[editor.whitespace.render]
space = "all"
tab = "all"
nbsp = "none"
nnbsp = "none"
newline = "none"
[editor.whitespace.characters]
space = "·"
nbsp = "⍽"
nnbsp = "␣"
tab = "→"
newline = "⏎"
tabpad = "·" # Tabs will look like "→···" (depending on tab width)
[editor.indent-guides] Section
Options for rendering vertical indent guides.
Example:
[editor.indent-guides]
render = true
character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
skip-levels = 1
[editor.gutters] Section
For simplicity, editor.gutters accepts an array of gutter types, which will use default
settings for all gutter components.
[editor]
gutters = ["diff", "diagnostics", "line-numbers", "spacer"]
To customize the behavior of gutters, the [editor.gutters] section must be used. This
section contains top level settings, as well as settings for specific gutter components as
subsections.
Example:
[editor.gutters]
layout = ["diff", "diagnostics", "line-numbers", "spacer"]
[editor.gutters.line-numbers] Section
Example:
[editor.gutters.line-numbers]
min-width = 1
[editor.gutters.diagnostics] Section
Currently unused
[editor.gutters.diff] Section
The diff gutter option displays colored bars indicating whether a git diff represents
that a line was added, removed or changed. These colors are controlled by the theme
attributes diff.plus , diff.minus and diff.delta .
[editor.gutters.spacer] Section
Currently unused
[editor.soft-wrap] Section
Options for soft wrapping lines that exceed the view width:
Example:
[editor.soft-wrap]
enable = true
max-wrap = 25 # increase value to reduce forced mid-word wrapping
max-indent-retain = 0
wrap-indicator = "" # set wrap-indicator to "" to hide it
[editor.smart-tab] Section
Options for navigating and editing using tab key.
Due to lack of support for S-tab in some terminals, the default keybindings don't fully
embrace smart-tab editing experience. If you enjoy smart-tab navigation and a terminal
that supports the Enhanced Keyboard protocol, consider setting extra keybindings:
[keys.normal]
tab = "move_parent_node_end"
S-tab = "move_parent_node_start"
[keys.insert]
S-tab = "move_parent_node_start"
[keys.select]
tab = "extend_parent_node_end"
S-tab = "extend_parent_node_start"
[editor.inline-diagnostics] Section
Options for rendering diagnostics inside the text like shown below
fn main() {
let foo = bar;
└─ no such value in this scope
}
The allowed values for cursor-line and other-lines are: error , warning , info ,
hint .
The (first) diagnostic with the highest severity that is not shown inline is rendered at the
end of the line (as long as its severity is higher than the end-of-line-diagnostics
config option):
fn main() {
let baz = 1;
let foo = bar; a local variable with a similar name exists: baz
└─ no such value in this scope
}
The new diagnostic rendering is not yet enabled by default. As soon as end of line or
inline diagnostics are enabled the old diagnostics rendering is automatically disabled.
The recommended default setting are:
[editor]
end-of-line-diagnostics = "hint"
[editor.inline-diagnostics]
cursor-line = "warning" # show warnings and errors on the cursorline inline
Themes
To use a theme add theme = "<name>" to the top of your config.toml file, or select it
during runtime using :theme <name> .
Creating a theme
Create a file with the name of your theme as the file name (i.e mytheme.toml ) and place
it in your themes directory (i.e ~/.config/helix/themes or %AppData%\helix\themes
on Windows). The directory might have to be created beforehand.
The names "default" and "base16_default" are reserved for built-in themes and
cannot be overridden by user-defined themes.
Overview
Each line in the theme file is specified as below:
Where key represents what you want to style, fg specifies the foreground color, bg
the background color, underline the underline style / color , and modifiers is a list
of style modifiers. bg , underline and modifiers can be omitted to defer to the
defaults.
key = "#ffffff"
If the key contains a dot '.' , it must be quoted to prevent it being parsed as a dotted
key.
"key.key" = "#ffffff"
For inspiration, you can find the default theme.toml here and user-submitted themes
here.
Color palettes
It's recommended to define a palette of named colors, and refer to them in the
configuration values in your theme. To do this, add a table called palette to your theme
file:
"ui.background" = "white"
"ui.text" = "black"
[palette]
white = "#ffffff"
black = "#000000"
Keep in mind that the [palette] table includes all keys after its header, so it should be
defined after the normal theme options.
The default palette uses the terminal's default 16 colors, and the colors names are listed
below. The [palette] section in the config file takes precedence over it and is merged
into the default palette.
Color Name
default
black
red
green
yellow
blue
magenta
cyan
gray
light-red
light-green
light-yellow
light-blue
light-magenta
Color Name
light-cyan
light-gray
white
Modifiers
The following values may be used as modifier, provided they are supported by your
terminal emulator.
Modifier
bold
dim
italic
underlined
slow_blink
rapid_blink
reversed
hidden
crossed_out
Underline style
One of the following values may be used as a value for underline.style , providing it is
supported by your terminal emulator.
Modifier
line
Modifier
curl
dashed
dotted
double_line
Inheritance
Extend other themes by setting the inherits property to an existing theme.
inherits = "boo_berry"
Scopes
The following is a list of scopes available to use for styling:
Syntax highlighting
When determining styling for a highlight, the longest matching theme key will be used.
For example, if the highlight is function.builtin.static , the key function.builtin
will be used instead of function .
We use a similar set of scopes as Sublime Text. See also TextMate scopes.
▪ type - Types
▪ constructor
▪ builtin Special constants provided by the language ( true , false , nil etc)
▪ boolean
▪ character
▪ escape
▪ numeric (numbers)
▪ integer
▪ float
▪ string (TODO: string.quoted.{single, double}, string.raw/.unquoted)?
▪ punctuation
▪ control
▪ conditional - if , else
▪ repeat - for , while , loop
▪ import - import , export
▪ return
▪ exception
▪ operator - or , in
▪ directive - Preprocessor directives ( #if in C)
▪ function - fn , func
▪ storage - Keywords describing how things are stored
▪ type - The type of something, class , function , var , let , etc.
▪ modifier - Storage modifiers like static , mut , const , ref , etc.
▪ operator - || , += , >
▪ function
▪ builtin
▪ method
▪ private - Private methods that use a unique syntax (currently just
ECMAScript-based languages)
▪ macro
▪ special (preprocessor in C)
▪ tag - Tags (e.g. <body> in HTML)
▪ builtin
▪ namespace
▪ special
▪ markup
▪ heading
▪ marker
▪ 1 , 2 , 3 , 4 , 5 , 6 - heading text for h1 through h6
▪ list
▪ unnumbered
▪ numbered
▪ checked
▪ unchecked
▪ bold
▪ italic
▪ strikethrough
▪ link
▪ url - URLs pointed to by links
▪ label - non-URL link references
▪ text - URL and image descriptions in links
▪ quote
▪ raw
▪ inline
▪ block
▪ diff - version control changes
▪ plus - additions
▪ gutter - gutter indicator
▪ minus - deletions
▪ gutter - gutter indicator
▪ delta - modifications
▪ moved - renamed or moved files/changes
▪ conflict - merge conflicts
▪ gutter - gutter indicator
Interface
▪ markup
▪ normal
▪ completion - for completion doc popup UI
▪ hover - for hover popup UI
▪ heading
▪ completion - for completion doc popup UI
▪ hover - for hover popup UI
▪ raw
▪ inline
▪ completion - for completion doc popup UI
▪ hover - for hover popup UI
Key Notes
ui.background
ui.cursor
ui.cursor.normal
ui.cursor.insert
Key Notes
ui.cursor.select
ui.cursor.primary.normal
ui.cursor.primary.insert
ui.cursor.primary.select
ui.gutter Gutter
ui.statusline Statusline
Key Notes
Key Notes
ui.selection.primary
Key remapping
Helix currently supports one-way key remapping through a simple TOML configuration
file. (More powerful solutions such as rebinding via commands will be available in the
future).
To remap keys, create a config.toml file in your helix configuration directory (default
~/.config/helix on Linux systems) with a structure like this:
To set a modifier + key as a keymap, type A-X = ... or C-X = ... for Alt + X or
Ctrl + X. Combine with Shift using a dash, e.g. C-S-esc . Within macros, wrap them
in <> , e.g. <A-X> and <C-X> to distinguish from the A or C keys.
[keys.insert]
"A-x" = "normal_mode" # Maps Alt-X to enter normal mode
j = { k = "normal_mode" } # Maps `jk` to exit insert mode
Minor modes
Minor modes are accessed by pressing a key (usually from normal mode), giving access
to dedicated bindings. Bindings can be modified or added by nesting definitions.
[keys.insert.j]
k = "normal_mode" # Maps `jk` to exit insert mode
[keys.normal.g]
a = "code_action" # Maps `ga` to show possible code actions
The Super key - the Windows/Linux key or the Command key on Mac keyboards - is also
supported when using a terminal emulator that supports the enhanced keyboard
protocol. The super key is encoded with prefixes Meta- , Cmd- or Win- . These are all
synonyms for the super modifier - binding a key with a Win- modifier will mean it can
be used with the Windows/Linux key or the Command key.
[keys.normal]
C-s = ":write" # Ctrl and 's' to write
Cmd-s = ":write" # Cmd or Win or Meta and 's' to write
Backspace "backspace"
Space "space"
Return/Enter "ret"
Left "left"
Right "right"
Up "up"
Down "down"
Home "home"
End "end"
Page Up "pageup"
Tab "tab"
Delete "del"
Insert "ins"
Null "null"
Escape "esc"
[keys.normal]
"?" = ":write"
"!" = ":write"
"-" = ":write"
Note: - can't be used when combined with a modifier, for example Alt + - should be
written as A-minus . A-- is not accepted.
Languages
Language-specific settings and settings for language servers are configured in
languages.toml files.
languages.toml files
There are three possible locations for a languages.toml file:
1. In the Helix source code, which lives in the Helix repository. It provides the default
configurations for languages and language servers.
2. In your configuration directory. This overrides values from the built-in language
configuration. For example, to disable auto-formatting for Rust:
# in <config_dir>/helix/languages.toml
[language-server.mylang-lsp]
command = "mylang-lsp"
[[language]]
name = "rust"
auto-format = false
Language configuration
Each language is configured by adding a [[language]] section to a languages.toml
file. For example:
[[language]]
name = "mylang"
scope = "source.mylang"
injection-regex = "mylang"
file-types = ["mylang", "myl"]
comment-tokens = "#"
indent = { tab-width = 2, unit = " " }
formatter = { command = "mylang-formatter" , args = ["--stdin"] }
language-servers = [ "mylang-lsp" ]
Key Description
A set of marker files to look for when trying to find the workspace
roots
root. For example Cargo.lock , yarn.lock
block-comment- The start and end tokens for a multiline comment either an array
tokens or single table of { start = "/*", end = "*/"} . The first set of
tokens will be used for commenting, any pairs in the array can be
Key Description
uncommented
The indent to use. Has sub keys unit (the text inserted into the
indent document when indenting; usually set to N spaces or "\t" for
tabs) and tab-width (the number of spaces rendered for a tab)
The Language Servers used for this language. See below for more
language-
information in the section Configuring Language Servers for a
servers
language
The formatter for the language, it will take precedence over the lsp
formatter when defined. The formatter must be able to take the original file
as input from stdin and write the formatted file to stdout
soft-wrap editor.softwrap
Maximum line length. Used for the :reflow command and soft-
text-width wrapping if soft-wrap.wrap-at-text-width is set, defaults to
editor.text-width
When determining a language configuration to use, Helix searches the file-types with the
following priorities:
1. Glob: values in glob tables are checked against the full path of the given file. Globs
are standard Unix-style path globs (e.g. the kind you use in Shell) and can be used
to match paths for a specific prefix, suffix, directory, etc. In the above example, the
{ glob = "Makefile" } config would match files with the name Makefile , the {
glob = ".git/config" } config would match config files in .git directories,
and the { glob = ".github/workflows/*.yaml" } config would match any yaml
files in .github/workflow directories. Note that globs should always use the Unix
path separator / even on Windows systems; the matcher will automatically take
the machine-specific separators into account. If the glob isn't an absolute path or
doesn't already start with a glob prefix, */ will automatically be added to ensure it
matches for any subdirectory.
2. Extension: if there are no glob matches, any file-types string that matches the
file extension of a given file wins. In the example above, the "toml" config
matches files like Cargo.toml or languages.toml .
For example:
[language-server.mylang-lsp]
command = "mylang-lsp"
args = ["--stdio"]
config = { provideFormatter = true }
environment = { "ENV1" = "value1", "ENV2" = "value2" }
[language-server.efm-lsp-prettier]
command = "efm-langserver"
[language-server.efm-lsp-prettier.config]
documentFormatting = true
languages = { typescript = [ { formatCommand ="prettier --stdin-filepath
${INPUT}", formatStdin = true } ] }
Key Description
Key Description
required-root- A list of glob patterns to look for in the working directory. The
patterns language server is started if at least one of them is found.
A format sub-table within config can be used to pass extra formatting options to
Document Formatting Requests. For example, with typescript:
[language-server.typescript-language-server]
# pass format options according to https://github.com/typescript-language-
server/typescript-language-server#workspacedidchangeconfiguration omitting
the "[language].format." prefix.
config = { format = { "semicolons" = "insert",
"insertSpaceBeforeFunctionParenthesis" = true } }
Different languages can use the same language server instance, e.g. typescript-
language-server is used for javascript, jsx, tsx and typescript by default.
The definition order of language servers affects the order in the results list of code
action menu.
[[language]]
name = "typescript"
language-servers = [ { name = "efm-lsp-prettier", only-features = [ "format"
] }, "typescript-language-server" ]
or equivalent:
[[language]]
name = "typescript"
language-servers = [ { name = "typescript-language-server", except-features
= [ "format" ] }, "efm-lsp-prettier" ]
Each requested LSP feature is prioritized in the order of the language-servers array. For
example, the first goto-definition supported language server (in this case
typescript-language-server ) will be taken for the relevant LSP request (command
goto_definition ). The features diagnostics , code-action , completion , document-
symbols and workspace-symbols are an exception to that rule, as they are working for
all language servers at the same time and are merged together, if enabled for the
language. If no except-features or only-features is given, all features for the
language server are enabled. If a language server itself doesn't support a feature, the
next language server array entry will be tried (and so on).
▪ format
▪ goto-definition
▪ goto-declaration
▪ goto-type-definition
▪ goto-reference
▪ goto-implementation
▪ signature-help
▪ hover
▪ document-highlight
▪ completion
▪ code-action
▪ workspace-command
▪ document-symbols
▪ workspace-symbols
▪ diagnostics
▪ rename-symbol
▪ inlay-hints
[[grammar]]
name = "mylang"
source = { git = "https://github.com/example/mylang", rev =
"a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" }
Key Description
source The method of fetching the grammar - a table with a schema defined below
Where source is a table with either these keys when using a grammar from a git
repository:
Key Description
git A git remote URL from which the grammar should be cloned
A path within the grammar directory which should be built. Some grammar
repositories host multiple grammars (for example tree-sitter-
subpath typescript and tree-sitter-ocaml ) in subdirectories. This key is used to
point hx --grammar build to the correct path for compilation. When
omitted, the root of repository is used
Choosing grammars
You may use a top-level use-grammars key to control which grammars are fetched and
built when using hx --grammar fetch and hx --grammar build .
# Note: this key must come **before** the [[language]] and [[grammar]]
sections
use-grammars = { only = [ "rust", "c", "cpp" ] }
# or
use-grammars = { except = [ "yaml", "json" ] }
Guides
This section contains guides for adding new language server configurations, tree-sitter
grammars, textobject queries, and other similar items.
Language configuration
1. Add a new [[language]] entry in the languages.toml file and provide the
necessary configuration for the new language. For more information on language
configuration, refer to the language configuration section of the documentation. A
new language server can be added by extending the [language-server] table in
the same file.
2. If you are adding a new language or updating an existing language server
configuration, run the command cargo xtask docgen to update the Language
Support documentation.
If you are adding a new Language Server configuration, make sure to update the
Language Server Wiki with the installation instructions.
Grammar configuration
1. If a tree-sitter grammar is available for the new language, add a new [[grammar]]
entry to the languages.toml file.
2. If you are testing the grammar locally, you can use the source.path key with an
absolute path to the grammar. However, before submitting a pull request, make
sure to switch to using source.git .
Queries
1. In order to provide syntax highlighting and indentation for the new language, you
will need to add queries.
2. Create a new directory for the language with the path runtime/queries/<name>/ .
3. Refer to the tree-sitter website for more information on writing queries.
4. A list of highlight captures can be found on the themes page.
In Helix, the first matching query takes precedence when evaluating queries,
which is different from other editors such as Neovim where the last matching query
supersedes the ones before it. See this issue for an example.
Common issues
▪ If you encounter errors when running Helix after switching branches, you may
need to update the tree-sitter grammars. Run the command hx --grammar fetch
to fetch the grammars and hx --grammar build to build any out-of-date
grammars.
▪ If a parser is causing a segfault, or you want to remove it, make sure to remove the
compiled parser located at runtime/grammars/<name>.so .
▪ If you are attempting to add queries and Helix is unable to locate them, ensure that
the environment variable HELIX_RUNTIME is set to the location of the runtime
folder you're developing in.
Capture Name
function.inside
function.around
class.inside
class.around
test.inside
test.around
parameter.inside
comment.inside
comment.around
entry.inside
entry.around
▪ object.movement
▪ object.around
▪ object.inside
For example if a function.around capture has been already defined for a language in
its textobjects.scm file, function navigation should also work automatically.
function.movement should be defined only if the node captured by function.around
doesn't make sense in a navigation context.
Note that it matters where these added indents begin. For example, multiple indent level
increases that start on the same line only increase the total indent level by 1. See Capture
types.
By default, Helix uses the hybrid indentation heuristic. This means that indent queries
are not used to compute the expected absolute indentation of a line but rather the
expected difference in indentation between the new and an already existing line. This
difference is then added to the actual indentation of the already existing line. Since this
makes errors in the indent queries harder to find, it is recommended to disable it when
testing via :set indent-heuristic tree-sitter . The rest of this guide assumes that
the tree-sitter heuristic is used.
Indent queries
When Helix is inserting a new line through o , O , or <ret> , to determine the indent
level for the new line, the query in indents.scm is run on the document. The starting
position of the query is the end of the line above where a new line will be inserted.
For o , the inserted line is the line below the cursor, so that starting position of the query
is the end of the current line.
For O , the newly inserted line is the current line, so the starting position of the query is
the end of the line above the cursor.
From this starting node, the syntax tree is traversed up until the root node. Each indent
capture is collected along the way, and then combined according to their capture types
and scopes to a final indent level for the line.
Capture types
▪ @indent (default scope tail ): Increase the indent level by 1. Multiple occurrences
in the same line do not stack. If there is at least one @indent and one @outdent
capture on the same line, the indent level isn't changed at all.
▪ @outdent (default scope all ): Decrease the indent level by 1. The same rules as
for @indent apply.
▪ @indent.always (default scope tail ): Increase the indent level by 1. Multiple
occurrences on the same line do stack. The final indent level is @indent.always –
@outdent.always . If an @indent and an @indent.always are on the same line,
the @indent is ignored.
▪ @outdent.always (default scope all ): Decrease the indent level by 1. The same
rules as for @indent.always apply.
▪ @align (default scope all ): Align everything inside this node to some anchor. The
anchor is given by the start of the node captured by @anchor in the same pattern.
Every pattern with an @align should contain exactly one @anchor . Indent (and
outdent) for nodes below (in terms of their starting line) the @align node is added
to the indentation required for alignment.
▪ @extend : Extend the range of this node to the end of the line and to lines that are
indented more than the line that this node starts on. This is useful for languages
like Python, where for the purpose of indentation some nodes (like functions or
classes) should also contain indented lines that follow them.
▪ @extend.prevent-once : Prevents the first extension of an ancestor of this node.
For example, in Python a return expression always ends the block that it is in. Note
that this only stops the extension of the next @extend capture. If multiple
ancestors are captured, only the extension of the innermost one is prevented. All
other ancestors are unaffected (regardless of whether the innermost ancestor
would actually have been extended).
@indent / @outdent
fn shout(things: Vec<Thing>) {
// ↑
// ├───────────────────────╮ indent level
// @indent ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
// │
let it_all = |out| { things.filter(|thing| { // │ 1
// ↑ ↑ │
// ├───────────────────────┼─────┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄
// @indent @indent │
// │ 2
thing.can_do_with(out) // │
})}; // ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
//↑↑↑ │ 1
} //╰┼┴──────────────────────────────────────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄
// 3x @outdent
((block) @indent)
["}" ")"] @outdent
Note how on the second line, we have two blocks begin on the same line. In this case,
since both captures occur on the same line, they are combined and only result in a net
increase of 1. Also note that the closing } s are part of the @indent captures, but the 3
@outdent s also combine into 1 and result in that line losing one indent level.
@extend / @extend.prevent-once
For an example of where @extend can be useful, consider Python, which is whitespace-
sensitive.
]
(parenthesized_expression)
(function_definition)
(class_definition)
] @indent
class Hero:
def __init__(self, strong, fast, sure, soon):# ←─╮
self.is_strong = strong # │
self.is_fast = fast # ╭─── query start │
self.is_sure = sure # │ ╭─ cursor │
self.is_soon = soon # │ │ │
# ↑ ↑ │ │ │
# │ ╰──────╯ │ │
# ╰─────────────────────╯ │
# ├─ traversal
def need_hero(self, life): # │ start node
return ( # │
self.is_strong # │
and self.is_fast # │
and self.is_sure # │
and self.is_soon # │
and self > life # │
) # ←─────────────────────────────────────────╯
Without braces to catch the scope of the function, the smallest descendant of the cursor
on a line feed ends up being the entire inside of the class. Because of this, it will miss the
entire function node and its indent capture, leading to an indent level one too small.
To address this case, @extend tells helix to "extend" the captured node's span to the line
feed and every consecutive line that has a greater indent level than the line of the node.
(parenthesized_expression) @indent
]
(function_definition)
(class_definition)
] @indent @extend
class Hero:
def __init__(self, strong, fast, sure, soon):# ←─╮
self.is_strong = strong # │
self.is_fast = fast # ╭─── query start ├─ traversal
self.is_sure = sure # │ ╭─ cursor │ start node
self.is_soon = soon # │ │ ←───────────────╯
# ↑ ↑ │ │
# │ ╰──────╯ │
# ╰─────────────────────╯
def need_hero(self, life):
return (
self.is_strong
and self.is_fast
and self.is_sure
and self.is_soon
and self > life
)
Furthermore, there are some cases where extending to everything with a greater indent
level may not be desirable. Consider the need_hero function above. If our cursor is on
the last line of the returned expression.
class Hero:
def __init__(self, strong, fast, sure, soon):
self.is_strong = strong
self.is_fast = fast
self.is_sure = sure
self.is_soon = soon
In Python, the are a few tokens that will always end a scope, such as a return statement.
Since the scope ends, so should the indent level. But because the function span is
extended to every line with a greater indent level, a new line would just continue on the
same level. And an @outdent would not help us here either, since it would cause
everything in the parentheses to become outdented as well.
(parenthesized_expression) @indent
]
(function_definition)
(class_definition)
] @indent @extend
(return_statement) @extend.prevent-once
@indent.always / @outdent.always
As mentioned before, normally if there is more than one @indent or @outdent capture
on the same line, they are combined.
Sometimes, there are cases when you may want to ensure that every indent capture is
additive, regardless of how many occur on the same line. Consider this example in YAML.
- foo: bar
# ↑ ↑
# │ ╰─────────────── start of map
# ╰───────────────── start of list element
baz: quux # ←─── cursor
# ←───────────── where the cursor should go on a new line
garply: waldo
- quux:
bar: baz
xyzzy: thud
fred: plugh
In YAML, you often have lists of maps. In these cases, the syntax is such that the list
element and the map both start on the same line. But we really do want to start an
indentation for each of these so that subsequent keys in the map hang over the list and
align properly. This is where @indent.always helps.
((block_mapping_pair
key: (_) @key
value: (_) @val
(#not-same-line? @key @val)
) @indent.always @extend
)
Predicates
In some cases, an S-expression cannot express exactly what pattern should be matched.
For that, tree-sitter allows for predicates to appear anywhere within a pattern, similar to
how #set! declarations work:
(some_kind
(child_kind) @indent
(#predicate? arg1 arg2 ...)
)
The number of arguments depends on the predicate that's used. Each argument is either
a capture ( @name ) or a string ( "some string" ). The following predicates are supported
by tree-sitter:
▪ #eq? / #not-eq? : The first argument (a capture) must/must not be equal to the
second argument (a capture or a string).
▪ #match? / #not-match? : The first argument (a capture) must/must not match the
▪ #not-kind-eq? : The kind of the first argument (a capture) must not be equal to the
second argument (a string).
▪ #same-line? / #not-same-line? : The captures given by the 2 arguments must/
must not start on the same line.
▪ #one-line? / #not-one-line? : The captures given by the fist argument must/must
span a total of one line.
Scopes
Added indents don't always apply to the whole node. For example, in most cases when a
node should be indented, we actually only want everything except for its first line to be
indented. For this, there are several scopes (more scopes may be added in the future if
required):
▪ tail : This scope applies to everything except for the first line of the captured
node.
▪ all : This scope applies to the whole captured node. This is only different from
tail when the captured node is the first node on its line.
fn aha() { // ←─────────────────────────────────────╮
let take = "on me"; // ←──────────────╮ scope: │
let take = "me on"; // ├─ "tail" ├─ (block) @indent
let ill = be_gone_days(1 || 2); // │ │
} // ←───────────────────────────────────┴──────────┴─ "}" @outdent
// scope: "all"
((block) @indent
(#set! "scope" "tail"))
("}" @outdent
(#set! "scope" "all"))
As we can see, the "tail" scope covers the node, except for the first line. Everything up to
and including the closing brace gets an indent level of 1. Then, on the closing brace, we
encounter an outdent with a scope of "all", which means the first line is included, and the
indent level is cancelled out on this line. (Note these scopes are the defaults for @indent
and @outdent —they are written explicitly for demonstration.)
And example of a simple query that would highlight all strings as bash in Nix:
Capture Types
▪ @injection.language (standard): The captured node may contain the language
name used to highlight the node captured by @injection.content .
Settings
▪ injection.combined (standard): Indicates that all the matching nodes in the tree
should have their content parsed as one nested document.
▪ injection.language (standard): Forces the captured content to be highlighted as
the given language
▪ injection.include-children (standard): Indicates that the content node’s entire
text should be re-parsed, including the text of its child nodes. By default, child
nodes’ text will be excluded from the injected document.
▪ injection.include-unnamed-children (extension): Same as injection.include-
children but only for unnamed child nodes.
Predicates
▪ #eq? (standard): The first argument (a capture) must be equal to the second
argument (a capture or a string).
▪ #match? (standard): The first argument (a capture) must match the regex given in
the second argument (a string).
▪ #any-of? (standard): The first argument (a capture) must be one of the other
arguments (strings).