Skip to content

Declare the app's macOS menu — its accelerators are undocumented chords #119

Description

@samkeen

crates/b2-desktop/tauri.conf.json sets no menu, so Tauri's Menu::default() applies. That means ⌘Q, ⌘W, ⌘M, ⌘H, ⌥⌘H, ⌘Z, ⇧⌘Z, ⌘X, ⌘C, ⌘V, ⌘A and ⌃⌘F are live in the app today, appear in no documentation, and can't — nothing enumerates them.

They're also invisible to the keyboard registry by construction: AppKit dispatches menu key equivalents inside NSApplication.sendEvent before the key window's responder chain, so these never reach the webview's keydown handler at all. (This is also why the Edit menu is load-bearing rather than decorative — without it, copy/paste in the webview breaks.)

Why it's a gap and not just untidiness. Invariant K1 promises every action has a keyboard path and that the path is findable. Since #118 the ? sheet is a projection of ui/src/bindings.ts, and shortcuts.test.ts fails on a binding no row documents — so every binding is now guaranteed discoverable. These aren't bindings, they're inherited, so they sit outside that guarantee entirely.

The work. Declare the menu explicitly in b2-desktop rather than introspecting an opaque default — you can't document what you can't enumerate, and a declared menu is B2's own data. Then export its accelerators through an ordinary #[tauri::command] (deserialize → one call → serialize, per the thin-adapter rules) and fold them into the registry as reserved chords, so conflicts() sees them and the sheet can list them.

Worth doing on its own merits, and a sensible prerequisite for shortcut customization: a rebinding UI can't warn about a chord nothing can enumerate.

Source: docs/design/invariants.md K1, crates/b2-desktop/CLAUDE.md (the four obligations), ui/src/bindings.ts (module header, on what the registry does and doesn't own).

Left over from the keyboard-registry work in #118 — Layer 3 of the collision-detection plan.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions