buffr default keymap (page mode)

Reference for the default page-mode bindings shipped by buffr_modal::Keymap::default_bindings. All entries assume the leader key is \ (vim default); the leader is configurable per-profile via Keymap::set_leader.

Defaults mirror Vieb (stock app/renderer/input.js). Intentional divergences are flagged inline with [buffr].

The engine speaks vim-flavoured chord notation. <C-...> = Ctrl, <S-...> = Shift, <M-...> / <A-...> = Alt, <D-...> = Super (Cmd on macOS), <leader> = configured leader char.

Modes

ModeTriggerNotes
Normalinitial / <Esc>Default; bindings below.
Visual(Phase 3)Selection-bearing motions. <Esc> returns to Normal.
Command: or eCommand line / omnibar focused. <Esc> returns.
Hintf / FDOM hint overlay active. <Esc> returns.
Pending(transient)Multi-key prefix in flight. Not user-bindable.
Inserttext-field focusForwarded to hjkl_editor::Editor once Phase 2 ships.

Count and register prefixes

  • Count — leading digits accumulate: 5j scrolls down 5 lines, 12G jumps to line 12 (when implemented). 0 alone is bindable (vim convention: column 0); digits 1-9 always start a count.
  • Register"<char> selects a register before a yank. Phase 2 captures register state on the engine but does not yet thread it through to actions. Yank-to-register lands with Phase 5.

Ambiguity timeout

When a binding is a prefix of a longer one (g vs gg), the engine waits up to Engine::timeout() (default 1000ms). If the user does not extend the prefix, the shorter action fires.

Normal-mode bindings

Scroll

KeysActionNotes
jScrollDown(1)
kScrollUp(1)
hScrollLeft(1)
lScrollRight(1)
<Down>ScrollDown(1)
<Up>ScrollUp(1)
<Left>ScrollLeft(1)
<Right>ScrollRight(1)
<C-e>ScrollDown(1)
<C-y>ScrollUp(1)
<C-d>ScrollHalfPageDown
<C-u>ScrollHalfPageUp
<C-f>ScrollFullPageDown
<C-b>ScrollFullPageUp
<PageDown>ScrollFullPageDown
<PageUp>ScrollFullPageUp
ggScrollTop
GScrollBottom
<Home>ScrollTop
<End>ScrollBottom

Tabs

KeysActionNotes
HTabPrev[buffr] Vieb uses H for history-back.
LTabNext[buffr] Vieb uses L for history-forward.
gtTabNext
gTTabPrev
oTabNewRight[buffr] Open tab to the right of active; omnibar opens so you type a URL.
OTabNewLeft[buffr] Open tab to the left of active; omnibar opens so you type a URL.
dTabClose
<C-w>cTabClose
<C-w>nDuplicateTab
<C-w>pPinTab[buffr] Vieb uses <C-w>p for prev-buffer.

TabClose (and :q) close the active tab. The application only exits when the last tab is gone. DuplicateTab clones the active tab's URL into a fresh tab; PinTab toggles the pinned bit (sort hint only — pin does not prevent close). See multi-tab.md.

History

KeysActionNotes
JHistoryBack[buffr] Vieb uses J for next-tab.
KHistoryForward[buffr] Vieb uses K for previous-tab.
<C-o>HistoryBack
<C-i>HistoryForward

Reload / stop

KeysActionNotes
rReload
RReloadHard
<C-r>ReloadHard
<C-c>StopLoading[buffr] Vieb uses <C-c> for copyText; buffr keeps StopLoading.

Note: <Esc> is no longer bound to StopLoading in Normal mode. Use <C-c> to stop a page load. <Esc> is now ExitInsertMode — it blurs the focused DOM element and resets the engine to Normal unconditionally.

Omnibar / command line

KeysActionNotes
eOpenOmnibar
<C-l>OpenOmnibar
:OpenCommandLine
;OpenCommandLine[buffr] alias; Vieb uses ; for hints.

Hints

KeysAction
fEnterHintMode
FEnterHintModeBackground

Find

KeysAction
/Find { forward: true }
?Find { forward: false }
nFindNext
NFindPrev

Yank

KeysAction
yYankUrl

Zoom

KeysActionNotes
+ZoomIn
-ZoomOut
_ZoomOut
=ZoomReset[buffr] Vieb maps = to zoomIn; buffr keeps = as ZoomReset (more useful default).
<C-0>ZoomReset

DevTools

KeysAction
<F12>OpenDevTools
<C-S-i>OpenDevTools

Insert mode

