Skip to content

Latest commit

 

History

History
203 lines (149 loc) · 4.09 KB

quickstart.md

File metadata and controls

203 lines (149 loc) · 4.09 KB

Quick Start

Rundo can help your data struct has undo redo ability painless. Thanks Rust Procedural Macros, you only need add a attr before your struct!

Just one line support undo/redo

Assume you have a struct Point, as below.

struct Point {
    x: f32,
    y: f32,
}

After add #[rundo] before Point, undo redo was supported. that all! A full demo:

#![feature(proc_macro)]
#![feature(decl_macro)]

extern crate rundo;
use rundo::prelude::*;

#[rundo]
struct Point {
    x: f32,
    y: f32,
}

fn main(){

  let mut space = Workspace::new(Point! {x: 2.0, y: 2.0,});

  // x will chgange to 3.0
  *space.get_mut().x = 3.0;
  assert_eq!(*space.data.x, 3.0);

  // x will chgange to 4.0
  *space.get_mut().x = 4.0;
  assert_eq!(*space.data.x, 4.0);

  // x will undo to 3.0
  space.undo();
  assert_eq!(*space.data.x, 3.0);

  // x will undo to 2.0
  space.undo();
  assert_eq!(*space.data.x, 2.0);

  // x will redo to 3.0
  space.redo();
  assert_eq!(*space.data.x, 3.0);
}

Note the macro Point! at the first line of main function, why not use Point {...} ? That because Rundo redefined origin Point type with the same shape, but support undo redo. You can use it as same as before, but to literal construct must use a same name macro replace. And remenber, to use undo redo, must place struct in Rundo Workspace.

Batch changes

In some case we want merge mulit change to one action, of cause:

#![feature(proc_macro)]
#![feature(decl_macro)]

extern crate rundo;
use rundo::prelude::*;

#[rundo]
struct Point {
    x: f32,
    y: f32,
}

fn main(){

  let mut space = Workspace::new(Point! {x: 2.0, y: 2.0,});

  {
    let point = &mut space.get_mut();   // <----+
    // x change many times              //      |
    *point.x = 5.0;                     //      |
    *point.x = 6.0;                     //      |
    *point.x = 7.0;                     //      |
    *point.x = 8.0;                     //      |
  }//--------- point life time -----------------+

  // undo will direct back to 2.0
  space.undo();
  assert_eq!(*space.data.x, 2.0);
}

Like what your see, all change in point life time will merge together.

Multi get_mut() life time can also be batched:

#![feature(proc_macro)]
#![feature(decl_macro)]

extern crate rundo;
use rundo::prelude::*;

#[rundo]
struct Point {
    x: f32,
    y: f32,
}

fn main(){
  let mut space = Workspace::new(Point! {x: 2.0, y: 2.0,});

  space.begin_op();
  {
    let point = &mut space.get_mut();
    *point.x = 3.0;
  }

  {
    let point = &mut space.get_mut();
    *point.x = 4.0;
  }
  space.end_op();

  // undo will direct back to 2.0
  space.undo();
  assert_eq!(*space.data.x, 2.0);
}

begin_op and end_op can be nested pair call.

You can access and modify Point across Workspace.data directly, like:

#![feature(proc_macro)]
#![feature(decl_macro)]

extern crate rundo;
use rundo::prelude::*;

#[rundo]
struct Point {
    x: f32,
    y: f32,
}

fn main(){
  let mut space = Workspace::new(Point! {x: 2.0, y: 2.0,});
  {
    let point = &mut space.data;
    // modify also allowed
    *point.x = 3.0;
  }

  // but undo not work, x not rollback to 2.0
  space.undo();
  assert_eq!(*space.data.x, 3.0);
}

if you directly modify value, the change isn't captured automatic. You can manaul capture by begin_op and end_op.

Skip Specified Field

If some field you don't want use undo redo, #[rundo(skip)] can skip it.

#![feature(proc_macro)]
#![feature(decl_macro)]

extern crate rundo;
use rundo::prelude::*;

#[rundo]
struct Point {
    #[rundo(skip)]
    x: f32,
    y: f32,
}

fn main() {
    let mut space = Workspace::new(Point! {x: 2.0, y: 2.0,});
    space.get_mut().x = 5.0;
    *space.get_mut().y = 6.0;

    space.undo();
    // x change will be not capture, undo will not affect it.
    assert_eq!(space.data.x, 5.0);
    // but y is undo to 2.0
    assert_eq!(*space.data.y, 2.0);
}

Custom Impl Rundo

You have a special struct, and want to implement undo redo by yourself, that easy, just implement the Rundo Trait.

.... Sorry, It's time to sleep, I will write this section in this weekend.