Skip to content

GetChangeVisualizations/GetCommandsToUndo return lazy queries over the live stack, so enumerating after a change reports the current command as not executed #95

Description

@matt-edmondson

What's wrong

UndoRedoService.GetChangeVisualizations (UndoRedo/Services/UndoRedoService.cs) captures some values when it is called: commands.Count (inside Take) and currentPosition. It then returns a deferred LINQ Select over the live _stackManager.Commands, with the saveBoundaries list also read at enumeration time.

GetCommandsToUndo is deferred in the same way.

Enumerating the result after the stack changes mixes the old snapshot with the new state.

Failure scenario

service.Execute(Cmd("A"));
var viz = service.GetChangeVisualizations();
service.Execute(Cmd("C"));
foreach (var v in viz) Console.WriteLine($"{v.Command.Description} executed={v.IsExecuted}");
  • Actual: C is listed with IsExecuted = False, even though it is the current, applied command. currentPosition is stale while the command list is live.
  • In a similar case, the list is cut at the old count while HasSaveBoundary reflects the new boundaries.
  • GetCommandsToUndo(boundary) taken at position 1 and enumerated after an Undo() still returns [A, B].

Any UI that caches the returned IEnumerable (for example a history panel bound to it, or one enumerated on a later frame or on another thread) shows wrong executed/saved markers. With concurrent modification it can also hit InvalidOperationException from the underlying list.

Suggested fix

Materialize both results before returning them ([.. query] / .ToList()), so each call returns a consistent snapshot of its own moment.

Acceptance criteria

  • A result taken before an Execute/Undo and enumerated afterwards reflects the state at the time of the call.
  • This is covered by a test for each of the two methods.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions