Skip to content

feat(editor): register Space/Escape with the host shortcut service (#39, #40) - #66

Merged
cchacs merged 2 commits into
mainfrom
pullfrog/40-remove-document-key-listener
Oct 9, 2026
Merged

cchacs merged 2 commits into
mainfrom
pullfrog/40-remove-document-key-listener

Conversation

@pullfrog

@pullfrog pullfrog Bot commented Oct 9, 2026

Copy link
Copy Markdown

What & why

Completes the keybind migration from #10. This lands #39 (migrate Space and Escape) as the prerequisite for #40 (remove the document-level listener), because #40 could not be done without it.

  • Space (Play / pause) and Escape (Close the top layer, or clear the selection) now register through window.registerShortcut({ key, handler, description, scope: 'plugin-editor' }), alongside the editing keys from Keybinds 2/4: migrate the editing keys (Delete, Backspace, G, F, K) to registerShortcut #38, so the global ? help panel lists them.
  • onKeyDown is reduced to the gates that genuinely cannot be registry rows, plus an inert compatibility fallback for the migrated keys:
    • can't be shortcuts: the swallow-all read-only lenses and tool palette, Select All policy, the recording gate, and the profile-dependent plain tool keys;
    • fallback: the Space/Escape/Delete/Drum branches, which now stand down the moment editorShortcutState.registered is true, so a key is never handled twice.

Collision resolution (from #39 / the #37 audit)

  • The Host's built-in Space/Escape are Player-scoped, so they do not fire on the #plugin-editor screen; the editor's own registrations are plugin-editor so they only fire there. This is the reason the editor keeps its own Space rather than delegating to the host's.
  • Escape keeps today's fall-through: the handler preventDefault()s only when it actually consumed the key, leaving an unowned Escape to the Host's back-to-library.
  • The registered Escape handler yields to every overlay that owns Escape through its own handler: the host-owned transient modals, the in-app text/choice prompts, the anchor sweep and a tempo-zones proposal. The read-only Tracks overview and a live take still ignore Escape, and the ladder order (lenses → menu → palette → tap-tempo → suggest ghosts → barline → note/drum selection) is preserved.
  • Space accepts both the raw event (e.key === ' ') and the Host's e.code === 'Space' token form.

Testing

  • node --test — 400 pass, 0 fail (new suite: Space/Escape registration, the full Escape ladder including ghost-before-barline precedence, the parts-view/prompt guards, and an explicit no-double-handling test asserting onKeyDown stands down once the registry is active).
  • npx eslint@9.39.4 src tests — 0 errors (3 pre-existing warnings unchanged).

Not verified here

  • The running-app check that the ? panel renders every shortcut: no desktop/browser host is available in this environment. The registrations carry descriptions and plugin-editor scope, which is what the panel reads.
  • A mid-take Space finalize test: _recState is a module-private live binding with no test setter, and driving editorStartRecordMidi() needs a real MIDI device + audio. _editorTogglePlayShortcut deliberately omits the recording gate (Space finalizes a take), so the behavior is structural.

Closes #39
Closes #40
Part of #10

Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

…, #40)

Move the editor's Space (transport) and Escape (dismissal ladder) handling onto window.registerShortcut({ scope: 'plugin-editor' }) so the global ? panel lists them, and reduce onKeyDown to the gates that cannot be registry rows plus an inert fallback for hosts without the API. One key press, one action: the fallback stands down when editorShortcutState.registered is true.
@pullfrog
pullfrog Bot requested a review from cchacs October 9, 2026 19:01
@pullfrog

pullfrog Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Author

Diagnosis: The failing check suite (102901624981) belonged to CodeFactor, not GitHub Actions CI. Its single annotation was a "Complex Method" on the new src/input.js:1924-1973 (_editorEscape) — the same gate the base commit 680fea8 addressed for _editorDeleteSelection.

Fix: Split _editorEscape into a thin ordered dispatcher plus three private rung helpers, mirroring the existing _editorDelete* pattern:

  • _editorEscapeOverlays() — lens / context-menu / tool-palette closes
  • _editorEscapeTempoState() — suggest-ghost dismiss, then barline multi-selection clear
  • _editorEscapeClearSelection() — note/drum selection clear

The ladder order, gates (parts-view, recording, tap-tempo, typing), and fall-through semantics are unchanged; the inline typing guard now uses the existing _editorIsTypingTarget helper. ESLint complexity dropped from 27 to 10 for _editorEscape (helpers 6–8), comfortably under the 15 that CodeFactor already accepts.

Verification: npm test 400/400 pass; npm run lint 0 errors (3 pre-existing warnings). After pushing f4fe84a, CodeFactor reports "No issues found" and ci / js, ci / python, and lint all pass.

Task list (7/7 completed)
  • Checkout PR branch
  • Fetch check suite logs
  • Verify failure introduced by PR
  • Diagnose and fix
  • Reproduce/verify fix locally
  • Commit and push
  • Report progress

Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

@kilo-code-bot

kilo-code-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • src/input.js
  • src/shortcut-registry.js
  • src/main.js
  • tests/keybind_registration.test.mjs
  • CHANGELOG.md

Reviewed by free · Input: 655.3K · Output: 8.9K · Cached: 583.2K

@cchacs
cchacs merged commit 973bad0 into main Oct 9, 2026
6 checks passed
@cchacs
cchacs deleted the pullfrog/40-remove-document-key-listener branch October 9, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant