Skip to content

Keyboard shortcuts

You can change Field's keyboard shortcuts to suit the way you work. They live in one file:

~/.afield/keybindings.yaml

Field writes that file itself, from its own list of commands, so every command Field has is in there, including the ones that ship with no shortcut at all. Change a line, save, and the shortcut moves immediately: the file is watched, like ~/.afield/theme.css, and nothing needs restarting.

Press ? on the canvas to see the shortcut card. It reads your current bindings, so any changes you make to the file show up there too.

Field's ? cheatsheet card, with every key legend filled in from the live keybindings

What you can rebind

Everything Field itself does: the canvas commands (new-box, copy-selection, …), the editor's actions (execute-fragment, ai-assist, …), the four global ones that work wherever you are (open-command-palette, open-anything, toggle-docs, show-cheatsheet) and all eighteen bookmark slots. Commands that only make sense with something selected, such as connecting two boxes, are in the file too, and you can rebind them at any time.

A command that ships without a shortcut appears in the file as "", and giving it a chord is the same edit as changing one:

bindings:
  macro-transcript-panel: "cmd+shift+r"   # was: no shortcut at all

Two things are not in the file:

  • Gestures. alt/option-click to launch a box, alt/option-drag to "strum" several, and the multi-taps — Esc Esc to clear the newest output, Esc Esc Esc to clear them all, Shift Shift to open anything from the canvas, Cmd Cmd-and-hold for stepping between boxes. These are not single chords, so there is no way to write them in the shortcut syntax described below; they are hard-wired.
  • Monaco's own editor bindings. Autocomplete (Ctrl+Space), undo, find, multi-cursor and the rest belong to the text editor Field embeds, not to Field's command list.

Two-key chords, such as cmd+k cmd+s, can be written in the shortcut syntax: see Writing a two-key chord. No default uses one, so every chord in your file is one you wrote.

Getting a file to edit

You already have one; Field writes it on first run. Two ways to get to it:

  • Run Open Keybindings from the command palette (ctrl/command-shift-P). Field opens the file as a box on the canvas, so you can edit your shortcuts in Field, with Field.
  • Or open ~/.afield/keybindings.yaml in any editor you like.

Saving is all it takes. Field notices within a second, re-resolves every binding and re-registers them in the editor and on the canvas at once, then tells you it has done so. If you would rather not wait, or you changed the file while Field was not running, there is a Reload Keybindings command that re-reads it on the spot.

If you delete the file, Field writes a fresh copy with the defaults on its next run. You can use the same trick to start over: move your edited file aside and let Field make another.

Writing a shortcut

The value is a spec: some modifiers and one key, in any order, joined by +.

bindings:
  new-box: "cmd+alt+b"            # one shortcut
  execute-all: ["alt+0", "f5"]    # several, all of which work
  search-docs-and-code: ""        # no shortcut at all
  # (delete a line)               # back to Field's default

Modifiers are cmd, alt and shift. cmd means Command on macOS and Control everywhere else, so one spec covers both platforms; ctrl means the same. alt is Option on macOS. Case does not matter, and +, -, a space or a comma all separate tokens, so cmd-shift-d, CMD + SHIFT + D and cmd shift d are the same shortcut as cmd+shift+d.

Keys are a–z, 0–9, f1–f24, one of

enter escape backspace delete space tab up down left right home end pageup pagedown insert

or a punctuation character written as itself:

[ ] ' ; , . / \ - = `

Those last two rows have friendly spellings too, if you would rather not put a bare backslash in a YAML file: return, esc, del, spacebar, arrowup, bracketleft, quote, semicolon, comma, period, slash, backslash, minus, dash, equal, backquote, backtick and plus all resolve to the key they name.

A shifted character stands for Shift plus its key, which is much nicer to read than spelling the modifier out. ? is exactly shift+/, and that is how the cheatsheet's own shortcut is written. The same goes for ~ ! @ # $ % ^ & * ( ) _ { } : " < > |.

Three characters that are also separators need a word about them: a lone ,, - or + is read as a key only when it is the last thing in the spec. So cmd+, binds the comma key (that really is one of Field's defaults, "Previous Property"), cmd+- binds the minus key, and cmd + k is just cmd+k with room to breathe.

Writing a two-key chord

Two specs separated by a space make a chord: press the first, let go, press the second.

bindings:
  open-user-keybindings: "cmd+k cmd+s"   # Cmd+K, then Cmd+S
  toggle-docs: "cmd+k d"                 # Cmd+K, then a bare D

Every key ends a chord, and the modifiers written before a key belong to it. That is why cmd shift d is still one shortcut, Cmd+Shift+D: it has one key. cmd+k cmd+s has two keys, so it is a chord. A chord is at most two keys.

After the first key Field shows it at the bottom of the window ("Cmd+K … (waiting for the second key)") and waits one second. Then:

  • the second key completes a chord: that command runs, and nothing bound to the second key on its own does;
  • another key cancels the wait. If the first key is a shortcut on its own, it runs now, and the new key does whatever it normally does;
  • Escape cancels without running anything;
  • nothing, for a second: the first key runs as an ordinary shortcut, if it is one.

So a key can be a shortcut and the first half of a chord at once (cmd+k and cmd+k cmd+s), and the cost is that the plain cmd+k now fires a second late. This is the same in an editor and on the canvas. Which chords work while you are typing is covered under Where a shortcut is live.

Where a shortcut is live

Some shortcuts should not fire while you are typing, and the file records that as a comment Field wrote for you:

  new-box: "n"                    # New Box  #scope canvas
  execute-fragment: "alt+enter"   # Run Line / Selection  #scope editor
  edit-hashtag: "cmd+h"           # Edit hashtag

#scope canvas means the shortcut only fires when the canvas has focus. That is why new-box can be a bare n: pressing n in an editor types an n. #scope editor means the opposite; no comment at all means both. The scope belongs to the command, not to your spec, so it is not something you edit, but it does tell you whether a bare letter is a sensible thing to bind a command to.

The same goes for chords. In an editor, a chord whose first key has no cmd or alt does not fire, because that key is typing. The second key may be bare, so cmd+k d works in an editor too.

One line of your file sets the shortcut for both the editor and the canvas. Shortcuts follow the key's position on the keyboard, not the character it types.

Finding a command's id

The file is the index: every entry carries the command's own label as a comment, so searching it for "Bookmark" or "Format" is usually the fastest route from what you want to what to write.

The command palette works the other way round: search for the command by name, and its current shortcut is shown on the right of the row. That makes it the real test of a rebind, since those labels are drawn from the same binding your keypress would use:

Field's command palette, opened with a custom Alt+K shortcut, listing New Box with its rebound Cmd+Opt+B

The ? card is the quickest way to see your current shortcuts for the twenty or so commands you will use every day.

When you get it wrong

If a binding cannot be applied, Field tells you what went wrong.

  • A spec it cannot read is reported with the reason, as a notification and in the log — and the other lines in the file still apply, so one bad shortcut does not cost you the rest:

    keybindings.yaml: 'cmd+k cmd+s cmd+d' (for 'open-anything') is not a shortcut
      — a chord is at most two keys, like `cmd+k cmd+s` — this one has more

    The command keeps its default. A line Field cannot read is ignored, not taken as an unbind: open-anything above is still on cmd+p. Only an empty value, "", removes a shortcut.

  • A command id it does not recognize — usually a typo — is logged as a warning naming the id, and the binding is kept anyway, because the selection-only commands are not registered most of the time and their shortcuts still have to work.

  • YAML that does not parse leaves your previous shortcuts in force and says where the file is broken. A stray bracket cannot lock you out of your own keyboard.
  • Two commands on one chord logs which two, and warns you that only one of them will win. Field checks this whenever your file is involved; the defaults are our problem, not yours.

If a shortcut silently does nothing at all and there is no complaint anywhere, the usual cause is scope: a canvas-only command bound to a chord you are pressing inside an editor.

Asking Field directly

When the file says one thing and your fingers report another, a box can read the resolved bindings, the same ones the keypresses themselves consult, and settle it:

// Point the watcher at ~/.afield/keybindings.yaml — a no-op unless something moved it,
// which the rebinding figure further up this page does.
afield.app.settings.UserKeybindingsManager.watchFile(null)

val live = afield.app.settings.UserKeybindingsManager.resolved
val ids = ["new-box", "open-command-palette", "show-cheatsheet", "execute-fragment", "connect"]
// A command with no binding yet is the interesting row, so it says so in a role rather than
// looking like any other cell.
val bound =
    Table(["command", "bound to"])
        .rows(
            ids.map { id ->
                [id, (live.effective[id] ?: live.bindings[id])?.joinToString(" or ") ?: "not registered yet"]
            },
        )
        .roleBy("bound to") { if (it == "not registered yet") CellRole.WARN else null }

markdown(
    "main",
    """
    {muted:${live.displayPath.md}}

    {muted:${live.problems.size} problem(s) in it}

    ${bound.h}
""",
    width = 560,
)

A Field box listing the shortcut currently bound to five commands, read from the live keybinding layer

effective is the answer for every command Field has seen this run, override or default already applied; bindings is only what your file changed. A command in neither, such as a selection-only one with nothing selected, is reported as dormant instead of unbound, which is why the ? card leaves that legend at its written default rather than claiming the key is dead.

Limits

  • Two keys per chord, one second apart. cmd+k cmd+s works; a third key is refused with that explanation rather than half-obeyed. The one-second wait is fixed.
  • f13–f24 and some rarer keys are accepted on the canvas but may have no counterpart in the editor, where the binding is Monaco's to make. If a shortcut works on the canvas and not in an editor, that is the likely reason.
  • One file per user, not per document or per workspace, and it is not synced anywhere.
  • The gestures and multi-taps listed at the top are not in it, and neither are Monaco's built-in editor bindings.

The defaults, in full

This is the same inventory that writes your file, read out of a running Field, so it is exactly what a fresh keybindings.yaml says.

133 rebindable commands, 56 of them with a shortcut out of the box.

Agents: regenerating this table

Regenerate this table against a running Field with tools/keybindings_defaults_table.py.

Global

Command id Default Where What it does
open-anything cmd+p both Open Anything
open-command-palette cmd+shift+p or f1 both Command Palette
show-cheatsheet ? both Show Cheatsheet
toggle-docs cmd+/ both Toggle Documentation
toggle-drawing-layer alt+d both Toggle Drawing Layer

Canvas

Command id Default Where What it does
-copy (none) both Duplicate box(es)
-layout-boxes (none) both Lay out selection
-layout-document (none) both Lay out whole document
-update-check (none) both Check for updates
add-document-note (none) both Add Note to This Document
add-editor-to-output (none) both Add Editor to Output Area
align (none) both Align boxes
anchor-drawing-to-boxes (none) both Anchor Drawing to Boxes
auto-display-editor (none) both Auto-display Editor
connect g canvas Connect boxes
copy-box-guide-link (none) both Copy Markdown Link to Box or Line
copy-selection cmd+c canvas Copy Selection
delete-box cmd+backspace or cmd+delete both Delete Box(es)
disable-auto-displaying-editor (none) both Disable Auto-displaying Editor
disconnect u canvas Disconnect boxes
edit-hashtag cmd+h both Edit hashtag
export-document-edn (none) both Export document (.edn)
export-ipynb (none) both Export notebook (.ipynb)
export-selection-edn (none) both Export selection (.edn)
fmt-kotlin (none) both Format Kotlin
fmt-property (none) both Format
frame-selected alt+f both Frame Selected
insert-from-workspace cmd+t both Insert template
macro-transcript-panel (none) both Macro: Recorder Panel
macro-transcript-run (none) both Macro: Run on Selection
macro-transcript-save (none) both Macro: Mark End & Save
macro-transcript-start (none) both Macro: Mark Start
macro-transcript-undo (none) both Macro: Undo on Selection
make-function-study (none) both Make a Function Study
make-rectsl-scene (none) both Make a RectSL Scene
make-stacksl-program (none) both Make a StackSL Program
move-forward (none) both Move selected boxes forward
nest-into (none) both Nest selection into a box
new-box n canvas New Box
normalize-nested-pan (none) both Normalize Nested contents
open-user-keybindings (none) both Open Keybindings
open-user-theme (none) both Open User Theme
paste-selection cmd+v canvas Paste Selection
provisional-accept-all (none) both Accept All Provisional (Everywhere)
provisional-reject-all (none) both Reject All Provisional (Everywhere)
record-selected-box-mp4 (none) both Record Selected Box MP4
record-selected-editor-mp4 (none) both Record Selected Editor MP4
record-window-mp4 (none) both Record Window MP4
relink-pane (none) both Relink Pane
reloadPersonal (none) both Reload personal/ classes
reload-user-keybindings (none) both Reload Keybindings
remove-canvas-split (none) both Remove Canvas Split
reset (none) both Reset Kotlin Environment for Box
reset-canvas-zoom (none) both Reset Canvas Zoom
reset-view alt+h both Reset View
route (none) both Route (position-guided)
save-as-template (none) both Save selection as template
search-docs-and-code cmd+shift+d both Search Documentation & Code
select-all-boxes (none) both Select All Boxes
set-main-language (none) both Set Main Language
set-main-language-clojure (none) both Set Main Language: Clojure
set-main-language-csound (none) both Set Main Language: Csound
set-main-language-datalog (none) both Set Main Language: Datalog
set-main-language-fieldml (none) both Set Main Language: FieldML
set-main-language-forth (none) both Set Main Language: ForthField
set-main-language-kotlin (none) both Set Main Language: Kotlin
set-main-language-kotlinjs (none) both Set Main Language: Kotlin → head
set-main-language-lua (none) both Set Main Language: Lua
set-main-language-morpho (none) both Set Main Language: MorphoHDL
set-main-language-nano (none) both Set Main Language: Nano
set-main-language-pd (none) both Set Main Language: Pure Data
set-main-language-python (none) both Set Main Language: Python
set-main-language-rectsl (none) both Set Main Language: RectSL
set-main-language-remotejs (none) both Set Main Language: Javascript
set-main-language-stacksl (none) both Set Main Language: StackSL
show-all-layers (none) both Show All Layers
show-document-guide (none) both Show Document Guide
show-document-history (none) both Show Document History
show-layers-panel alt+l both Show Layers Panel
show-profiling-timeline (none) both Show Profiling Timeline
snap_tidy (none) both Snap + tidy boxes
solo-next-layer alt+] both Solo Next Layer
solo-previous-layer alt+[ both Solo Previous Layer
split-canvas-columns-here (none) both Split Canvas Columns Here
split-canvas-here (none) both Split Canvas Here
split-canvas-rows-here (none) both Split Canvas Rows Here
switch-to-docs-iframe (none) both Read the Field Documentation
switch-to-monaco-editor (none) both Switch to Monaco Editor
toggle-box-snapping (none) both Toggle Box Snapping
toggle-keypress-display (none) both Toggle Keypress Display
toggle-notes-markdown-preview cmd+shift+m both Toggle Markdown Preview
un-nest (none) both Un-nest selection
unlink-pane (none) both Unlink Pane
unlink-pane-horizontally (none) both Unlink Pane Horizontally
unlink-pane-vertically (none) both Unlink Pane Vertically

Editor

Command id Default Where What it does
ai-assist alt+o editor Apply Intelligence
ai-assist-error alt+shift+o editor Apply Intelligence to Error message
ai-chat cmd+3 editor AI Chat in editor
ai-chat-panel cmd+4 editor AI Chat (panel)
back-next-property cmd+, editor Previous Property
continue-all alt+shift+up editor Continue Box
execute-all alt+0 editor Run Box
execute-fragment alt+enter editor Run Line / Selection
forward-next-property cmd+. editor Next Property
history-lens-selection alt+shift+h editor Show Code History for Line / Selection
launch-all alt+up editor Launch Box
launch-fragment alt+1 editor Launch Line / Selection
paired-shader-definition f12 editor Go to Paired Shader Definition
provisional-accept-current (none) editor Accept All Provisional (This Editor)
provisional-reject-current (none) editor Reject All Provisional (This Editor)
send-to-preamble alt+shift+p editor Move code to preamble
stop-all alt+down or alt+shift+down editor Stop Box
toggle-fold-current-line cmd+' editor Toggle Fold on Current Line
update-shader alt+shift+enter editor Update Shader

Bookmarks

Command id Default Where What it does
restore-bookmark-1 shift+f1 both Restore Bookmark 1
restore-bookmark-2 shift+f2 both Restore Bookmark 2
restore-bookmark-3 shift+f3 both Restore Bookmark 3
restore-bookmark-4 shift+f4 both Restore Bookmark 4
restore-bookmark-5 shift+f5 both Restore Bookmark 5
restore-bookmark-6 shift+f6 both Restore Bookmark 6
restore-bookmark-7 shift+f7 both Restore Bookmark 7
restore-bookmark-8 shift+f8 both Restore Bookmark 8
restore-bookmark-9 shift+f9 both Restore Bookmark 9
save-bookmark-1 cmd+shift+f1 both Save Bookmark 1
save-bookmark-2 cmd+shift+f2 both Save Bookmark 2
save-bookmark-3 cmd+shift+f3 both Save Bookmark 3
save-bookmark-4 cmd+shift+f4 both Save Bookmark 4
save-bookmark-5 cmd+shift+f5 both Save Bookmark 5
save-bookmark-6 cmd+shift+f6 both Save Bookmark 6
save-bookmark-7 cmd+shift+f7 both Save Bookmark 7
save-bookmark-8 cmd+shift+f8 both Save Bookmark 8
save-bookmark-9 cmd+shift+f9 both Save Bookmark 9
show-bookmarks alt+b both Show Bookmarks

See also

  • Survival Guide — the shortcuts worth learning first.
  • Feature Overview — what the commands in that table actually do.
  • Layers — the layer commands (alt+l, alt+], alt+[) in use.