081b6f1028
Pure planner classifies missing/unreadable/unrepresentable and repairs transport names; the verb digests, streams and commits atomically over a const session.
7.0 KiB
7.0 KiB
src/shell/actions — bindable REAPER actions, drag/drop shells, ingest
Scope
The bindable action families routed through REAPER's command_id/gaccel/
hookcommand contract (Design View toggle actions, bank actions, the prune
action, and the shared registration plumbing/table), plus the three drag-out
outcome shells (OS hand-off, instrument drop, arrange drop), plus the
extension-side ingest-through-the-bank shell. This is
where user-facing REAPER actions and OS-level drag/drop live; the underlying
mutation logic (bank verbs, prune's orphan computation, view-mode reconciliation)
is owned by other directories and only skinned here.
Invariants
- Ingest is an extension act; the instrument is a read-only bank consumer. Any instrument code path that captures, imports, inserts a timeline item, or writes back into the bank is a bug — the instrument reads and plays only.
arrange_drop_winis the only timeline-placing shell IN THIS DIRECTORY — the claim scopes here, not to the system:shell/captureholds two more (RunInsertSelectedandrender_in_place, the third verb).arrange_drop_winplaces because the USER dragged a card onto the arrange. RootCLAUDE.md's capture/placement separation forbids a CAPTURE placing an item; a deliberate drop is placement on demand. No other module here may grow anInsertMediacall.- Ingest NEVER inserts a timeline item. Arrange capture→bank→assign reuses the
existing capture add-path and assigns the resulting
Sampleid to the target instance; it never places anything on the timeline — capture/placement separation is load-bearing here same as everywhere else. Only the arrange-capture surface writes theassignment_requestwire; Media-Explorer import and file-drop onto the bank panel do not, and neither affects a live instance's selection. - Every bank index verb wraps its mutation in a batched REAPER undo point
(
Undo_BeginBlock2/EndBlock2,UNDO_STATE_MISCCFG) so one bank operation is one Ctrl-Z. - The prune action is the ONLY file-deletion action in the system; it opens no
undo point (file deletion is not REAPER-undoable). It halts on
blockedByTrackingand prints whichever blockers fired — the malformed ledger, the offendingrsusage_*key names, or both.
Modules
shell/actions(action_registry/design_view_actions/bank_actions/prune_action) — the bindable action families, all routed via thecommand_id/gaccel/hookcommandcontract.action_registryowns the shared registration plumbing (interned channel-qualified id strings; register and mirror-unregister present the identical pointer) and the Q-W6 registration TABLE:main.cpp's own family (capture scopes, panel toggle, insert, batch, realtime, recapture, version) is oneActionTableRowarray — suffix, phrase, flat function-pointer handler — that registration, hookcommand dispatch, and the unload mirror-unregister all iterate, so adding an action touches the table only (OCP). Bank mutations flow through the promptlessshell/bank_opsverbs (bankOp*+persistBankOp, takingReaSamplerSession&), which the panel menus andbank_actionsconsume as thin UX skins. Every bank index verb wraps its mutation in a batched REAPER undo point (Undo_BeginBlock2/EndBlock2,UNDO_STATE_MISCCFG) so one bank operation is one Ctrl-Z. The prune action (prune_action,BANK_PRUNE_FOLDER) is the ONLY file-deletion action in the system; it opens no undo point (file deletion is not REAPER-undoable).BANK_PRUNE_FOLDERhalts onblockedByTrackingand prints each blocker that fired, with recovery instructions.package_export_action— the "export bank as package" skin: survey and report first, confirm what is absent (and, separately, a destination being replaced), pick a destination, write. Every prompt in the flow lives here soshell/package/export_bankstays promptless. Read-only against the project — it holds the session byconst&, so no ext-state write, generation bump or undo point is reachable. Registration ridesmain.cpp's action table (EXPORT_BANK_PACKAGE); the panel's tab menu is the second skin over the same body.drag_out_win— OS drag-out shell: Windows OLEDoDragDrop/CF_HDROP, copy-only (DROPEFFECT_MOVEnot offered); macOS/Linux viaSWELL_InitiateDragDropOfFileList.instrument_drop_win— instrument-drop shell:probeDropTargetresolves a screen point to a track + aReaperSurface(via the purewire::classifyReaperSurface, whose token rulescore/wire/CLAUDE.mdowns), and the drop half adds a ReaSampler 9000 instance and applies the dragged capture's state via a transient.vstpreset+TrackFX_SetPreset(the formerTrackFX_SetNamedConfigParm"vst_chunk" write was silently unappliable for VST3). ExposesloadInstrumentOntoTrack(inner half, no own undo block) andperformInstrumentDrop(wraps in its own undo block). Never captures, never writes the bank, never inserts a timeline item.arrange_drop_win— the drag-out gesture's arrange outcome:arrangeTimeAtScreenX(pointer column → time viaGetSet_ArrangeView2's one-pixel-span reading — inferred, not SDK-documented) andperformArrangeDrop(snap the drop time, then oneInsertMediaper capture on the pointer's track — assumed, not confirmed, to land end-to-end via REAPER's own cursor advance — in ONE undo block, counting only InsertMedia's reported successes, with the caller's track selection and edit cursor restored). The one timeline-placing shell here, per the invariant above; it never captures and never writes the bank.ingest— ingest-through-the-bank shell on the EXTENSION side: three surfaces — (1) arrange capture→bank→assign (bindable action), (2) Media-Explorer import→bank→instrument on the selected track, (3) file drop onto the bank panel→bank only. Only surface (1) writes theassignment_requestext-state wire. ingest NEVER inserts a timeline item. Surface (2)'s action is the one in this directory published into a NON-main action section (Media Explorer) as well as Main — two ids, one handler, two dispatch hooks; see rootCLAUDE.md§"REAPER extension contract" for the mechanism.
Gotchas
- Structural wart, partly closed:
ingest.cpp/ingest.hnow live in this directory.ext_keys.handresource.hstill sit atsrc/root:ext_keys.his consumed mostly fromshell/instrument/, so it is not this directory's to claim, andresource.his a build input paired withsrc/resource.rc(the SWELL resgen step) rather than a shell module. - Media-Explorer import is single-file, pull-on-action (
OpenMediaExplorer+MediaExplorerGetLastPlayedFileInfo) — there is no enumerate-selected-files or register-a-drop-handler API on the Media Explorer surface. - REAPER exposes no drag-drop registration API; drop handling is only on
ReaSampler's own HWNDs (
WM_DROPFILES/IDropTargeton the dockedbank_panel). A drop onto the VST3 editor window relaying to the extension is an unproven spike, not a shipped path.