Skip to content

Extract IUndoRenameLogic narrow port; inject it into UndoManager in place of IRenameLogic (ADR-0005 Phase 3)#3356

Merged
vchelaru merged 1 commit into
mainfrom
undo-rename-port
Jun 25, 2026
Merged

Extract IUndoRenameLogic narrow port; inject it into UndoManager in place of IRenameLogic (ADR-0005 Phase 3)#3356
vchelaru merged 1 commit into
mainfrom
undo-rename-port

Conversation

@vchelaru

Copy link
Copy Markdown
Owner

What

Mirrors #3355 (IUndoPluginNotifier), this time for IRenameLogic — the last shell-only ctor dependency UndoManager held before it can be relocated headless (ADR-0005 Phase 3).

UndoManager injected the full, MEF/WinForms-entangled IRenameLogic but called only three of its ~12 methods — HandleRename, GetChangesForRenamedVariable, ApplyVariableRenameChanges — all with headless GumDataTypes/ToolsUtilities parameters. This PR extracts those three calls into a narrow port, IUndoRenameLogic, in the headless Gum.Presentation assembly, and injects that port into UndoManager in place of IRenameLogic.

How

  • New port Tools/Gum.Presentation/Undo/IUndoRenameLogic.cs (namespace Gum.Undo, alongside IUndoManager / IUndoPluginNotifier) — exactly the 3 members.
  • Relocated 5 data types out of the tool's Gum/Logic/RenameLogic.cs into Tools/Gum.Presentation/Logic/RenameChangeTypes.cs — the 3 methods' closure pulled them in: NameChangeAction + SideOfEquals enums, and VariableChange / VariableReferenceChange / VariableChangeResponse. All are framework-neutral (GumDataTypes/ToolsUtilities only). They keep the Gum.Logic namespace, so the ~20 tool-side consumers compile unchanged (the file physically moves assemblies; the namespace travels with the types). Confirmed via an assembly-graph sweep that no consumer compiles into GumCommon/Gum.ProjectServices (which would have forced them lower) — every consumer is in the tool Gum.dll or its test assembly.
  • RenameLogic implements it — its existing method signatures matched the port exactly, so : IRenameLogic, IUndoRenameLogic was all that was needed — no shim/adapter.
  • DI (Builder.cs) registers RenameLogic as its own singleton and resolves both IRenameLogic and IUndoRenameLogic to it, so the rename calls fire against the same instance as before (mirrors the PluginManager 3-line pattern).
  • UndoManager field/ctor param IRenameLogic _renameLogicIUndoRenameLogic _renameLogic; the 3 call sites are unchanged (field name kept).

Behavior-preserving

The three rename calls route through the narrow port unchanged. This is the canonical refactoring-direction "narrow port over an entangled dependency" pattern. With it landed, all of UndoManager's ctor deps are now headless (ISelectedState, IUndoRenameLogic, IGuiCommands, IFileCommands, IMessenger, IUndoPluginNotifier) — and its body references no tool-only types — so the class itself can be relocated to Gum.Presentation in a follow-up. This PR does NOT move UndoManager. File-disjoint from #3355.

Tests

  • The two existing rename-delegation pinning tests now mock Mock<IUndoRenameLogic> (covering GetChangesForRenamedVariable / ApplyVariableRenameChanges).
  • Added PerformUndo_OnElementRename_ShouldDelegateToRenameLogicHandleRename to pin the third call (HandleRename) — red-first verified (disabling the seam produced "No invocations performed").
  • Full GumToolUnitTests suite green: 1000 passed, 0 failed, 4 pre-existing skips. AllPluginsCompositionTests confirms plugins still compose via MEF.
  • Gum.Presentation builds standalone (zero WPF/WinForms leak); GumFull.sln builds with 0 errors.

Manual test: not needed — behavior-preserving narrow-port swap + type relocation, proven by the compiler (GumFull.sln + standalone Gum.Presentation), the full unit suite, and the red-first pinning check.

🤖 Generated with Claude Code

…lace of IRenameLogic (ADR-0005 Phase 3)

Mirrors #3355 (IUndoPluginNotifier). UndoManager injected the full, MEF/WinForms-entangled IRenameLogic but called only three of its ~12 methods (HandleRename, GetChangesForRenamedVariable, ApplyVariableRenameChanges), all with headless GumDataTypes/ToolsUtilities parameters.