KeysActionNotes
iFocusFirstInput[buffr] Same as gi — JS focuses first form input; focusin auto-promotes to Insert.
giFocusFirstInput[buffr] Vieb's insertAtFirstInput. JS focuses first input; focusin auto-promotes.
<Esc>ExitInsertModeBlurs the active DOM element; resets edit state and engine to Normal unconditionally.

EnterInsertMode remains in the action enum for advanced user config (e.g. [keymap.normal] "<F2>" = "enter_insert_mode") but is unbound by default.

Mode transitions

The engine reads the resolved [PageAction] and auto-transitions:

  • OpenOmnibar, OpenCommandLineCommand
  • EnterHintMode, EnterHintModeBackgroundHint
  • EnterInsertModeInsert (trie bypassed; feed_edit_mode_key takes over)
  • ExitInsertModeNormal (blurs DOM active element; clears EditFocus)
  • EnterMode(m)m

<Esc> is bound in Normal to ExitInsertMode and in Visual / Command / Hint to EnterMode(Normal) so every mode has a guaranteed escape hatch.

In-overlay shortcuts (command line / omnibar)

When : opens the command line or e/<C-l> opens the omnibar, all keystrokes route to the input bar instead of the page-mode trie. The bindings below mirror readline / vim's command-line conventions.

KeysAction
<Esc> / <C-c>Cancel — close overlay, return to Normal mode.
<CR>Confirm — dispatch the command or navigate to the URL.
<Tab> / <Down>Move suggestion selection one row down (cycles to last).
<S-Tab> / <Up>Move suggestion selection one row up (clears at top).
<Left> / <Right>Move cursor through the buffer.
<BS>Delete the codepoint before the cursor.
<C-u>Clear the entire buffer.
<C-w>Delete the word before the cursor.

In-prompt shortcuts (permissions)

When a page asks for a permission (camera, microphone, geolocation, notifications, clipboard, MIDI sysex, …) buffr surfaces a prompt strip and routes keystrokes to it until the request is resolved. The page content does not see these keys.

KeysAction
a / yAllow once (no row written).
A / YAllow + remember for this origin.
d / nDeny once (no row written).
D / NDeny + remember for this origin.
sSynonym for D — deny + remember.
<Esc>Defer — Dismiss / cancel(), no persistence.

If multiple requests pile up they queue; the statusline shows (N more pending) on the prompt strip. After resolving one the next prompt appears on the following frame.

See crates/buffr-permissions/README.md for the decision-precedence rules.

Mouse / context menu

Gesture / inputAction
Right-click (page area)Open context menu. Items depend on the hit-test target (see context-menu.md).
<Up> / <Down>Move row selection in the open menu.
<Enter>Activate selected menu item.
<Esc>Dismiss menu without action.
Click outside panelDismiss menu without action.
Any non-navigation keyDismiss menu and pass key to normal page-mode dispatcher.
Left-click (tab strip)Switch tab and close the omnibar overlay (parity with gt/gT).
Two-finger swipe rightHistoryBack (≥ 150 px horizontal, 2× more horiz than vertical).
Two-finger swipe leftHistoryForward (same threshold).

Vieb chords intentionally NOT mapped

The following Vieb normal-mode actions have no buffr PageAction equivalent and are skipped until those features land:

Vieb chord(s)Vieb actionReason not mapped
p / PopenFromClipboardNo OpenFromClipboard action
vstartVisualSelectVisual mode not yet wired
<C-v>toVisualModeVisual mode not yet wired
<C-p>previousTab (pointer)Pointer mode not implemented
<C-n>nextTab (pointer)Pointer mode not implemented
m / MsetMark / restoreMarkMarks not implemented
<C-s>downloadLinkNo DownloadLink action
<C-f> (pointer)scrollPageDown (pointer)Pointer mode not implemented
s / StoSearchMode (special)Covered by / / ?
<C-a> / <C-x>incrementUrl / decrementNo URL increment action
<kPlus> / <kMinus>zoomIn / zoomOutkPlus/kMinus not a named key in buffr parser; covered by +/-
<C-t>openNewTabNo default binding; use o/O for adjacent-tab open.
ureopenTabNo ReopenTab action
<C-Tab> / <C-S-Tab>nextTab / prevTabCovered by J/K

Customising

Bindings come from a static table in crates/buffr-modal/src/keymap.rs. User overrides go in ~/.config/buffr/config.toml under [keymap.<mode>] — see config.md for the full schema and action notation. The watcher reloads the keymap on file changes (250ms debounced).