Repository navigation
Back SimpleUndoRedoProvider with ktsu.UndoRedo [minor] - #68
Merged
Merged
Conversation
SimpleUndoRedoProvider now adapts IUndoRedoProvider onto ktsu.UndoRedo's UndoRedoService instead of keeping its own List-based stacks. The public contract (IUndoRedoProvider, IUndoableAction, the constructor, and the GetUndoStack/GetRedoStack accessors) is unchanged. - Each registered action is wrapped in a command that skips its first Execute. UndoRedoService.Execute runs a command as it records it, but Navigation<T>.NavigateTo has already navigated by the time it registers. - UndoRedoService 1.1.4 moves its position before running a command. On its own, a failed undo would leave the action on the redo stack as though it had worked, and a failed redo would leave it on the undo stack. The adapter moves the position back without running the action again, so a throwing undo or redo still leaves the history where it was. - Merging and change navigation are switched off. Navigation actions are never merged. ktsu.UndoRedo.Core does not reference ktsu.Navigation, so no package cycle exists. New SimpleUndoRedoProviderTests pin the provider's behaviour: registering without executing, stack order, redo truncation, history trimming, stack accessors, StateChanged, and failed undo and redo. Fixes #46 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAvt7dvjcukkH3y6mtUL16
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



This implements the 2026-09-28 decision on #46 (option 2: accept the DI dependency).
SimpleUndoRedoProvideris now an adapter that keepsIUndoRedoProviderand is backed byktsu.UndoRedo.Core1.1.4'sUndoRedoService. The public contract is unchanged:IUndoRedoProvider,IUndoableAction, the constructor andGetUndoStack/GetRedoStack.The decision accepted that "a throwing
Undoloses its history entry". I re-measured this against 1.1.4, and the entry is not lost.UndoRedoServicemoves its position before it runs the command. So on its own:Redo()then runsExecute()on an action that was never undone.The 2026-09-22 probe read "
CanUndoisfalseafterward" as the command being gone. With a single command on the stack, that is what the cursor moving past it looks like.That is a state inconsistency, not the history loss that was accepted. So the adapter compensates: on a throw, it moves the position back with a skipped
Execute/Undo, then rethrows. The provider's failed-undo and failed-redo behaviour is therefore exactly what it was before: the action stays where it was. Both cases are pinned by tests.This is local handling of an upstream gap, which the reuse rule would prefer fixed in
ktsu.UndoRedo. It is about 20 lines. IfUndoRedoServicelater restores its position on a throw, the compensation can go and the tests will still hold. If you would rather ship the raw 1.1.4 behaviour instead, remove the twocatchblocks and flip the two tests.The adapter
Executewrapper: each registeredIUndoableActionis wrapped in a privateICommand.UndoRedoService.Executeruns a command as it records it, butNavigation<T>.NavigateTohas already navigated by the time it registers.MaxStackSize=maxHistorySize,AutoMergeCommandsoff (navigation actions are never merged),EnableNavigationoff.GetUndoStack()andGetRedoStack()are derived fromCommandsandCurrentPosition. They keep their old order: each list ends with the action the next undo or redo would run.StateChanged: still raised once per register, undo, redo and clear, and not on a failed one.Package graph (UndoRedo#109)
ktsu.UndoRedo.Core1.1.4 depends onMicrosoft.Extensions.DependencyInjection(.Abstractions),System.Memory,System.Text.JsonandSystem.Threading.Tasks.Extensions. It has no reference toktsu.Navigation, so Navigation → UndoRedo creates no cycle.ktsu.UndoRedoalready defines its ownINavigationProvider. That leaves both routes the decision names open for UndoRedo#109, and neither needs anything from this PR.#57 (locking for
NavigationStack) touchesNavigationStack.cs, which this PR does not change.Tests
SimpleUndoRedoProviderTestshas 11 new tests:falseClearStateChangedThe suite has 29 tests, all passing locally (net10.0). The full solution builds across every target, netstandard2.0 through net10.0.
This is a refactor, so all 29 tests also pass against the old
List-based implementation, which is the point. Removing each piece of the adapter makes them fail:Executewrapper: 4 fail, includingRegisterAction_DoesNotExecuteTheAction.docs/API.mdanddocs/Architecture.mdnow describe the adapter and its dependency.Fixes #46
🤖 Generated with Claude Code
https://claude.ai/code/session_01TAvt7dvjcukkH3y6mtUL16
Generated by Claude Code