Use emacs-style undo.
Rather than truncating the undo stack when making an edit after undoing, the undo steps themselves are pushed onto the undo stack before the edit. This means that the undo stack never loses any previous states of the document, and those states are always accessible by just undoing enough.
This commit is contained in:
parent
693cdf078c
commit
5ad3f0ce8c
|
@ -15,7 +15,7 @@ impl History {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_edit(&mut self, edit: Transaction) {
|
pub fn push_edit(&mut self, edit: Transaction) {
|
||||||
self.edits.truncate(self.position);
|
self.commit();
|
||||||
self.edits.push(edit);
|
self.edits.push(edit);
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
}
|
}
|
||||||
|
@ -38,4 +38,19 @@ impl History {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes the current undo state, and pushes that as another transaction on
|
||||||
|
/// top of the existing undo stack, without deleting any existing items.
|
||||||
|
pub fn commit(&mut self) {
|
||||||
|
if self.position == self.edits.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut undo_trans = Transaction::new();
|
||||||
|
for trans in self.edits[self.position..].iter().rev() {
|
||||||
|
undo_trans = undo_trans.compose(&trans.inverse());
|
||||||
|
}
|
||||||
|
self.edits.push(undo_trans);
|
||||||
|
self.position = self.edits.len();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,6 +294,32 @@ impl Transaction {
|
||||||
trans
|
trans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a transaction that is the inverse of this one (i.e. the "undo"
|
||||||
|
/// of this transaction).
|
||||||
|
pub fn inverse(&self) -> Transaction {
|
||||||
|
let mut inv = Transaction::new();
|
||||||
|
|
||||||
|
for op in self.ops.iter() {
|
||||||
|
match op {
|
||||||
|
Op::Retain(byte_count) => {
|
||||||
|
inv.retain(*byte_count);
|
||||||
|
}
|
||||||
|
Op::Replace {
|
||||||
|
old: old_range,
|
||||||
|
new: new_range,
|
||||||
|
} => {
|
||||||
|
// Swap old and new to do the inverse.
|
||||||
|
let old = &self.buffer[new_range.0..new_range.1];
|
||||||
|
let new = &self.buffer[old_range.0..old_range.1];
|
||||||
|
|
||||||
|
inv.replace(old, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inv
|
||||||
|
}
|
||||||
|
|
||||||
/// Applies the Transaction to a Rope.
|
/// Applies the Transaction to a Rope.
|
||||||
pub fn apply(&self, text: &mut Rope) {
|
pub fn apply(&self, text: &mut Rope) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user