From 9936bb2efad7eb9d9130bdb6a7494bb0e4117e08 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 10 Feb 2022 09:04:53 -0700 Subject: [PATCH] Undo subsequent edits when undoing in multi-buffer When undoing in the multi-buffer, don't preserve edits that occurred outside the multi-buffer after the edit being undone. Co-Authored-By: Antonio Scandurra --- crates/editor/src/multi_buffer.rs | 4 +- crates/language/src/buffer.rs | 28 ++++++++------ crates/text/src/text.rs | 64 +++++++++++++++++-------------- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index c22b592e2a..c516489f96 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -560,7 +560,7 @@ impl MultiBuffer { for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions { if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) { undone |= buffer.update(cx, |buf, cx| { - buf.undo_transaction(*buffer_transaction_id, cx) + buf.undo_to_transaction(*buffer_transaction_id, cx) }); } } @@ -583,7 +583,7 @@ impl MultiBuffer { for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions { if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) { redone |= buffer.update(cx, |buf, cx| { - buf.redo_transaction(*buffer_transaction_id, cx) + buf.redo_to_transaction(*buffer_transaction_id, cx) }); } } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 0be632fecd..dcc96fb9b0 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1695,7 +1695,7 @@ impl Buffer { } } - pub fn undo_transaction( + pub fn undo_to_transaction( &mut self, transaction_id: TransactionId, cx: &mut ModelContext, @@ -1703,13 +1703,15 @@ impl Buffer { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); - if let Some(operation) = self.text.undo_transaction(transaction_id) { + let operations = self.text.undo_to_transaction(transaction_id); + let undone = !operations.is_empty(); + for operation in operations { self.send_operation(Operation::Buffer(operation), cx); - self.did_edit(&old_version, was_dirty, cx); - true - } else { - false } + if undone { + self.did_edit(&old_version, was_dirty, cx) + } + undone } pub fn redo(&mut self, cx: &mut ModelContext) -> Option { @@ -1725,7 +1727,7 @@ impl Buffer { } } - pub fn redo_transaction( + pub fn redo_to_transaction( &mut self, transaction_id: TransactionId, cx: &mut ModelContext, @@ -1733,13 +1735,15 @@ impl Buffer { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); - if let Some(operation) = self.text.redo_transaction(transaction_id) { + let operations = self.text.redo_to_transaction(transaction_id); + let redone = !operations.is_empty(); + for operation in operations { self.send_operation(Operation::Buffer(operation), cx); - self.did_edit(&old_version, was_dirty, cx); - true - } else { - false } + if redone { + self.did_edit(&old_version, was_dirty, cx) + } + redone } pub fn completion_triggers(&self) -> &[String] { diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 743217dfe2..20f0e422c8 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -280,19 +280,19 @@ impl History { } } - fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&HistoryEntry> { + fn remove_from_undo(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] { assert_eq!(self.transaction_depth, 0); + + let redo_stack_start_len = self.redo_stack.len(); if let Some(entry_ix) = self .undo_stack .iter() .rposition(|entry| entry.transaction.id == transaction_id) { - let entry = self.undo_stack.remove(entry_ix); - self.redo_stack.push(entry); - self.redo_stack.last() - } else { - None + self.redo_stack + .extend(self.undo_stack.drain(entry_ix..).rev()); } + &self.redo_stack[redo_stack_start_len..] } fn forget(&mut self, transaction_id: TransactionId) { @@ -322,19 +322,19 @@ impl History { } } - fn remove_from_redo(&mut self, transaction_id: TransactionId) -> Option<&HistoryEntry> { + fn remove_from_redo(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] { assert_eq!(self.transaction_depth, 0); + + let undo_stack_start_len = self.undo_stack.len(); if let Some(entry_ix) = self .redo_stack .iter() .rposition(|entry| entry.transaction.id == transaction_id) { - let entry = self.redo_stack.remove(entry_ix); - self.undo_stack.push(entry); - self.undo_stack.last() - } else { - None + self.undo_stack + .extend(self.redo_stack.drain(entry_ix..).rev()); } + &self.undo_stack[undo_stack_start_len..] } } @@ -1203,14 +1203,18 @@ impl Buffer { } } - pub fn undo_transaction(&mut self, transaction_id: TransactionId) -> Option { - if let Some(entry) = self.history.remove_from_undo(transaction_id) { - let transaction = entry.transaction.clone(); - let op = self.undo_or_redo(transaction).unwrap(); - Some(op) - } else { - None - } + pub fn undo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { + let transactions = self + .history + .remove_from_undo(transaction_id) + .iter() + .map(|entry| entry.transaction.clone()) + .collect::>(); + + transactions + .into_iter() + .map(|transaction| self.undo_or_redo(transaction).unwrap()) + .collect() } pub fn forget_transaction(&mut self, transaction_id: TransactionId) { @@ -1228,14 +1232,18 @@ impl Buffer { } } - pub fn redo_transaction(&mut self, transaction_id: TransactionId) -> Option { - if let Some(entry) = self.history.remove_from_redo(transaction_id) { - let transaction = entry.transaction.clone(); - let op = self.undo_or_redo(transaction).unwrap(); - Some(op) - } else { - None - } + pub fn redo_to_transaction(&mut self, transaction_id: TransactionId) -> Vec { + let transactions = self + .history + .remove_from_redo(transaction_id) + .iter() + .map(|entry| entry.transaction.clone()) + .collect::>(); + + transactions + .into_iter() + .map(|transaction| self.undo_or_redo(transaction).unwrap()) + .collect() } fn undo_or_redo(&mut self, transaction: Transaction) -> Result {