contracts / keymap.md

Keymap

Shortcuts that exist in the code, plus PRD shortcuts that are not built. ⌘ is metaKey or ctrlKey: Command on macOS, Ctrl on Linux and Windows.

Scopes

ScopeWhen the shortcut applies
globalThe window listener, whether or not a page is open
documentA page is open
editorThe block editor, the Markdown source editor, or a widget inside them
reviewThe proposal review screen. Not built
dialogA dialog, menu, palette, or sheet is open

Collisions

The same key is a different action in different scopes. A binding in one scope must not steal the other.

Keyglobal or documentreview
CNew page. BuiltRequest changes, and the note is required. Not started
EStart editing, when a page is open. BuiltEdit before merge. Not started

C and E run only when the target is not an input, textarea, contenteditable, or .cm-content, and no .overlay or .menu is open, and neither ⌘ nor Alt is held. Shift is ignored (c and C both match). That is what keeps C from firing while typing and while a dialog is open. It does not define the review binding. Review is not built, so review C and review E have no handler yet.

⌘E in the editor toggles inline code. It is not E. The plain E handler requires ⌘ to be up, so the two do not fire together.

Global

KeysAction
⌘KOpen search. Close shortcut help. Runs while typing
⌘/If the mode is Markdown source, switch to editing. Otherwise switch to Markdown source. From viewing this opens source, not editing. Runs while typing. In the source editor, CodeMirror's comment binding on ⌘/ is swallowed and does not run
⌘\Show or hide the outline. Runs while typing
⌘,Open or close settings. Runs while typing
?Open shortcut help and close search. Suppressed while typing. Not suppressed by an open dialog
EscapeClose search, close shortcut help, and close the mobile files drawer. Separate listeners also close settings and the share sheet. A dialog that stops the key (the table under Dialog) keeps this from running too
CNew page in the open page's folder, or at the top level when no page is open. Opens the files column and starts the name field. Suppressed while typing or while a dialog or menu is open

Document

KeysAction
ESet the mode to editing. Requires a page. Suppressed while typing or while a dialog or menu is open
⌘SSave a version of the open page into the browser version list. If nothing changed since the last version, say so. No page, no save. The source editor swallows ⌘S so the browser does not save the page itself; the window listener still records the version

The page menu shows ⌘/ and ⌘S as hints. Those menu rows call the same actions. They are not extra shortcuts.

A link with ?edit=1 opens editing, and ?edit=0 opens viewing. The query is then removed. That is not a key binding.

Editor

Written in this repo

