User guide / Custom key bindings

View and list bindings

Development reference · View source

keys.scopes.<scope>.<mode> assigns one supported action name to a key, or null to suppress that exact binding in that view. Other views and modes keep their bindings. Suppression also hides inherited bindings; it does not reveal the global action underneath, and does not remove longer sequences beginning with the same key.

keys:
  scopes:
    markdown:
      normal:
        j: move-up
        k: null
    global:
      list:
        F9: list-next
        Ctrl-n: null
    session-manager:
      list:
        F8: list-previous

Editor scope names are markdown, directory, directory-tree, settings, media, pdf-pages, help, commit-message, diff, workspace-search, terminal, and the Git scopes: git-status, git-branches, git-conflicts, git-conflict-file, git-conflict-markdown, git-merge-review, git-merge-detail, git-merge-input, git-worktrees, git-comparison, git-revision-diff, git-log, git-network, git-blame, and git-stash. Ordinary editor scopes support normal, select, insert, and replace. The merge review scopes currently dispatch normal only. Terminal replace is unavailable. Terminal insert admits terminal-safe mode, pane, clipboard, and persistent-session actions. For example:

keys:
  scopes:
    terminal:
      insert:
        F6: enter-normal-mode
        Ctrl-4: null
        'Ctrl-\': null
        'F7 h': focus-window-left

Ordinary keys still reach the child. An assigned action claims its first key and any following sequence; an explicit persistent-session action also claims its key outside a persistent session and reports when unavailable. A null removes only the exact binding and its legacy capture policy. Longer surviving bindings still claim their prefix. Removing Ctrl-w alone therefore does not remove the window namespace. Unmodified Escape still reaches the child unless explicitly assigned. Global custom text-editing bindings remain excluded from Terminal Insert.

Use global.list for ordinary result-list bindings and session-manager.list for overrides in the session manager. List bindings contain one key. List navigation actions are list-next, list-previous, list-page-down, list-page-up, list-first, list-last, list-toggle-preview, list-clear-filter, and list-close. Use list-accept to activate a row, list-open-actions to open its actions (or cycle tags / advance to the next row when no action menu applies), and list-backspace to delete the last filter character. These three actions do nothing in reports. Their inherited Enter, Tab and Backspace bindings accept every modifier combination, preserving the original behavior; scoped overrides replace or remove only the exact spelling. For example, Enter: null leaves Shift-Enter available. Empty-filter leader input follows the effective Escape action, including its removal. Nested action menus own their input separately. Numbered session choices remain structural input.

:help key-actions includes the scoped action names and their modes. Actions must be supported by the selected view and mode. Scoped assignments currently take one action name, without arguments or action lists. Editor sequences may contain up to eight keys, including Leader and Window. Context-action Tab, overlay leader dismissal, and merge acknowledgment editing still belong to their existing input owners; assignments or removals that those handlers would bypass are rejected.

Assignments apply simultaneously. Invalid scoped configuration rolls back the whole scopes section, while bind, ui, and pointer remain independent. A child override wins over inherited parents. If both Markdown and conflict-file scopes override the same key, git-conflict-markdown must decide explicitly, including by assigning null. Configuration fragments merge by scope, mode, and key. Existing scoped defaults remain with keys.defaults: false; that option still controls only global editor defaults.