Skip to content

Latest commit

 

History

History
213 lines (193 loc) · 18 KB

keybindings.md

File metadata and controls

213 lines (193 loc) · 18 KB

Keybindings

Every keyboard shortcut is a named command, and the [keybindings] table maps command ids to the keys you want them on:

[keybindings]
"hunk.app.quit" = "ctrl+x"               # one chord
"hunk.review.nextHunk" = ["]", "ctrl+n"] # several chords for one command
"hunk.review.focusFilter" = "/"          # takes "/" back from content search
"hunk.view.toggleMenuBar" = false        # unbind it entirely
"myext.toggle" = "ctrl+g"                # extension commands too

Every id starts with the name of whoever owns the command: Hunk's own commands live under hunk., and an extension's live under its extension id. That split is structural — hunk is a reserved extension id, so an extension can never mint a command id that shadows a built-in, whatever Hunk adds later. Extension commands currently run on review surfaces; history resolves its built-in command set without claiming review-only extension chords.

Rules worth knowing:

  • User bindings replace defaults. Listing chords for a command is the complete set of keys it answers to, not an addition to the shipped ones.
  • A key you bind is yours. Any command that held the same chord only as a default gives it up, keeping its other keys. Above, hunk.search.find hands / to the filter while n / N still step search matches.
  • false (or []) unbinds a command, leaving its keys doing nothing.
  • Unbound commands are one line away. The file filter ships without a key (Tab and the File menu reach it), as do hunk.review.nextNote / previousNote (} / { step through annotated hunks); one [keybindings] line gives any of them a chord.
  • Two entries claiming one chord is a conflict: the first in the file wins and the session reports the other. Unknown command ids and unusable chords are reported the same way, and the rest of the table still applies.
  • Escape clears an active visual selection contextually after overlays and extension modes have had their normal ownership. Without a selection, Escape remains available to extension commands because clear-selection is unbound.

Chords are ctrl, alt/option, cmd/meta, and shift joined with + around a base key: a character ("y", "["), an uppercase letter for its shifted form ("G"), or a named key ("tab", "pageup", "left", "f2"). shift applies to letters and named keys only — for a shifted symbol or digit, write the character the shift produces ("!", not "shift+1"), since that is what terminals report. ctrl+<letter> also matches an unnamed bare control byte; named Tab and Enter events stay distinct. alt/option matches both explicit Alt events and the Escape-prefixed form used by legacy terminals. A legacy terminal cannot distinguish Alt from Meta, so alt+n and meta+n may overlap there; Kitty keyboard events keep them distinct.

Inline saved notes also expose clickable Edit, Reply, and (for reply-free user notes) Delete actions. E edits the first editable user note in the selected hunk and R replies to its first visible stored note. Replies inherit the code anchor and may be nested without a product depth limit. Static sidecar annotations are not reply targets, and a parent cannot be deleted until its replies are removed.

The built-in commands and the keys they ship with:

On a terminal, hunk log opens its read-only history browser automatically. Its hunk.history.* commands use the same configurable keybinding resolver as review while retaining history-specific effects. Shared application commands such as hunk.app.quit, hunk.app.toggleHelp, and hunk.view.openThemeSelector keep the same ids on both surfaces. F10 opens File, View, Navigate, Commit, and Help menus; View includes Hunk's shared theme selector and an optional Graph view that replaces the default day-grouped timeline with commit-topology lanes. It uses Up/Down or j/k to move; press v first to extend a contiguous commit selection with those same keys. Shift+Up/Shift+Down or uppercase K/J extend directly, and Escape collapses the selection. PageUp/PageDown, b/f, or Shift+Space/Space page through history; u/d or Ctrl-U/Ctrl-D move by half a page; g/G or Home/End jump, / to search, n/N for matches, t to choose a theme, r to refresh, y to copy the focused commit's full id, Enter to open the selection in normal Hunk review, and q or Ctrl-C to quit. With a mouse, Shift-click a row to extend the selection when the terminal forwards modifiers, click a commit id to open it immediately, click the adjacent copy icon to copy its full immutable id, click elsewhere on a row to select it, or double-click a row to open it. Range selection is unavailable with --all or author, message, date, and path filters because those traversals can interleave unrelated commits or hide intermediate commits. Quitting the opened review returns to the retained history selection and viewport. The Commit menu's Compare with first parent and Compare with parent… actions compare the selected commit against an ordered provider-owned parent; they do not navigate the history selection to that parent.

History-specific commands:

Command id Does Default keys
hunk.history.openSelection Open the selected commit(s) enter
hunk.history.copyRevision Copy the focused commit id y
hunk.history.refresh Refresh repository history r
hunk.history.previousCommit Move to the previous commit up, k
hunk.history.nextCommit Move to the next commit down, j
hunk.history.startVisualSelection Start visual selection v
hunk.history.clearSelection Clear visual selection escape
hunk.history.extendPrevious Extend selection upward shift+up, K
hunk.history.extendNext Extend selection downward shift+down, J
hunk.history.pageUp Move up one page pageup, b, shift+space
hunk.history.pageDown Move down one page pagedown, space, f
hunk.history.halfPageUp Move up half a page u, ctrl+u
hunk.history.halfPageDown Move down half a page d, ctrl+d
hunk.history.jumpToFirst Jump to the first commit home, g
hunk.history.jumpToLast Jump to the last commit end, G
hunk.history.search Search history /
hunk.history.nextMatch Select the next match n
hunk.history.previousMatch Select the previous match N
hunk.history.toggleGraph Toggle graph presentation (none)
hunk.history.toggleUnicode Toggle Unicode graph lines (none)
hunk.history.toggleAuthor Toggle author metadata (none)
hunk.history.toggleDate Toggle date metadata (none)
hunk.history.toggleDecorations Toggle ref decorations (none)
hunk.history.openFirstParent Compare with first parent (none)
hunk.history.openParent Choose a parent to compare (none)
hunk.history.showAbout Show application information (none)

Review and shared commands:

Command id Does Default keys
hunk.app.openAgentSkill Show agent skill (none)
hunk.app.quit Quit q
hunk.app.refresh Refresh the review r
hunk.app.toggleFocusArea Switch focus between files and filter tab
hunk.app.toggleHelp Toggle help ?
hunk.review.alignCurrentLineBottom Align current line to viewport bottom (none)
hunk.review.alignCurrentLineCenter Center current line in viewport (none)
hunk.review.alignCurrentLineTop Align current line to viewport top (none)
hunk.review.clearSelection Clear the active visual selection (none)
hunk.review.copySelection Copy the active visual selection y
hunk.review.deleteActiveNote Delete active review note D
hunk.review.editActiveNote Edit active review note E
hunk.review.editSelectedFile Open the selected file in your editor e
hunk.review.focusFilter Focus the file filter (none)
hunk.review.halfPageDown Scroll down half a page d, ctrl+d
hunk.review.halfPageUp Scroll up half a page u, ctrl+u
hunk.review.jumpToBottom Jump to end G, end
hunk.review.jumpToTop Jump to start g, home
hunk.review.nextAnnotatedFile Next annotated file (none)
hunk.review.nextAnnotatedHunk Next annotated hunk }
hunk.review.nextFile Next file .
hunk.review.nextHunk Next hunk ]
hunk.review.nextNote Next review note (none)
hunk.review.pageDown Scroll down one page pagedown, space, f
hunk.review.pageUp Scroll up one page pageup, b, shift+space
hunk.review.previousAnnotatedFile Previous annotated file (none)
hunk.review.previousAnnotatedHunk Previous annotated hunk {
hunk.review.previousFile Previous file ,
hunk.review.previousHunk Previous hunk [
hunk.review.previousNote Previous review note (none)
hunk.review.replyToActiveNote Reply to active review note R
hunk.review.saveNote Save a draft review note ctrl+s
hunk.review.scrollCodeLeft Scroll code left (shifted scrolls fast) left, shift+left
hunk.review.scrollCodeRight Scroll code right (shifted scrolls fast) right, shift+right
hunk.review.startNote Add a review note c
hunk.review.startVisualSelection Start visual line selection v
hunk.review.stepDown Move down one line or note down, j
hunk.review.stepUp Move up one line or note up, k
hunk.review.toggleHunkGap Expand or collapse the selected context z
hunk.search.find Search diff content /
hunk.search.next Next search match n
hunk.search.previous Previous search match N
hunk.view.applyFilePresentationToAllMatching Apply current file presentation to all matches (none)
hunk.view.cursorLineNumber Mark the current line number (none)
hunk.view.cursorLineOff Hide the current-line marker (none)
hunk.view.cursorLineRow Highlight the current row (none)
hunk.view.layoutAuto Auto layout 0
hunk.view.layoutSplit Split layout 2
hunk.view.layoutUnified Unified layout 1
hunk.view.openThemeSelector Choose theme t
hunk.view.toggleAgentNotes Toggle agent notes a
hunk.view.toggleCopyDecorations Toggle copy decorations (none)
hunk.view.toggleFilesPane Toggle files pane s
hunk.view.toggleHunkHeaders Toggle hunk headers m
hunk.view.toggleLineNumbers Toggle line numbers l
hunk.view.toggleLineWrap Toggle line wrapping w
hunk.view.toggleMenuBar Toggle menu bar M

The files-pane command follows the named hunk:files role. If an extension replaces that role, the command and View → Files pane toggle the resolved replacement on any terminal edge without changing unrelated panes. Remapping or unbinding hunk.view.toggleFilesPane changes that role-aware action, not an extension pane's own commands. The former hunk.view.toggleSidebar id remains a compatibility alias; prefer the files-pane name in new config and extension code. Likewise, hunk.view.layoutStack remains a deprecated alias for hunk.view.layoutUnified, so existing keybindings and extension command calls continue to select the canonical unified layout.

Commands marked (none) ship without a key: they remain callable by command id and can be assigned a shortcut through [keybindings]. Some also appear in a menu, while semantic commands such as current-line alignment do not need a menu entry.

The menus and the controls help dialog (?) show the keys for the commands they present, so remapping something changes what they advertise. Unbinding a menu command keeps its menu item and simply stops showing a key.

Extension commands are named <extensionId>.<commandId> and remap the same way (see docs/extensions.md). An explicitly activated extension keyboard mode is a routing layer rather than a second command table: it may consume a key, pass it to these resolved bindings, or consume it and exit. Its multi-key grammar and counts are extension-owned, but resolved actions should invoke these same public hunk.* commands.

Routing precedence is host prompts and dialogs, menus/overlays, focused text inputs, an interactive file-view mode, a session extension keyboard mode, then the command table and focused review widget. Keys that belong to a dialog, menu, or focused text input — Esc, Enter — are part of those widgets rather than commands, and are not remappable. The note composer's save shortcut is the command hunk.review.saveNote (default ctrl+s) and is remappable; while the composer is focused it still wins over the command table, using the resolved chord. Escape is also the reserved exit from each active extension mode, so an extension cannot trap the keyboard.

[keybindings]
"hunk.review.saveNote" = "ctrl+enter"   # Zellij-friendly; default is ctrl+s

[keybindings] is read from your user config only — never from a repository's .hunk/config.toml. Which keys do what is a property of your keyboard and your habits, so a checkout you review cannot rearrange them.