KeysAction
/Open the slash menu at the start of a suggestion. Inserts a block. Does not run inside a code fence
[[Open the page picker and insert a wiki link
``` then space or newlineTurn the line into a code fence. An optional language sticks
$$ then spaceTurn the line into a math block
EscapeClose the slash menu or the page picker
ArrowDown / ArrowUpMove the slash or page-picker highlight
Enter or TabPick the highlighted slash or page-picker item
Escape or ⌘EnterClose a block's source editor and return to the page
TabIn a block source editor, insert two spaces
BackspaceIn an empty block source editor, delete the block
Enter or EscapeFinish inline math
EscapeClose the embed picker
EnterIn the embed picker, embed the first match
EnterCommit a frontmatter field
EscapeRevert a frontmatter field
EscapeClose the bubble link field and return to the page

The bubble labels name ⌘B, ⌘I, and ⌘E. Those bindings come from the editor extensions below, not from a keymap in components/.

Enabled by the editor extensions

lib/editor/nodes.ts turns on StarterKit (code block and underline off; bullet list and ordered list replaced by the tight lists), task list, task item with nesting, table, and highlight. These bindings are that configuration. They apply in the block editor.

KeysAction
⌘BBold
⌘IItalic
⌘EInline code
⌘⇧SStrikethrough
⌘⇧HHighlight
⌘⌥1 through ⌘⌥6Heading levels 1–6
⌘⇧BBlockquote
⌘⇧8Bullet list
⌘⇧7Numbered list
⌘⇧9To-do list
⌘Enter or ⇧EnterHard break
EnterSplit a list item
Tab / ⇧TabIndent or outdent a list item. On a to-do, Tab indents only because nesting is on
BackspaceLift an empty blockquote or list item
Tab / ⇧TabNext or previous table cell. Tab on the last cell adds a row
Backspace or Delete, with or without ⌘Delete a table when every cell is selected

Markdown typed in the block editor also converts, from those same extensions:

TypedBecomes
# through ###### then spaceHeading 1–6
-, *, or + then spaceBullet list
1. then spaceNumbered list
[ ] or [x] then spaceTo-do
> then spaceBlockquote
---, —-, ___ , or *** Divider
**, __, *, _, `, ~~, == around a wordBold, italic, code, strike, highlight, using the extension's own pattern

Underline is off, so ⌘U is not a binding. The StarterKit code block is off; the fence rule above is the one that runs.

Markdown source

components/editor.tsx binds Tab to indent and ⇧Tab to outdent. It also swallows ⌘S and ⌘/.

basicSetup leaves these CodeMirror maps on (defaultKeymap, historyKeymap, searchKeymap, foldKeymap, completionKeymap, lintKeymap, closeBracketsKeymap). Autocompletion and the fold gutter are off; the keymaps are still registered. ⌘/ in that default map would toggle a comment; the swallow above wins, and the global handler switches mode instead.

KeysAction
Tab / ⇧TabIndent / outdent
⌘ZUndo
⌘Y, or ⌘⇧Z on macOS, or Ctrl⇧Z on LinuxRedo
⌘UUndo selection
⌥U, or ⌘⇧U on macOSRedo selection
⌘FOpen the source find panel
F3 or ⌘GFind next. Shift finds previous
EscapeClose the find panel, when that panel is open
⌘⇧LSelect matches of the selection
⌘⌥GGo to line
⌘DSelect the next occurrence
⌘EnterInsert a blank line
⌘[ / ⌘]Indent less / more
⌘⌥\Indent the selection
⌘⇧KDelete the line
⌘⇧\Jump to the matching bracket
⌥AToggle a block comment. ⌘/ does not; see above
CtrlM, or ⇧⌥M on macOSToggle Tab-focus mode
⌥Left / ⌥Right (Ctrl on macOS)Move by syntax group
⌥Up / ⌥DownMove the line
⇧⌥Up / ⇧⌥DownCopy the line
EscapeSimplify the selection, when find is not taking it
⌘ISelect the parent syntax node. This is the source editor, not italic
Ctrl⇧[ / Ctrl⇧] (⌘⌥ on macOS)Fold / unfold
Ctrl⌥[ / Ctrl⌥]Fold / unfold all
⌘⇧MOpen the lint panel
F8Next diagnostic
CtrlSpace, or ⌥` on macOSStart completion
Escape, arrows, PageUp, PageDown, EnterCompletion menu, when it is open
BackspaceDelete an empty bracket pair

CodeMirror's standard map also binds the usual cursor, selection, and deletion keys inside the source editor (arrows, Home, End, Page Up, Page Down, Backspace, Delete, and their ⌘ and Shift variants).

Dialog

WhereKeysAction
SearchArrowDown / ArrowUpMove the highlight
SearchEnterOpen the highlighted page
SearchEscapeClose, via the global handler
MoveArrowDown / ArrowUpMove the highlight
MoveEnterMove to the highlighted folder
MoveEscapeClose
History, trash, share, delete-projectEscapeClose
Project create or renameEscapeClose
Project descriptionEnter without ShiftSubmit
Project switcherArrowDown / ArrowUpMove through projects
Project switcherEscapeClose and focus the switcher button
Project switcherTabClose
Page or block menuArrowDown / ArrowUpMove through items
Page or block menuEscapeClose. The block menu also returns focus to the editor
Shortcut helpEscapeClose, via the global handler
Settings⌘,Close, because the global binding toggles
SettingsEscapeClose
Tree name fieldEnterCommit the name
Tree name fieldEscapeCancel

Review

Not started. No handler in the code.

KeysActionStatus
G then IGo to InboxNot started
G then TGo to TimelineNot started
G then MGo to MetricsNot started
MMergeNot started
RReject. A reason is optionalNot started
CRequest changes. A note is required. See CollisionsNot started
EEdit before merge. See CollisionsNot started
DToggle the rendered diff and the source diffNot started
J / KNext / previous itemNot started
⌘⇧FNew finding from this experimentNot started

⌘K, C, E, ⌘S, ⌘\, ⌘/, and ? are the PRD bindings that are built. Their shipped actions are in the tables above. ⌘\ toggles the outline, not the PRD right panel of properties, backlinks, and history. ⌘/ switches between editing and Markdown source, not the PRD raw-source toggle on an inline preview.