std/keybindings

Key bindings, as editors have them: keys as text, chords of several strokes, conditions on when a binding applies, defaults for each platform, and the user's bindings over them.

import "std/keybindings"

KeyMap keys = key_map([
    KeyBinding("mod+s", "file.save"),
    KeyBinding("ctrl+k ctrl+c", "editor.comment", condition: "textFocus && !readOnly"),
], user_bindings)?
map[str, Json] context = {"textFocus": Json.BOOL(true)}
KeyOutcome o = keys.press(key_stroke("k", ctrl: true), context)   // pending
o = keys.press(key_stroke("c", ctrl: true), context)               // editor.comment

Keys are written as strokes separated by spaces, each its modifiers and key joined by +: ctrl, alt (or option), shift, meta (or cmd, win, super), and mod, which is Cmd on macOS and Ctrl elsewhere; keys are characters or enter, escape, tab, space, backspace, delete, the arrows up, down, left, and right, home, end, page_up, page_down, insert, and f1 to f24.

Function or method
parse_keys(text, platform) the KeyStrokes of keys as text: key, ctrl, alt, shift, meta
format_keys(strokes, platform) as people read them: Ctrl+K Ctrl+S, or ⌘S on macOS
key_stroke(key, ctrl, alt, shift, meta) a stroke, as a key event gives it
when_holds(condition, context) whether a condition holds: names of values in context, !, &&, `
key_map(defaults, user, platform) a KeyMap; a user binding whose command starts with - takes away that command's bindings, of its keys when it gives some
keys.press(stroke, context) a KeyOutcome: the command and args of the last binding added whose keys and condition match, or pending while a chord waits for its next stroke
keys.cancel(), keys.keys_for(command, context) forgets a chord started; the keys a menu shows for a command
key_bindings_from_json(value) bindings as an editor's keybindings.json writes them: key, command, when, args, and mac, linux, and win for other keys there

A KeyBinding has keys, command, condition, args, and mac, linux, and windows keys for those platforms.