Fix undo/redo not updating the syntax tree.

imgbot
Blaž Hrastnik 4 years ago
parent b39849dde1
commit c0e17dd324

@ -57,37 +57,31 @@ impl History {
self.cursor == 0 self.cursor == 0
} }
pub fn undo(&mut self, state: &mut State) { // TODO: I'd like to pass Transaction by reference but it fights with the borrowck
pub fn undo(&mut self) -> Option<Transaction> {
if self.at_root() { if self.at_root() {
// We're at the root of undo, nothing to do. // We're at the root of undo, nothing to do.
return; return None;
} }
let current_revision = &self.revisions[self.cursor]; let current_revision = &self.revisions[self.cursor];
// TODO: pass the return value through? It should always succeed
let success = current_revision.revert.apply(state);
if !success {
panic!("Failed to apply undo!");
}
self.cursor = current_revision.parent; self.cursor = current_revision.parent;
Some(current_revision.revert.clone())
} }
pub fn redo(&mut self, state: &mut State) { pub fn redo(&mut self) -> Option<Transaction> {
let current_revision = &self.revisions[self.cursor]; let current_revision = &self.revisions[self.cursor];
// for now, simply pick the latest child (linear undo / redo) // for now, simply pick the latest child (linear undo / redo)
if let Some((index, transaction)) = current_revision.children.last() { if let Some((index, transaction)) = current_revision.children.last() {
let success = transaction.apply(state);
if !success {
panic!("Failed to apply redo!");
}
self.cursor = *index; self.cursor = *index;
return Some(transaction.clone());
} }
None
} }
} }
@ -120,17 +114,27 @@ mod test {
assert_eq!("hello 世界!", state.doc()); assert_eq!("hello 世界!", state.doc());
// --- // ---
fn undo(history: &mut History, state: &mut State) {
if let Some(transaction) = history.undo() {
transaction.apply(state);
}
}
fn redo(history: &mut History, state: &mut State) {
if let Some(transaction) = history.redo() {
transaction.apply(state);
}
}
history.undo(&mut state); undo(&mut history, &mut state);
assert_eq!("hello world!", state.doc()); assert_eq!("hello world!", state.doc());
history.redo(&mut state); redo(&mut history, &mut state);
assert_eq!("hello 世界!", state.doc()); assert_eq!("hello 世界!", state.doc());
history.undo(&mut state); undo(&mut history, &mut state);
history.undo(&mut state); undo(&mut history, &mut state);
assert_eq!("hello", state.doc()); assert_eq!("hello", state.doc());
// undo at root is a no-op // undo at root is a no-op
history.undo(&mut state); undo(&mut history, &mut state);
assert_eq!("hello", state.doc()); assert_eq!("hello", state.doc());
} }
} }

@ -509,13 +509,17 @@ pub fn insert_char_prompt(prompt: &mut Prompt, c: char) {
// Undo / Redo // Undo / Redo
pub fn undo(view: &mut View, _count: usize) { pub fn undo(view: &mut View, _count: usize) {
view.doc.history.undo(&mut view.doc.state); if let Some(revert) = view.doc.history.undo() {
view.doc.apply(&revert);
}
// TODO: each command could simply return a Option<transaction>, then the higher level handles storing it? // TODO: each command could simply return a Option<transaction>, then the higher level handles storing it?
} }
pub fn redo(view: &mut View, _count: usize) { pub fn redo(view: &mut View, _count: usize) {
view.doc.history.redo(&mut view.doc.state); if let Some(transaction) = view.doc.history.redo() {
view.doc.apply(&transaction);
}
} }
// Yank / Paste // Yank / Paste

@ -108,7 +108,6 @@ impl Document {
}; };
} }
// TODO: needs to run on undo/redo
pub fn apply(&mut self, transaction: &Transaction) -> bool { pub fn apply(&mut self, transaction: &Transaction) -> bool {
let old_doc = self.text().clone(); let old_doc = self.text().clone();

Loading…
Cancel
Save