@@ -0,0 +1,127 @@
1+use crate::{ChangeSet, Rope, State, Transaction};
2+
3+/// Undo-tree style history store.
4+pub struct History {
5+ revisions: Vec<Revision>,
6+ cursor: usize,
7+ //
8+}
9+
10+#[derive(Debug)]
11+struct Revision {
12+ // prev: usize,
13+ parent: usize,
14+ /// The transaction to revert to previous state.
15+ revert: Transaction,
16+ // selection before, selection after?
17+}
18+
19+impl Default for History {
20+ fn default() -> Self {
21+ // Add a dummy root revision with empty transaction
22+ Self {
23+ revisions: vec![Revision {
24+ parent: 0,
25+ revert: Transaction::from(ChangeSet::new(&Rope::new())),
26+ }],
27+ cursor: 0,
28+ }
29+ }
30+}
31+
32+impl History {
33+ pub fn commit_revision(&mut self, transaction: &Transaction, original: &State) {
34+ // TODO: store both directions
35+ // TODO: could store a single set if deletes also stored the text they delete
36+ let revert = transaction.invert(original);
37+
38+ let new_cursor = self.revisions.len();
39+ self.revisions.push(Revision {
40+ parent: self.cursor,
41+ revert,
42+ });
43+ self.cursor = new_cursor;
44+
45+ // TODO: child tracking too?
46+ }
47+
48+ #[inline]
49+ pub fn at_root(&self) -> bool {
50+ self.cursor == 0
51+ }
52+
53+ pub fn undo(&mut self, state: &mut State) {
54+ if self.at_root() {
55+ // We're at the root of undo, nothing to do.
56+ return;
57+ }
58+
59+ let current_revision = &self.revisions[self.cursor];
60+ // unimplemented!("{:?}", revision);
61+ // unimplemented!("{:?}", state.doc().len_chars());
62+ // TODO: pass the return value through?
63+ let success = current_revision.revert.apply(state);
64+
65+ if !success {
66+ panic!("Failed to apply undo!");
67+ }
68+
69+ self.cursor = current_revision.parent;
70+ }
71+
72+ pub fn redo(&mut self, state: &mut State) {
73+ let current_revision = &self.revisions[self.cursor];
74+
75+ // TODO: pick the latest child
76+
77+ // if !success {
78+ // panic!("Failed to apply undo!");
79+ // }
80+
81+ unimplemented!()
82+ }
83+}
84+
85+#[cfg(test)]
86+mod test {
87+ use super::*;
88+
89+ #[test]
90+ fn test_undo_redo() {
91+ let mut history = History::default();
92+ let doc = Rope::from("hello");
93+ let mut state = State::new(doc);
94+
95+ let transaction1 =
96+ Transaction::change(&state, vec![(5, 5, Some(" world!".into()))].into_iter());
97+
98+ // Need to commit before applying!
99+ history.commit_revision(&transaction1, &state);
100+ transaction1.apply(&mut state);
101+ assert_eq!("hello world!", state.doc());
102+
103+ // ---
104+
105+ let transaction2 =
106+ Transaction::change(&state, vec![(6, 11, Some("世界".into()))].into_iter());
107+
108+ // Need to commit before applying!
109+ history.commit_revision(&transaction2, &state);
110+ transaction2.apply(&mut state);
111+ assert_eq!("hello 世界!", state.doc());
112+
113+ // ---
114+
115+ history.undo(&mut state);
116+ assert_eq!("hello world!", state.doc());
117+ history.redo(&mut state);
118+ assert_eq!("hello 世界!", state.doc());
119+ history.undo(&mut state);
120+ history.undo(&mut state);
121+ assert_eq!("hello", state.doc());
122+
123+ // undo at root is a no-op
124+ history.undo(&mut state);
125+ assert_eq!("hello", state.doc());
126+ }
127+}