Vim mode
Vim mode adds Vim’s modal editing to Tyrn. It covers the core of Vim and replaces some Vim features with Tyrn’s own, such as language servers, multiple cursors and project search. It does not aim to match Vim one to one.
Turn it on
Run workspace: toggle vim mode from the command palette. This switches the vim_mode setting:
{ "vim_mode": true }Tyrn also has a Helix mode that builds on Vim mode.
What works differently
- Motions use the syntax tree. For example,
%matches brackets in a language-aware way. - Visual block mode is built on multiple cursors, so what you type after a block selection appears on every line.
- Macros use Tyrn’s recording, so they can include things like accepting a completion.
- Search (
/,?,:s) uses Tyrn’s search. Setvim.use_regex_searchto choose between regex and plain text.
Language server and Tyrn commands
These work in normal mode.
| Task | Keys |
|---|---|
| Go to definition | g d |
| Go to declaration | g D |
| Go to type definition | g y |
| Go to implementation | g I |
| Find all references | g A |
| Rename | c d |
| Symbols in this file | g s |
| Symbols in the project | g S |
| Next, previous diagnostic | g ], g [ (also ] d, [ d) |
| Hover | g h |
| Code actions | g . |
| Project search | g / |
| Open the search excerpt under the cursor | g space |
| Open it in a split | ctrl-w space |
| Go to definition in a split | ctrl-w g d |
Newer-style bindings also work: g r n renames, g r r finds references, g r i goes to implementation and g r a opens code actions.
Git
| Task | Keys |
|---|---|
| Next, previous change | ] c, [ c |
| Expand a diff hunk | d o |
| Toggle staged | d O |
| Stage and next | d u |
| Unstage and next | d U |
| Restore the change | d p |
Syntax tree
| Task | Keys |
|---|---|
| Next, previous method start | ] m, [ m |
| Next, previous method end | ] M, [ M |
| Next, previous section start | ] ], [ [ |
| Next, previous section end | ] [, [ ] |
| Next, previous comment | ] /, [ / (also ] *, [ *) |
| Select a larger syntax node | [ x |
| Select a smaller syntax node | ] x |
Text objects, used after an operator with i (inside) or a (around):
| Object | Keys |
|---|---|
| Class or type | a c, i c |
| Function or method | a f, i f |
| Comment | g c |
| Argument | a a, i a |
| HTML tag | a t, i t |
| Indent level | i i (and a i, a I) |
| Entire file | a e, i e |
| Quotes | q (quote pair near the cursor), plus ', " and ` |
| Brackets | b, B, r, (, {, [, < |
Multiple cursors
| Task | Keys |
|---|---|
| Add a cursor at the next match of the word | g l |
| Add a cursor at the previous match | g L |
| Select every match | g a |
| Skip this match and add the next | g > |
| Skip this match and add the previous | g < |
| Add a cursor at the end of each selected line (visual mode) | g A |
| Add a cursor at the first character of each selected line (visual mode) | g I |
Plugin-style features
- Surround:
ysadds,cschanges,dsdeletes. For exampleysiw"surrounds a word with quotes. - Comment:
g c ctoggles the current line, andg cin visual mode toggles the selection.g btoggles block comments. - Replace with register:
g R. - Exchange:
c x. - Indent-aware motions:
[ -,] -,[ +,] +,[ =,] =. - Case and rotation:
g u,g U,g ~,g ?. - Reflow:
g qorg w.
Insert mode
| Task | Keys |
|---|---|
| Open completions | ctrl-x ctrl-o |
| Request an edit prediction | ctrl-x ctrl-c |
| Open code actions | ctrl-x ctrl-l |
| Hide suggestions | ctrl-x ctrl-z |
| Word completions | ctrl-n, ctrl-p |
| Signature help | ctrl-s |
Command palette and ex commands
Press : to open the command palette. Vim-style commands work there, and any other Tyrn command does too. Square brackets show the part you may leave out.
| Command | Action |
|---|---|
:w[rite][!], :up[date] |
Save |
:wa[ll][!] |
Save all |
:q[uit][!] |
Close the buffer |
:wq[!], :x[it] |
Save and close the buffer |
:qa[ll][!], :wqa[ll], :xa[ll] |
Close all, with or without saving |
:cq[uit] |
Quit Tyrn |
:bd[elete][!] |
Close the file in all panes |
:sp[lit], :vs[plit] |
Split the pane horizontally or vertically |
:new, :vne[w] |
New file in a split |
:tabe[dit], :tabnew |
New file in a tab |
:tabn[ext], :tabp[revious], :tabc[lose], :tabo[nly] |
Move between and close tabs |
:ls, :buffers |
Show open buffers |
:E[xplore] |
Open the project panel |
:G[it] |
Open the git panel |
:D[ebug] |
Open the debug panel |
:te[rm] |
Open the terminal panel |
:cl[ist] |
Open project diagnostics |
:cn[ext], :cp[rev] |
Next, previous diagnostic |
:dif[fupdate] |
Expand the diff hunk (d o) |
:rev[ert] |
Revert the change (d p) |
:<number>, :$ |
Jump to a line, or to the end |
:[range]s/foo/bar/[g] |
Substitute |
:j[oin], :d[elete], :y[ank], :sor[t] |
Edit lines |
:norm[al] |
Run normal-mode keys |
:noh[lsearch] |
Clear search highlights |
:se[t] [no]wrap, [no]nu[mber], [no]r[elative]nu[mber], [no]i[gnore]c[ase] |
Buffer options |
Add your own short names with command_aliases.
Settings
{ "vim": { "default_mode": "normal", "use_system_clipboard": "always", "use_smartcase_find": false, "use_regex_search": true, "gdefault": false, "toggle_relative_line_numbers": false, "highlight_on_yank_duration": 200, "custom_digraphs": {}, "cursor_shape": { "normal": "block", "replace": "underline", "visual": "block", "insert": "inherit" } }}| Key | Meaning |
|---|---|
default_mode |
Mode to start in: "normal", "insert", "replace", "visual", "visual_line", "visual_block" or "helix_normal" |
use_system_clipboard |
"always" (default), "never" or "on_yank" |
use_smartcase_find |
Make f and t ignore case for a lowercase target |
use_regex_search |
Treat / searches as regular expressions |
gdefault |
Make :s replace every match in a line by default |
toggle_relative_line_numbers |
Relative numbers in normal mode, absolute in insert mode |
highlight_on_yank_duration |
Milliseconds to flash yanked text. 0 turns it off. |
custom_digraphs |
Extra digraphs, typed with ctrl-k then two characters |
cursor_shape |
Cursor per mode. "inherit" uses the editor’s cursor_shape. |
Other settings that pair well with Vim mode: relative_line_numbers, cursor_blink, scroll_beyond_last_line, vertical_scroll_margin and command_aliases.
Custom key bindings
Vim mode adds attributes to the Editor context. Use them in key bindings.
| Context | Meaning |
|---|---|
VimControl |
Vim keys are active (normal, visual or operator mode) |
vim_mode == normal |
Normal mode |
vim_mode == visual |
Visual mode |
vim_mode == insert |
Insert mode |
vim_mode == replace |
Replace mode |
vim_mode == waiting |
Waiting for a key, for example after f |
vim_mode == operator |
Waiting for a motion after an operator such as d |
vim_operator |
The pending operator, such as d. none otherwise. |
Contexts match one node at a time. Editor && vim_mode == normal works. Workspace && vim_mode == normal never matches.
[ { "context": "vim_mode == insert", "bindings": { "j k": "vim::NormalBefore" } }, { "context": "vim_mode == normal && !menu", "bindings": { "shift-y": ["workspace::SendKeystrokes", "y $"] } }]To emulate Vim’s map commands, use workspace::SendKeystrokes in the right context.
Optional bindings
Move between panels with the same keys as between panes:
{ "context": "Dock", "bindings": { "ctrl-w h": "workspace::ActivatePaneLeft", "ctrl-w l": "workspace::ActivatePaneRight", "ctrl-w k": "workspace::ActivatePaneUp", "ctrl-w j": "workspace::ActivatePaneDown" }}Subword motion for camelCase and snake_case is off by default:
{ "context": "VimControl && !menu && vim_mode != operator", "bindings": { "w": "vim::NextSubwordStart", "b": "vim::PreviousSubwordStart", "e": "vim::NextSubwordEnd", "g e": "vim::PreviousSubwordEnd" }}Add surround in visual mode, enable the Sneak motion, or make h and l wrap across lines:
[ { "context": "vim_mode == visual", "bindings": { "shift-s": "vim::PushAddSurrounds" } }, { "context": "vim_mode == normal || vim_mode == visual", "bindings": { "s": "vim::PushSneak", "shift-s": "vim::PushSneakBackward" } }, { "context": "VimControl && !menu", "bindings": { "h": "vim::WrappingLeft", "l": "vim::WrappingRight" } }]Project panel and other panels
With the project panel focused: j and k move, h and l collapse and expand, o opens in a horizontal split, v in a vertical split, t opens permanently, % creates a file, d creates a folder, shift-r renames, shift-d deletes and / searches inside the folder. escape returns to the editor. The outline panel and git panel accept j, k, g g and shift-g too.