Skip to main content

Helix Editor

A cheatsheet for Rune's Helix-style editor. Helix inverts the vi grammar: a motion first selects the text you mean, then an operator acts on that selection. You press w then d to delete a word, not dw, and you always see what an operator is about to touch.

The : command mode lives at the Command Prompt: same prompt, broader scope.

Preset​

Enable it in config.yaml:

editor:
mode: "helix"

Where the helix editor applies​

Setting mode: "helix" does more than turn your file buffers modal; the same editor powers prompts and output surfaces throughout Rune, so the motions and operators on this page work everywhere:

  • The console. Rune's console uses it as the prompt editor, so you compose command lines with the full selection grammar.
  • The agent dialogue. In Rune Agent, the dialogue prompt becomes a helix editor.
  • Terminals. Terminals gain a modal mode: enter it to edit the prompt line, and treat the whole scrollback as a navigable buffer.
  • Task and command output. When a task finishes, or a one-shot plugin command (! command) completes, its output opens in a helix editor so you can scroll and navigate the results.

Selections come first​

Every range is an anchor and a head, and it is never empty: in normal mode the caret is itself a one-character selection, and that character can be a line ending. The one exception is the end of the document, after its last character, where the caret sits on an empty range. A motion in normal mode drops a fresh anchor and moves the head; in select mode (v) the anchor survives, so motions grow and flip the range.

foo bar baz w selects "foo " with the caret on the space
foo bar baz w d deletes "foo ", leaving "bar baz"
foo bar baz v w w selects "foo bar " (select mode keeps the anchor)

There can be any number of them: see Multiple selections. The syntax-tree sibling and parent motions (A-n, A-p, A-e, A-b, A-left, A-right) are left unbound, so they stay free for your own command.key_bindings.

Modes​

ModeEnterLeave
Normal<esc>—
Selectvv or <esc>
Inserti I a A o O c<esc>
Gotogany key (one shot)
Matchmany key (one shot)
Viewzany key (one shot)
View (sticky)Z<esc>
Bracket[ or ]any key (one shot)
Replacerany key (one shot)

Most operators drop select mode when they run, as Helix does. J, A-J and = deliberately keep it. p and P drop it too, but they leave the selection on the text it covered rather than on the pasted text.

Counts​

Type digits before a motion or operator to repeat it: 3w walks three words, 2x selects two lines, 3p pastes the register three times as one run.

Motions​

Character and line​

KeyMotion
h l / <left> <right>Left / right one character, crossing line endings
j k / <down> <up>Down / up one line
<home> / g hLine start
<end> / g lLine end
g sFirst non-blank on the line
g |Column n (with a count)

Word​

KeyMotion
w / bNext word start / previous word start
eNext word end
W / B / ESame, treating punctuation as word material

Word motions are a port of Helix's own word_move, so repeated presses walk forward exactly as Helix does, line endings re-anchor the selection onto the next word, and a motion that cannot move leaves the range untouched.

Find character on line​

KeyMotion
f{char} / F{char}Select forward / backward through {char}
t{char} / T{char}Select forward / backward up to {char}
A-.Repeat the last f / t / F / T

A miss leaves the selection alone. <space> and <tab> are accepted as the target character.

File, paragraph and brace​

KeyMotion
g gFirst line (or line n with a count)
g eLast line
{n}GLine n. Bare G is a no-op, as in Helix
] p / [ pNext / previous paragraph
m mMatching bracket
g t / g c / g bWindow top / centre / bottom
g k / g jLine up / down keeping the column
g .Last modification
KeyMotion
/ / ?Search forward / backward for a regex; the first match is selected as you type, <enter> confirms
n / NNext / previous match. In select mode every match joins the selection
*Make the selection the search pattern, anchored at word boundaries
A-*Make the selection the search pattern verbatim

Patterns are regular expressions, case-insensitive unless they contain an upper-case letter. n always walks forward and N backward, whichever of / and ? set the pattern, and both wrap around the document, reporting Wrapped around document or No more matches. * with several selections joins their texts with |, so n finds the next occurrence of any of them. The pattern lives in the / register.

Jumps​

KeyAction
g wLabel every visible word, then jump to the one whose two-character label you type
C-sPush the current selection onto the jumplist
C-o / C-i or <tab>Jump backward / forward

G, g \|, g . and a confirmed search push the position they left, so C-o walks back to it.

Helix's jumplist spans files; the editor's covers the file in front of you. The helix preset binds C-o and C-i to Rune's cursor history too, so once you reach either end of the file's jumplist, the next press carries on through the history into other files.

g w only labels words of two or more word characters, and never the word the caret is already on. Labels are ordered outward from the caret, so the nearest targets get the shortest ones. Any key that is not part of a live label cancels. In select mode g w extends the selection to the label instead of replacing it.

Language and Git navigation​

The helix editor answers these entries of the goto and bracket menus with Rune commands, whatever preset you load:

KeyAction
g d / g DGo to the definition / declaration
g y / g iGo to the type definition / implementation
g rReferences to the symbol
g n / g pNext / previous tab
] d / [ dNext / previous diagnostic
] g / [ gNext / previous Git change

Scrolling​

KeyAction
C-f / C-b, <pgdn> / <pgup>Page down / up
C-d / C-uHalf page down / up
z j / z k, C-e / C-yScroll one line down / up
z z or z cCentre the caret
z t / z bPut the caret at the top / bottom

z is one shot; Z keeps view mode until <esc>. Inside view mode, /, ?, n and N search, and <space> / <backspace> page by half screens.

Changing the selection​

KeyAction
vToggle select mode
;Collapse the selection onto the caret
A-;Flip anchor and head
A-:Force the selection forward
xSelect the whole line; repeats extend downwards
XSnap the selection out to whole lines
A-xDrop the partially covered first and last lines
%Select the whole file
_Trim whitespace off both ends
A-o / A-<up>Expand to the enclosing syntax node
A-i / A-<down>Shrink to the child syntax node

Multiple selections​

Every motion, operator and insert-mode key acts on all selections at once. One of them is the primary: it carries the terminal cursor, and the others show as dimmed ghost cursors over their reversed text. The message bar counts them Helix-style (2/5 sels: primary 2 of 5). Selections never overlap; two that touch merge into one.

Making selections​

KeyAction
C / A-CCopy every selection onto the next / previous line, on the same columns; lines too short to hold it are skipped
sSelect every regex match inside every selection
SSplit every selection on every regex match
A-sSplit every selection on line endings
K / A-KKeep / remove the selections whose text matches a regex
n / N in select modeAdd the next / previous search match
/ in select modeAdd the confirmed match

s, S, K and A-K open a prompt; the result is shown as you type and <esc> puts the selection back. s ^ puts a cursor on every line of the selection and % s {pattern} is the idiom for "every occurrence in the file". A pattern that selects nothing reports nothing selected; K and A-K report no selections remaining.

Managing selections​

KeyAction
,Keep only the primary
A-,Remove the primary
( / )Make the previous / next selection primary
A-( / A-)Rotate the text under the selections backward / forward
A-minusMerge everything into one selection
A-_Merge selections that touch
&Align: pad the n-th selection of every line onto the same column
; A-; A-: x X A-x _As in Changing the selection, on every selection

Operators and insert mode​

Operators fan out: d deletes every selection, > indents every line any selection touches (once), J joins after each one, r, ~, m s, C-a and the rest act per selection. o opens a line under each selection and leaves a cursor on every new line, and 3o opens three lines per selection with a cursor on each.

Yank stores one fragment per selection; a later p, P, R or C-r pairs the n-th fragment with the n-th selection, repeating the last fragment for any selection beyond that. A register written elsewhere pastes into all of them. The # register turns C-a into a running count: with three selections on 1, "#C-a writes 2, 3, 4.

Insert mode types at every selection: i puts a cursor at the start of each, a at the end of each, I and A at every line's edges, and every key on the insert mode table, a paste burst and C-r act at all of them. <esc> leaves one selection per cursor, and u undoes the whole session in one step, bringing every selection back.

foo bar %s\w+<enter> selects "foo" and "bar"
foo bar ( makes "foo" primary
foo bar , keeps "foo"

a C C three cursors, one per line
a iX<esc> every line now starts with X

Text objects​

m i {object} selects the inside, m a {object} includes the delimiters.

ObjectSelects
w / WWord / word including punctuation
pParagraph
mThe closest enclosing bracket pair
( ) { } [ ] < >That pair
" ' `That quote

Rune also accepts s for a sentence and the vi aliases b, B and t; Helix leaves those keys for its tree-sitter objects, which need a syntax service Rune's editor does not own.

Operators​

An operator acts on the current selection.

KeyAction
d / A-dDelete, with / without yanking
c / A-cChange, with / without yanking
yYank
p / PPaste after / before the selection. Lines pasted below an unterminated last line run on from its end
RReplace the selection with the register
r{char}Replace every character in the selection, line endings included
~Toggle case
` / A-` Lowercase / uppercase
J / A-JJoin lines / join and select the separator
> / <Indent / unindent
=Reindent to the syntax target
C-cToggle line comments
C-a / C-xIncrement / decrement the selected number or date
u / UUndo / redo
A-u / A-UUndo / redo, taking a count

c on a whole-line selection opens a fresh blank line instead of pulling the next line up, so x c leaves you a line to type on — the same behaviour as Helix's only_whole_lines branch.

C-a and C-x work on exactly the text under the selection, as they do in Helix: a cursor on one digit of 123 changes that digit alone, so select the whole number first (m i w). Decimal, 0x, 0o and 0b numbers keep their zero padding and _ separators, and a date or time such as 2021-12-31, 23:59 or Nov 24, 2021 moves by a day or a minute.

J keeps the selections where they were, dropping the indentation of the joined line and, when the file's language has line comments, the comment leader the first line already carries. A-J selects the separators instead.

Surround​

KeyAction
m s{char}Wrap the selection in {char}
m r{from}{to}Replace the surrounding {from} pair with {to}
m d{char}Delete the surrounding {char} pair

Adding lines​

KeyAction
] <space> / [ <space>Add a blank line below / above without leaving normal mode

Insert mode​

KeyEnters insert
i / aBefore / after the selection
I / AAt the first non-blank / at the line end
o / OOn a new line below / above
cAfter deleting the selection

The selection survives insert mode, as it does in Helix. i flips it so its cursor sits on its first cell, and the text you type goes in front of it: <esc> keeps the caret where it already was. a widens it one cell past its end so the text goes after it, and <esc> pulls that cell back off, leaving the selection over the original text plus what you typed. I, A, o, O and c start from a bare cursor, so <esc> lands on the cell after the last character inserted. a at the very end of a file with no final line ending adds one, so there is a cell to widen onto.

While inserting:

KeyAction
<esc>Back to normal mode
C-sCommit an undo checkpoint
C-r{reg}Insert a register, one fragment per selection
C-w / A-<backspace>Delete the word before the caret
A-d / A-<del>Delete the word after the caret
C-uKill to the line start
C-kKill to the line end, joining when already there
C-h / <backspace>Delete backwards, dedenting a whole level inside indentation
C-d / <del>Delete forwards
C-j / <enter>Insert a newline
<tab> / <shift-tab>Smart indent / literal indent
Arrows, <pgup> / <pgdn>, <home> / <end>Move the caret

Registers​

"{reg} picks the register the next operator uses.

RegisterHolds
a–zNamed. A–Z appends instead of replacing
"The unnamed register: every yank and delete
0The last yank
-The last small (non-linewise) delete
_The black hole: writes are discarded
.The last inserted text
/The last search pattern
%The current file path
+ / *The system clipboard

Helix clears a pending register on the very next key, so the idiom is w"ay — motion, register, operator. Rune keeps the register until an operator consumes it, which makes "ay work too.

Macros​

KeyAction
QStart recording into the selected register; press again to stop
qReplay the selected register
"{reg}Q / "{reg}qRecord into / replay register {reg}

A recorded macro is a plain register, so you can bind it to a key or wrap it in an alias with the command prompt's echo {register} instruction.

Windows, tabs and pickers​

The helix preset follows Helix's own leader conventions. <space> and <ctrl-w> are free in normal mode and taken in insert mode, which is exactly the gate these menus need.

The <space> menu​

KeyAction
not bound by selected presetOpen a file
not bound by selected presetToggle the file explorer
not bound by selected presetSearch open tabs
not bound by selected presetPick a stop from the cursor history
not bound by selected presetSearch the workspace
not bound by selected presetHover
not bound by selected presetRename the symbol
not bound by selected presetReferences to the symbol
not bound by selected preset / not bound by selected presetDiagnostics
not bound by selected presetNext Git change
not bound by selected preset / not bound by selected presetCopy to / paste from the system clipboard
not bound by selected presetCommand history
not bound by selected preset / not bound by selected preset / not bound by selected presetJump to a function / type / variable

Windows and tabs​

<meta> is Command on macOS. On Linux, first-run setup asks whether it should be Super or Alt, and you can change it later with gui.meta_key. With Alt, Helix's own Alt keys such as <alt-c> still come first.

The helix preset's layout keys work from every surface, including a terminal in INSERT mode:

KeyAction
<alt-j> / <alt-k> / <alt-i> / <alt-l>Focus the window left / down / up / right
<alt-shift-j> / <alt-shift-k> / <alt-shift-i> / <alt-shift-l>Move the window left / down / up / right
<alt-meta-j> / <alt-meta-k> / <alt-meta-i> / <alt-meta-l>Make the window narrower / shorter / taller / wider
<alt-q> / <alt-shift-q>Close this window / close the others
<alt-[> / <alt-]>Focus the previous / next tab
<alt-shift-[> / <alt-shift-]>Move the tab left / right
<meta-w>, <alt-w>Close the tab

The <ctrl-w> window menu​

Helix's window menu is bound too, so your muscle memory still works in the editor. A focused terminal takes <ctrl-w> for itself, though, so reach for the keys above there.

KeyAction
not bound by selected preset j k lFocus the window left / down / up / right
not bound by selected preset J K LMove the window left / down / up / right
not bound by selected presetFocus the other window
not bound by selected preset / not bound by selected presetSplit horizontally / vertically
not bound by selected preset / not bound by selected presetClose this window / close the others

The second key also works with <ctrl> still held, and the arrows stand in for h j k l, as in Helix. Helix reaches the same menu through <space>w, but a Rune key sequence is exactly two keys, so only the <ctrl-w> spelling survives the translation.

Typable commands​

The preset aliases Helix's short command names to the Rune commands that do the same job:

CommandRuns
:q / :wq / :xClose the window, after writing for :wq and :x
:qa / :qa!Quit Rune / quit without saving
:waWrite every file
:o {file}Open a file
:bc / :bcaClose the tab / close every tab
:bn / :bpNext / previous tab
:vs / :hs / :spSplit vertically / horizontally
:fmtFormat the file
:rlReload the file from disk

Rune has no per-split quit, so :q closes the window like not bound by selected preset and leaves the last one open. Quit with :qa. The long names are Rune's own commands, and :quit leaves Rune rather than closing a split.

See Layout Management for the complete layout system, and Key Mapping to remap the physical keys that drive the editor grammar itself.

What's different from Helix​

  • No tree-sitter objects. m i f, m i t, m i a, m i c and the sibling motions need a syntax service the editor does not own. A-o / A-i expansion still works because Rune supplies it.
  • Go regular expressions. Patterns use Go's RE2 syntax rather than Rust's regex crate: no look-around or back-references in either, but \w and \b are ASCII-only here, so reach for \pL for letters beyond it, and * only adds \b next to an ASCII word character. ^, $ and \b see one character past either edge of a selection, as in Helix, but with one of them in the pattern a match that runs past the edge is dropped rather than cut short.
  • Search matches are highlighted. Helix only selects the match; Rune also lights up every other occurrence, as its other editors do.
  • : is Rune's prompt. There is no separate Helix command mode; : opens the global command prompt, so :w, :q and friends are Rune commands or the preset's aliases for them.
  • No pickers inside the editor. not bound by selected preset, not bound by selected preset and the rest are Rune commands bound by the preset, not editor-internal pickers.
  • Extras. . repeats the last insert, and C-e / C-y scroll by a line. Helix leaves those keys unbound.
  • Registers live longer. See Registers.

What's not here​

Shell piping (\|, !, $), C-z suspend, A-I / A-a (insert at the start / end of every line of the selection) and the [/] syntax tree jumps are not bound by the editor. Use the command prompt and the preset's <space> menu for the ones Rune provides.

Ask Rune Agent