feat(desktop): list Files changed's keys in a ? sheet and on the Keyboard shortcuts page

Merged
DA
19h ago
+478-59

What was asked

Files changed (the Pull request tab's diff view) already answers stage-cli's keys, but nothing listed them. This adds stage-cli's ? sheet, and lists the same keys on Settings › Keyboard shortcuts. Both read the one table the handler matches against, so the lists can't drift from the real bindings.

What changed

  • One declarative table. @luke/settings/shortcuts now holds FILES_CHANGED_KEY, FILES_CHANGED_SHORTCUTS (a label and a chord per key) and FILES_CHANGED_SHORTCUT_GROUPS, using stage-cli's groups: General, Navigation, Review. filesChangedKeyFor(event) matches a press against that table through the existing shortcutMatches.
  • Handler reads the table. changes-list.tsx drops its hand-written FILE_KEY / fileKeyOf letter checks. What each key does is a record that must cover every key in the table (satisfies Record<FilesChangedKey, …>), so a key added to the table won't build until it's handled. FOLD_CHORD (the fold buttons' hints) now reads from the table too.
  • ; and / are read by where they sit on the keyboard. A new placed flag on SHORTCUT_KEY.SEMICOLON and SLASH makes a plain chord (no ⌘) match event.code, because Shift turns ; into : and / into ?. This keeps the old by-position reading of ; and ⇧;. ⌘/ (Keyboard shortcuts) still matches by character, as the menu bar does. Also adds SHORTCUT_KEY.V.
  • ? (⇧/) sheet. files-changed-keys.tsx is a @luke/ui Dialog at wide size. Each group is a SettingsSection with SettingsRows at list density, and each chord is drawn by the app's Shortcut, exactly as the Keyboard shortcuts page draws them. Escape, Done, a click on the dimmed window, or ? again closes it, and focus goes back into the view.
  • Where ? works. Like the other plain keys, only while focus is inside Files changed and you're not typing in a field. No app command uses plain ?.
  • Settings page. A "Files changed" group is added below the window's groups, and settings search finds its rows.
  • Fewer edge-case differences: Escape with ⇧ held no longer clears the file focus, since the table's Escape is the bare key.

Coordination

  • I (show or hide minimized comments) is in #3789, which isn't merged, so it isn't in this table yet. Whichever PR lands second adds it as a FILES_CHANGED_KEY row in the Review group, plus a line in the record in changes-list.tsx.
  • The same goes for ⇧F (file tree) from the tree work. It would go in a new group, like stage-cli's "Panels".

Tests

  • agent-changes-tab.test.ts:
    • every row of the table is pressed by its own chord inside the view, and each one is answered;
    • ? opens a sheet listing each group, label and drawn chord, and Escape or ? again closes it;
    • ? does nothing outside the view (with the window keymap mounted) or when typed into the tree's search.
  • desktop-settings.test.ts: Keyboard shortcuts lists the Files changed group with its chords, and search finds a row of it.
  • shortcuts.test.ts: every Files changed key appears in exactly one group of the sheet.

Checks

The per-package fallback, because pnpm check:affected ran out of memory in this sandbox (on desktop tsc and service vitest):

  • per-package tsc for settings, panel and desktop: passed
  • vitest for panel tasks, settings, settings search, desktop settings and the command palette: 1075 passed
  • ./scripts/oxlint.sh, biome, pnpm knip, pnpm discarded-effect, ./scripts/repository-checks.sh: passed
  • apps/desktop node scripts/build.mjs: bundle budget passed

This is desktop/panel only, so no Preview run.

Screenshots

Rendered from this branch's built styles.css (Linux fonts).

LightDark
? sheetsheet lightsheet dark
Settings › Keyboard shortcutspage lightpage dark

Made with Luke


Devin Review