Key bindings
Every action in Tyrn can be bound to a key. You can start from a familiar editor’s keymap, change bindings in a visual editor, or write them by hand in keymap.json.
Keys in these docs use the cmd-shift-p style: modifiers joined with -, keys in a sequence separated by a space.
Base keymaps
If you come from another editor, set base_keymap in settings.json:
{ "base_keymap": "VSCode" }Supported values are "VSCode", "Atom", "JetBrains", "SublimeText", "TextMate", "Emacs", "Cursor" and "None". "None" turns off every default binding. Remove the setting to go back to Tyrn’s own keymap.
Turn on Vim or Helix bindings with vim_mode or helix_mode.
Keymap editor
Open it with cmd-k cmd-s, or run tyrn: open keymap. It lists every action with its current binding. To change a binding, double-click a row or select it and press enter, press the new keys, then confirm with enter. Your changes are written to keymap.json.
| Task | Keybinding |
|---|---|
| Search actions | cmd-f |
| Search by keystroke | cmd-alt-f |
| Show only conflicts | cmd-alt-c |
| Edit the selected binding | enter |
| Add another binding for the action | alt-enter |
| Copy the action name | cmd-c |
| Copy the context | cmd-shift-c |
Open keymap.json |
cmd-e |
To see the default bindings, run tyrn: open default keymap.
keymap.json
Your keymap file is ~/.config/tyrn/keymap.json. Open it with tyrn: open keymap file. It is a list of binding groups. A group without a context is always active.
[ { "bindings": { "ctrl-right": "editor::SelectLargerSyntaxNode", "ctrl-left": "editor::SelectSmallerSyntaxNode" } }, { "context": "ProjectPanel && not_editing", "bindings": { "o": "project_panel::Open" } }]Find action names in the keymap editor, or by searching the command palette. An action name has the form namespace::ActionName.
Most actions are bound as a string. Some take arguments and are bound as an array: "cmd-1": ["workspace::ActivatePane", 0].
Key syntax
A binding can be one keypress or a sequence typed in order. Separate keypresses with a space.
- Modifiers are
ctrl-,cmd-,alt-(the option key on macOS),shift-andfn-. - A key is a single character, or a name such as
tab,enter,escape,f1orspace. shift-works with letters, as inshift-gfor capitalG. For punctuation, write the character itself.
{ "bindings": { "cmd-k cmd-p": "workspace::ReopenLastPicker", "space e": "editor::ShowCompletions", "shift shift": "file_finder::Toggle" }}shift shift matches pressing and releasing shift twice. Bindings on a bare modifier fire on release.
Contexts
A binding group can have a context that limits where it applies. Tyrn’s contexts form a tree. The root is Workspace, which holds panes and docks, which hold editors, panels and so on. A binding is active only when its context matches the focused part of the tree.
To see what is active right now, run dev: open key context view. It prints something like:
Workspace os=macos Pane Editor mode=full extension=md vim_mode=insertContext expressions can use:
X && YandX || Y!X(X)to groupX > Y, true when an ancestor matchesXand this node matchesYkey == valueandkey != valuefor attributes such asmode,extension,osandvim_mode
Examples:
| Context | Matches |
|---|---|
Editor |
Any editor, including small inputs |
Editor && mode == full |
The main code editors |
Editor && extension == md |
Editors showing Markdown files |
!Editor && !Terminal |
Anywhere except an editor or a terminal |
os == macos > Editor |
Editors on macOS |
Attributes belong only to the node that sets them. To match an attribute that a parent sets, use >, for example debugger_stopped > Editor.
Precedence
When several bindings match the same keys:
- A binding on a deeper node wins. An
Editorbinding beats aWorkspacebinding. A group with no context matches at the lowest level. - At the same depth, the binding defined later wins. Your
keymap.jsonloads after the defaults, so yours win.
If one binding is a prefix of another, such as ctrl-w and ctrl-w left, Tyrn waits a moment after ctrl-w to see whether you type more. Pending keys show in the status bar. Hover the indicator to list what can still match.
To list the options without leaving a half-typed sequence, press alt-/. To show a bigger pop-up automatically, set:
{ "which_key": { "enabled": true, "delay_ms": 1000 } }Disable a binding
Bind a key to null to make it do nothing in a context.
[ { "context": "Workspace", "bindings": { "cmd-r": null } }]Send keystrokes
workspace::SendKeystrokes replays a list of keystrokes. Use it to map one key to several.
[ { "bindings": { "alt-down": ["workspace::SendKeystrokes", "down down down down"] } }, { "context": "Editor && vim_mode == insert", "bindings": { "j k": ["workspace::SendKeystrokes", "escape"] } }]Asynchronous steps such as opening the command palette, talking to a language server or the network happen only after all the keystrokes are sent, so you can’t chain keystrokes after them. At most 100 keystrokes are sent at once.
Other keyboard layouts
On layouts that can’t type all ASCII characters without alt, set "use_key_equivalents": true on a binding group so the group matches the character on the key rather than the one produced by alt.
[ { "use_key_equivalents": true, "bindings": { "ctrl->": "editor::Indent" } }]Task keys
Bind a key to run a task from tasks.json. See Tasks.