This extracts those three calls into a narrow port, IUndoRenameLogic, in the headless Gum.Presentation assembly, and injects that port into UndoManager in place of IRenameLogic. The three methods' closure pulled five small data types out of the tool's Gum/Logic/RenameLogic.cs (NameChangeAction + SideOfEquals enums; VariableChange / VariableReferenceChange / VariableChangeResponse) which are relocated to Tools/Gum.Presentation/Logic/RenameChangeTypes.cs, keeping the Gum.Logic namespace so the ~20 tool-side consumers compile unchanged.

RenameLogic's signatures matched exactly, so ': IRenameLogic, IUndoRenameLogic' was all that was needed (no adapter). DI registers RenameLogic as its own singleton and resolves both interfaces to it, so rename calls fire as before. This is the last shell-only ctor dependency UndoManager held; with it ported, all of UndoManager's ctor deps are now headless, a prerequisite for relocating the class itself headless in a later PR. This PR does NOT move UndoManager.

Tests: the two existing rename-delegation pinning tests now mock Mock<IUndoRenameLogic>. Added PerformUndo_OnElementRename_ShouldDelegateToRenameLogicHandleRename to pin the third call (HandleRename) - red-first verified (disabling the seam produced 'No invocations performed'). Full GumToolUnitTests suite green: 1000 passed, 0 failed, 4 pre-existing skips. AllPluginsCompositionTests confirms plugins still compose via MEF. Gum.Presentation builds standalone (zero WPF/WinForms leak).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vchelaru vchelaru merged commit 88d4b60 into main Jun 25, 2026
3 checks passed
@vchelaru vchelaru deleted the undo-rename-port branch June 25, 2026 19:44
vchelaru added a commit that referenced this pull request Jun 25, 2026
…esentation (ADR-0005 Phase 3) (#3357)

First concrete logic class (not just a contract) to cross the headless boundary, unblocked by #3355 (IUndoPluginNotifier) and #3356 (IUndoRenameLogic), which drained UndoManager's last two tool-coupled ctor deps. All 6 ctor deps are now headless interfaces and the body references no tool-only types.

- git mv Gum/Undo/UndoManager.cs and AfterUndoMessage.cs -> Tools/Gum.Presentation/Undo/. Namespace stays Gum.Undo, so Builder.cs DI and all consumers (incl. PluginManager's AfterUndoMessage handler) compile unchanged.

- Drop now-stale usings Gum.Managers and Gum.Wireframe.

- Localize the tool-only StateSave.SetFrom extension as a private UndoManager.SetStateContentsFrom helper (UndoManager was its only caller in the repo); remove the orphan from StateSaveExtensionMethodsGumTool. FixEnumerations is now unconditional, matching prior tool behavior (the extension guarded it with #if GUM, and GUM is defined in the tool build).

- Delete the dead GetWhatToApplyTo method and its only-consumer UndoObject.cs.

- Grant Gum.Presentation InternalsVisibleTo GumToolUnitTests so UndoManagerTests keeps reaching the internal UndoLocks; Gum.csproj already granted this via AssemblyInfo, so the grant moves with the class.

Behavior-preserving. Verified: Gum.Presentation compiles standalone (0 errors, no WPF/WinForms leak); GumFull.sln builds (0 errors); GumToolUnitTests 1000 passed / 0 failed / 4 skipped.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vchelaru added a commit that referenced this pull request Jun 25, 2026
…s Gum.Presentation (ADR-0005 Phase 3) (#3360)

git mv Gum/Logic/IReferenceFinder.cs -> Tools/Gum.Presentation/Logic/IReferenceFinder.cs, and extract the reference-result types it returns (ElementReferences, InstanceReferences, StateReferences, BehaviorReferences, CategoryReferences) out of the WPF-entangled Gum/Logic/RenameLogic.cs into a new headless file Tools/Gum.Presentation/Logic/ReferenceTypes.cs (mirroring the RenameChangeTypes.cs precedent from #3356).

All five types — not the three named in the original scoping — had to move: IReferenceFinder also returns StateReferences and CategoryReferences, so the port could not compile in Gum.Presentation without them. VariableChangeResponse, the sixth return type, was already relocated in #3356. The full dependency closure is framework-neutral (GumDataTypes + the already-relocated VariableChange/VariableReferenceChange), so nothing tool-only crossed the boundary.

Namespace stays Gum.Logic for every moved type, so tool-side consumers (RenameLogic, the concrete ReferenceFinder, DeleteLogic, EditCommands) compile unchanged. The concrete impl (Gum/Logic/ReferenceFinder.cs, DI-registered in Builder.cs) stays in the shell. Behavior-preserving: Gum.Presentation compiles standalone (no WPF leak), GumFull.sln builds clean, and 982 GumToolUnitTests pass.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant