do state = %{done: [], undone: []} GenServer.start_link(__MODULE__, state, name: __MODULE__) end def execute(commands), do: GenServer.call(__MODULE__, {:execute, commands}) def undo(), do: GenServer.call(__MODULE__, :undo) def redo(), do: GenServer.call(__MODULE__, :redo) def handle_call({:execute, commands}, _from, state) do commands = List.wrap(commands) Enum.each commands, fn command -> {mod, args} = command apply(mod, :execute, List.wrap(args)) end {:reply, :ok, %{state | done: Enum.reverse(commands) ++ state.done}} end def handle_call(:undo, _from, state=%{done: [command|t]}) do {mod, args} = command apply(mod, :unexecute, List.wrap(args)) state = %{state | done: t, undone: [command | state.undone]} {:reply, :ok, state} end def handle_call(:redo, _from, state=%{undone: [command|t]}) do {mod, args} = command apply(mod, :execute, List.wrap(args)) state = %{state | undone: t, done: [command | state.done]} {:reply, :ok, state} end end