You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
helix/book/src/usage.md

7.9 KiB

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.

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 register a.
  • "op - Paste the text in register o 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 register h and then change it (delete and enter insert mode).
  • "md - Store the selection in register m 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:

Surround demo

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]:

  1. % to select the whole file
  2. s to split the selections on a search term
  3. Input use and hit Enter
  4. 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.

Textobject demo Textobject tree-sitter demo

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

Tree-sitter-nav-demo

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.