Undo/redo stack for reversible commands. Pure data structure, no processes.
Each command provides an apply function and an undo function. The stack
tracks entries as {apply_fn, undo_fn} pairs so that undo moves an entry
to the redo stack (calling undo_fn) and redo moves it back (calling
apply_fn).
Max size
The undo stack is bounded by :max_size (default 100).
When a push exceeds the limit, the oldest entries are dropped. The redo
stack is unbounded (it can only shrink or be cleared, never grow past
the undo stack size).
Coalescing
Commands with the same :coalesce key that arrive within
:coalesce_window_ms of each other are merged into a single undo entry.
The merged entry keeps the original undo function (so one undo reverses
all coalesced changes) and composes the apply functions.
Example
iex> u = Plushie.Undo.new(0)
iex> cmd = %{apply: &(&1 + 1), undo: &(&1 - 1)}
iex> u = Plushie.Undo.push(u, cmd)
iex> Plushie.Undo.current(u)
1
iex> u = Plushie.Undo.undo(u)
iex> Plushie.Undo.current(u)
0
Summary
Functions
Return true if there are entries on the redo stack.
Return true if there are entries on the undo stack.
Return the current model.
Return the labels from the undo stack, most recent first.
Create a new undo stack with model as the initial state.
Push a command onto the undo stack, updating the current model. Clears the redo stack.
Redo the last undone command. Returns unchanged if the redo stack is empty.
Undo the last command. Returns unchanged if the undo stack is empty.
Types
@type t() :: %Plushie.Undo{ current: term(), max_size: pos_integer(), redo_stack: [entry()], undo_size: non_neg_integer(), undo_stack: [entry()] }
Functions
Return true if there are entries on the redo stack.
Return true if there are entries on the undo stack.
Return the current model.
Return the labels from the undo stack, most recent first.
Create a new undo stack with model as the initial state.
Options
:max_size- maximum number of undo entries (default 100). When exceeded, the oldest entries are dropped silently.
Push a command onto the undo stack, updating the current model. Clears the redo stack.
The command must be a map with :apply and :undo keys (both single-arity
functions). Optional keys: :label, :coalesce, :coalesce_window_ms.
If the command carries a :coalesce key that matches the top of the undo
stack and the time delta is within :coalesce_window_ms, the entry is
merged rather than pushed.
When the undo stack exceeds :max_size, the oldest entries are dropped.
Redo the last undone command. Returns unchanged if the redo stack is empty.
Undo the last command. Returns unchanged if the undo stack is empty.