From f055053fc9f1dd7e3bbe604f3eb040a167d02741 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 27 Jan 2022 15:51:46 +0100 Subject: [PATCH 1/3] Avoid grouping transactions created by different editors Co-Authored-By: Nathan Sobo --- crates/editor/src/editor.rs | 1 + crates/editor/src/multi_buffer.rs | 6 ++++++ crates/language/src/buffer.rs | 4 ++++ crates/text/src/tests.rs | 35 +++++++++++++++++++++++++++++++ crates/text/src/text.rs | 16 +++++++++++++- 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 26d7f2f87506e2e43f708a3949ae4c763f621ea4..f16d982cc220f526a2e55ec992c48c2907ecaf7e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -3952,6 +3952,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 f3d906e27dd411fcf0938b923ac202c01b383735..4cedfa80d2703f3987bf92aac080db2d98733f48 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 eae15fe5af5c7dd524e8fa6ba6cb1ac84cf7fdf7..05128776b640527a9162175ec1f8ffa2ee3cbe0c 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/text/src/tests.rs b/crates/text/src/tests.rs index 586be6f9a2650d0b1e1d477c7ecbc675f12d9743..b4ac7d46d4f79fa68ccc5fc4213fdf2a453c4b88 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 a762b1ca397e4f93e06e0304c33940dfe0658cb8..b619aba2cebaa575e8478221539193311a00ae41 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 } From 41ec4645ab6cf9a13ef95c05980b860ce3a3ac01 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 27 Jan 2022 15:53:44 +0100 Subject: [PATCH 2/3] Don't panic when ending transaction that wasn't started by the same editor Co-Authored-By: Nathan Sobo --- crates/editor/src/editor.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f16d982cc220f526a2e55ec992c48c2907ecaf7e..a3c62295f75f994c947ae9c9d51287b84273d6c6 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"); + } } } From ff24766319edb0c9660ac675cb13d7e2740b6f24 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 27 Jan 2022 15:55:48 +0100 Subject: [PATCH 3/3] Fix warning Co-Authored-By: Nathan Sobo --- crates/rpc/src/conn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/rpc/src/conn.rs b/crates/rpc/src/conn.rs index a0db93287688d91899a482aa1e90508987eaee3c..70c59d013b43d8bbeb9bce93c6a10ba59ee9139b 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::();