diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 26d7f2f875..a3c62295f7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -3527,7 +3527,11 @@ impl Editor { .buffer .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) { - self.selection_history.get_mut(&tx_id).unwrap().1 = Some(self.selections.clone()); + if let Some((_, end_selections)) = self.selection_history.get_mut(&tx_id) { + *end_selections = Some(self.selections.clone()); + } else { + log::error!("unexpectedly ended a transaction that wasn't started by this editor"); + } } } @@ -3952,6 +3956,7 @@ impl View for Editor { self.focused = true; self.blink_cursors(self.blink_epoch, cx); self.buffer.update(cx, |buffer, cx| { + buffer.avoid_grouping_next_transaction(cx); buffer.set_active_selections(&self.selections, cx) }); } diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index f3d906e27d..4cedfa80d2 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -457,6 +457,12 @@ impl MultiBuffer { } } + pub fn avoid_grouping_next_transaction(&mut self, cx: &mut ModelContext) { + for BufferState { buffer, .. } in self.buffers.borrow().values() { + buffer.update(cx, |buffer, _| buffer.avoid_grouping_next_transaction()); + } + } + pub fn set_active_selections( &mut self, selections: &[Selection], diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index eae15fe5af..05128776b6 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1234,6 +1234,10 @@ impl Buffer { } } + pub fn avoid_grouping_next_transaction(&mut self) { + self.text.avoid_grouping_next_transaction(); + } + pub fn set_active_selections( &mut self, selections: Arc<[Selection]>, diff --git a/crates/rpc/src/conn.rs b/crates/rpc/src/conn.rs index a0db932876..70c59d013b 100644 --- a/crates/rpc/src/conn.rs +++ b/crates/rpc/src/conn.rs @@ -1,5 +1,5 @@ use async_tungstenite::tungstenite::{Error as WebSocketError, Message as WebSocketMessage}; -use futures::{channel::mpsc, SinkExt as _, Stream, StreamExt as _}; +use futures::{SinkExt as _, Stream, StreamExt as _}; use std::{io, task::Poll}; pub struct Connection { @@ -57,7 +57,7 @@ impl Connection { Box>, Box>>, ) { - use futures::SinkExt as _; + use futures::channel::mpsc; use io::{Error, ErrorKind}; let (tx, rx) = mpsc::unbounded::(); diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index 586be6f9a2..b4ac7d46d4 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -500,6 +500,41 @@ fn test_history() { assert_eq!(buffer.text(), "12cde6"); } +#[test] +fn test_avoid_grouping_next_transaction() { + let now = Instant::now(); + let mut buffer = Buffer::new(0, 0, History::new("123456".into())); + + buffer.start_transaction_at(now); + buffer.edit(vec![2..4], "cd"); + buffer.end_transaction_at(now); + assert_eq!(buffer.text(), "12cd56"); + + buffer.avoid_grouping_next_transaction(); + buffer.start_transaction_at(now); + buffer.edit(vec![4..5], "e"); + buffer.end_transaction_at(now).unwrap(); + assert_eq!(buffer.text(), "12cde6"); + + buffer.start_transaction_at(now); + buffer.edit(vec![0..1], "a"); + buffer.edit(vec![1..1], "b"); + buffer.end_transaction_at(now).unwrap(); + assert_eq!(buffer.text(), "ab2cde6"); + + buffer.undo(); + assert_eq!(buffer.text(), "12cd56"); + + buffer.undo(); + assert_eq!(buffer.text(), "123456"); + + buffer.redo(); + assert_eq!(buffer.text(), "12cd56"); + + buffer.redo(); + assert_eq!(buffer.text(), "ab2cde6"); +} + #[test] fn test_concurrent_edits() { let text = "abcdef"; diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index a762b1ca39..b619aba2ce 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -72,6 +72,7 @@ pub struct Transaction { ranges: Vec>, first_edit_at: Instant, last_edit_at: Instant, + suppress_grouping: bool, } impl Transaction { @@ -164,6 +165,7 @@ impl History { ranges: Vec::new(), first_edit_at: now, last_edit_at: now, + suppress_grouping: false, }); Some(id) } else { @@ -194,7 +196,9 @@ impl History { if let Some(mut transaction) = transactions.next_back() { while let Some(prev_transaction) = transactions.next_back() { - if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval + if !prev_transaction.suppress_grouping + && transaction.first_edit_at - prev_transaction.last_edit_at + <= self.group_interval && transaction.start == prev_transaction.end { transaction = prev_transaction; @@ -223,6 +227,12 @@ impl History { self.undo_stack.last().map(|t| t.id) } + fn avoid_grouping_next_transaction(&mut self) { + if let Some(transaction) = self.undo_stack.last_mut() { + transaction.suppress_grouping = true; + } + } + fn push_undo(&mut self, edit_id: clock::Local) { assert_ne!(self.transaction_depth, 0); let last_transaction = self.undo_stack.last_mut().unwrap(); @@ -1157,6 +1167,10 @@ impl Buffer { } } + pub fn avoid_grouping_next_transaction(&mut self) { + self.history.avoid_grouping_next_transaction() + } + pub fn base_text(&self) -> &Arc { &self.history.base_text }