Repository navigation
fix: attribute action extension handlers by identity; add enabled_when action registration - #561
Conversation
ActionExtensionRegistry keyed its addon map by handler function name, so addons registering same-named handlers (print-and-cut, sketcher) collided: disabling one left stale handlers behind or stripped the other addon's handlers. The map is now keyed by handler identity, and registering an already-registered handler is a no-op. The register_actions hook is now also invoked when an addon is enabled while the window exists, and action_registry.register() accepts an enabled_when predicate that ActionManager evaluates on every action state update. Addons can therefore create, place and enable/disable their actions in the register_actions hook alone, without action_extension_registry. Plugin API 22.
🤖 Estimated LLM implementation costReplayed each of the 1 commits in this pull request and counted the code lines each commit added or rewrote:
Added lines by language: Python 163, Markdown 9 Full estimate
Cost model: ≈10 tokens per code line at $15/Mtok output and $3/Mtok input (assuming heavy prompt caching); input ≈ 15× output for conversation replay; a review round ≈ 42,000 tokens; a failed CI run ≈ 21,000 tokens; file reads capped at 20 kB each. Active window from first commit to merge: <1 day.
|
Summary
Two related changes to the action registration machinery, preparing the
ground for #552:
Identity-keyed handler attribution.
ActionExtensionRegistrykeyedits addon map by
handler.__name__. Every addon following theextension pattern names its module-level handlers
_register_actionsand
_update_action_states— sketcher and print-and-cut alreadycollide on main. Because the map held one entry per name, disabling the
addon that registered last removed all same-named handlers, and
disabling any other addon removed none (stale handlers survived
unload, and the next
invoke_setup_handlersran code from an unloadedmodule). The map is now keyed by handler identity, and registering an
already-registered handler is a no-op.
Declarative action state (plugin API 22).
action_registry.register()accepts anenabled_whenpredicate thatreceives the
ActionManagerand is evaluated on every action stateupdate, after the extension handlers. The
register_actionshook isalso invoked again when an addon is enabled while the window exists
(
MainWindow._on_addon_state_changed), so a runtime-enabled addon getsits actions created without the extension registry. An addon can now
create, place, and enable/disable its actions in the
register_actionshook alone — this retires theaction_extension_registryindirection for new addons; migratingsketcher and print-and-cut can follow separately.
Verification
tests/ui_gtk/test_action_registries.py(6 tests): same-namehandler attribution, idempotent setup/state registration,
enabled_whenstorage, predicate evaluation, and isolation of afailing predicate.
pixi run lintand targeted suites:test_action_registries,test_move_head_here_action,test_mainwindow,addon_managerall pass.