undo 0.3.1

An undo/redo library with state awareness and automatic command merging.
Documentation

Undo

A undo/redo library.

It uses the Command Pattern where the user implements the UndoCmd trait for each command and then the commands can be used with the UndoStack.

The UndoStack has two different states, clean and dirty. The stack is in a clean state when there are no more commands that can be redone, otherwise it's in a dirty state. The stack can be configured to call a given method when this state changes, using the on_clean and on_dirty methods.

The UndoStack also supports easy merging of commands by just implementing the id method for a given command.

Build Status Crates.io Docs

[dependencies]
undo = "0.3.0"

Example

extern crate undo;

use std::rc::Rc;
use std::cell::RefCell;
use undo::{UndoCmd, UndoStack};

/// Pops an element from a vector.
#[derive(Clone)]
struct PopCmd {
    vec: Rc<RefCell<Vec<i32>>>,
    e: Option<i32>,
}

impl UndoCmd for PopCmd {
    fn redo(&mut self) {
        self.e = self.vec.borrow_mut().pop();
    }

    fn undo(&mut self) {
        self.vec.borrow_mut().push(self.e.unwrap());
        self.e = None;
    }
}

fn main() {
    // We need to use Rc<RefCell> since all commands are going to mutate the vec.
    let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
    let mut stack = UndoStack::new()
        .on_clean(|| println!("This is called when the stack changes from dirty to clean!"))
        .on_dirty(|| println!("This is called when the stack changes from clean to dirty!"));

    let cmd = PopCmd { vec: vec.clone(), e: None };
    stack.push(cmd.clone());
    stack.push(cmd.clone());
    stack.push(cmd.clone());

    assert!(vec.borrow().is_empty());

    stack.undo(); // on_dirty is going to be called here.
    stack.undo();
    stack.undo();

    assert_eq!(vec.borrow().len(), 3);
}