7.9 KiB
Using Helix
- Registers
- Surround
- Selecting and manipulating text with textobjects
- Navigating using tree-sitter textobjects
- Moving the selection with syntax-aware motions
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.
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:
"ay
- Yank the current selection to registera
."op
- Paste the text in registero
after the selection.
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 registerh
and then change it (delete and enter insert mode)."md
- Store the selection in registerm
and delete it.
Special registers
Register character | Contains |
---|---|
/ |
Last search |
: |
Last executed command |
" |
Last yanked text |
_ |
Black hole |
The system clipboard is not directly supported by a special register. Instead, special commands and keybindings are provided. Refer to the key map for more details.
The black hole register is a no-op register, meaning that no data will be read or written to it.
Surround
Helix includes built-in functionality similar to vim-surround. The keymappings have been inspired from vim-sandwich:
Key Sequence | Action |
---|---|
ms<char> (after selecting text) |
Add surround characters to selection |
mr<char_to_replace><new_char> |
Replace the closest surround characters |
md<char_to_delete> |
Delete the closest surround characters |
You can use counts to act on outer pairs.
Surround can also act on multiple selections. For example, to change every occurrence of (use)
to [use]
:
%
to select the whole files
to split the selections on a search term- Input
use
and hit Enter mr([
to replace the parentheses with square brackets
Multiple characters are currently not supported, but planned for future release.
Selecting and manipulating text with textobjects
In Helix, textobjects are a way to select, manipulate and operate on a piece of text in a structured way. They allow you to refer to blocks of text based on their structure or purpose, such as a word, sentence, paragraph, or even a function or block of code.
ma
- Select around the object (va
in Vim,<alt-a>
in Kakoune)mi
- Select inside the object (vi
in Vim,<alt-i>
in Kakoune)
Key after mi or ma |
Textobject selected |
---|---|
w |
Word |
W |
WORD |
p |
Paragraph |
( , [ , ' , etc. |
Specified surround pairs |
m |
The closest surround pair |
f |
Function |
c |
Class |
a |
Argument/parameter |
o |
Comment |
t |
Test |
g |
Change |
💡
f
,c
, 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!
Navigating using tree-sitter textobjects
Navigating between functions, classes, parameters, and other elements is
possible using tree-sitter and textobject queries. For
example to move to the next function use ]f
, to move to previous
class use [c
, and so on.
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.
Moving the selection with syntax-aware motions
Alt-p
, Alt-o
, Alt-i
, and Alt-n
(or Alt
and arrow keys) allow you to move the
selection according to its location in the syntax tree. For example, many languages have the
following syntax for function calls:
func(arg1, arg2, arg3);
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.
func[(arg1, arg2, arg3)];
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
.