Rearview
This is an Elixir library inspired by this excellent writeup (HN discusion).
It implements an Emacs-style undo-stack which does not throw away state when you undo steps and then do more edits. Instead, the whole history of edits is preserved as a linear timeline. This provides the end-user with a way to travel back and forth in time without the fear of losing work.
Usage
Rearview is just a library, so you have to keep the Rearview state on your side. In this example, we are storing integers to keep track of the order of inserts.
{:ok, state} = Rearview.init()
{:ok, state} = Rearview.record(1, state)
{:ok, state} = Rearview.record(2, state)
{:ok, 1, state} = Rearview.undo(state)
{:ok, 2, state} = Rearview.redo(state)
{:error, :nothing_to_redo} == Rearview.redo(state)
{:ok, state} = Rearview.record(3, state)
{:ok, state} = Rearview.record(4, state)
{:ok, 3, state} = Rearview.undo(state)
{:ok, 2, state} = Rearview.undo(state)
{:ok, 1, state} = Rearview.undo(state)
{:ok, state} = Rearview.record(1.50, state)
{:ok, state} = Rearview.record(1.75, state)
{:ok, 1.50, state} = Rearview.undo(state)
{:ok, 1.75, state} = Rearview.redo(state)
{:ok, 1.50, state} = Rearview.undo(state)
{:ok, 1, state} = Rearview.undo(state)
{:ok, 2, state} = Rearview.undo(state)
{:ok, 3, state} = Rearview.undo(state)
{:ok, 4, state} = Rearview.undo(state)
{:ok, 3, state} = Rearview.undo(state)
{:ok, 2, state} = Rearview.undo(state)
{:ok, 1, state} = Rearview.undo(state)
{:error, :nothing_to_undo} = Rearview.undo(state)Memory cosumption
Rearview stores the states you record (not diffs) so it can consume quite a bit of memory (even though it's de-duplicated). If each state is large it might be worth switching on compression.
Installation
If available in Hex, the package can be installed
by adding rearview to your list of dependencies in mix.exs:
def deps do
[
{:rearview, "~> 0.1.0"}
]
endDocumentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/gurc.