Q-W6: registration table (OCP) in main.cpp; bank verbs -> shell/bank_ops(Session&); persist.h + wav_trim + namespaces.h shims deleted; 61/61

capture.h realtime seam split to capture_realtime_shell.h; GetProjExtState grow-loop rehomed to core/wire/ext_state_read; stale persist.cpp/bank_panel.cpp comment refs fixed; CLAUDE.md persist/bank_book/actions bullets updated. Command-id suffixes, display phrases, and undo labels byte-identical.
This commit is contained in:
2026-07-29 13:40:09 -04:00
parent 4831e0e172
commit f3be4d8cce
81 changed files with 970 additions and 1085 deletions
+61 -7
View File
@@ -1,13 +1,30 @@
#pragma once
// action_registry — shared registration plumbing for the bindable action families
// (Q-W4 split of actions.cpp). Owns the durable interned-string store both the
// Design View and multi-bank families register through, so a composed command id
// keeps ONE stable pointer from register to the mirror-unregister, and the
// register-a-command_id-then-gaccel sequence has one implementation.
// action_registry — shared registration plumbing + the Q-W6 registration TABLE.
//
// Two layers, one TU:
//
// * The Q-W4 plumbing (channelIdFor / registerAction): the durable interned-string
// store the action families register through, so a composed command id keeps ONE
// stable pointer from register to the mirror-unregister, and the
// register-a-command_id-then-gaccel sequence has one implementation. The
// design_view / bank / ingest families still register row-by-row through this.
//
// * The Q-W6 registration TABLE (ActionTableRow + registerActionTable /
// actionTableHandleCommand / actionTableCommandId / unregisterActionTable): the
// data-driven home of main.cpp's own action family (capture scopes, panel toggle,
// insert, batch, realtime, recapture, version). One row = one action (FOREVER-
// STABLE id suffix, display phrase, flat function-pointer handler); registration
// iterates the rows, hookcommand dispatch walks the same rows, and unload
// mirror-unregisters from them — adding an action touches the table only (OCP).
// Handlers are plain function pointers (a static dispatch walk, no std::function,
// no virtual — the §3 performance guardrail); gaccel + interned-id storage is
// owned here for the module lifetime, so REAPER's held pointers stay valid and
// the '-command_id' unregister re-presents the IDENTICAL pointer registered.
//
// Includes reaper_plugin.h (gaccel_register_t / reaper_plugin_info_t full defs);
// only the action-family TUs include this header. Q-W6's registration table
// subsumes this helper when the hand-written blocks become data.
// only the action-family TUs and main.cpp include this header.
#include <cstddef>
#include "reaper_plugin.h" // reaper_plugin_info_t, gaccel_register_t
@@ -26,4 +43,41 @@ const char* channelIdFor(const char* suffix);
int registerAction(reaper_plugin_info_t* rec, const char* suffix,
gaccel_register_t& accel, const char* phrase);
// --- The registration table (Q-W6) -------------------------------------------
// One bindable action. `suffix` and `phrase` are the channel-AGNOSTIC pieces (the
// registry composes the full id/label via channelCommandId / channelActionName);
// both must have static storage duration (string literals, or a pure static table
// like captureActionTable()). `run` fires when the minted command does; `arg` is an
// opaque per-row value passed through to it (e.g. a captureActionTable row index, or
// a bool-like flag), so sibling actions can share one handler without captures.
struct ActionTableRow {
const char* suffix; // FOREVER-STABLE command-id suffix — never change shipped
const char* phrase; // Actions-list display phrase (after the channel prefix)
void (*run)(int arg); // handler — a flat function pointer, no state
int arg = 0; // opaque per-row handler argument
};
// Registers every row (command_id -> gaccel, via the same interning plumbing as
// registerAction) in table order. Rows are COPIED into registry-owned storage whose
// element addresses never move (REAPER holds each gaccel pointer until unload).
// Call once at load; a failed command_id mint (cmd 0) leaves that row inert but
// still mirror-unregistered on unload (harmless, matches the pre-table behavior).
void registerActionTable(reaper_plugin_info_t* rec, const ActionTableRow* rows,
std::size_t count);
// Dispatches one fired command: fires the matching row's handler and returns true;
// false when the command belongs to no table row (caller's hookcommand keeps
// looking, per the claim-only contract). A flat walk over the registered rows.
bool actionTableHandleCommand(int command);
// The minted command id for `suffix` (0 when unregistered / mint failed). For the
// callers that need a raw command id outside dispatch — e.g. the toggleaction
// checked-state hook resolving TOGGLE_BANK_PANEL once at load.
int actionTableCommandId(const char* suffix);
// Mirror-unregisters every table row (reverse table order): '-gaccel' with the same
// held storage, '-command_id' with the SAME interned pointer used at register.
void unregisterActionTable(reaper_plugin_info_t* rec);
} // namespace reasampler