Detailed changes
@@ -14018,6 +14018,8 @@ impl Editor {
return;
}
+ self.finalize_last_transaction(cx);
+
let clipboard_text = Cow::Borrowed(text.as_str());
self.transact(window, cx, |this, window, cx| {
@@ -8839,6 +8839,36 @@ async fn test_paste_multiline(cx: &mut TestAppContext) {
)ห"});
}
+#[gpui::test]
+async fn test_paste_undo_does_not_include_preceding_edits(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ let mut cx = EditorTestContext::new(cx).await;
+
+ cx.update_editor(|e, _, cx| {
+ e.buffer().update(cx, |buffer, cx| {
+ buffer.set_group_interval(Duration::from_secs(10), cx)
+ })
+ });
+ // Type some text
+ cx.set_state("ห");
+ cx.update_editor(|e, window, cx| e.insert("hello", window, cx));
+ // cx.assert_editor_state("helloห");
+
+ // Paste some text immediately after typing
+ cx.write_to_clipboard(ClipboardItem::new_string(" world".into()));
+ cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
+ cx.assert_editor_state("hello worldห");
+
+ // Undo should only undo the paste, not the preceding typing
+ cx.update_editor(|e, window, cx| e.undo(&Undo, window, cx));
+ cx.assert_editor_state("helloห");
+
+ // Undo again should undo the typing
+ cx.update_editor(|e, window, cx| e.undo(&Undo, window, cx));
+ cx.assert_editor_state("ห");
+}
+
#[gpui::test]
async fn test_paste_content_from_other_app(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -3274,6 +3274,10 @@ impl Buffer {
pub fn preserve_preview(&self) -> bool {
!self.has_edits_since(&self.preview_version)
}
+
+ pub fn set_group_interval(&mut self, group_interval: Duration) {
+ self.text.set_group_interval(group_interval);
+ }
}
#[doc(hidden)]
@@ -3289,10 +3293,6 @@ impl Buffer {
self.edit(edits, autoindent_mode, cx);
}
- pub fn set_group_interval(&mut self, group_interval: Duration) {
- self.text.set_group_interval(group_interval);
- }
-
pub fn randomly_edit<T>(&mut self, rng: &mut T, old_range_count: usize, cx: &mut Context<Self>)
where
T: rand::Rng,
@@ -1234,8 +1234,15 @@ impl MultiBuffer {
}
}
- pub fn set_group_interval(&mut self, group_interval: Duration) {
+ pub fn set_group_interval(&mut self, group_interval: Duration, cx: &mut Context<Self>) {
self.history.set_group_interval(group_interval);
+ if self.singleton {
+ for BufferState { buffer, .. } in self.buffers.values() {
+ buffer.update(cx, |buffer, _| {
+ buffer.set_group_interval(group_interval);
+ });
+ }
+ }
}
pub fn with_title(mut self, title: String) -> Self {
@@ -3513,8 +3513,8 @@ fn test_history(cx: &mut App) {
buf
});
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadWrite));
- multibuffer.update(cx, |this, _| {
- this.set_group_interval(group_interval);
+ multibuffer.update(cx, |this, cx| {
+ this.set_group_interval(group_interval, cx);
});
multibuffer.update(cx, |multibuffer, cx| {
multibuffer.set_excerpts_for_path(
@@ -223,10 +223,11 @@ impl History {
redo_stack: Vec::new(),
transaction_depth: 0,
// Don't group transactions in tests unless we opt in, because it's a footgun.
- #[cfg(any(test, feature = "test-support"))]
- group_interval: Duration::ZERO,
- #[cfg(not(any(test, feature = "test-support")))]
- group_interval: Duration::from_millis(300),
+ group_interval: if cfg!(any(test, feature = "test-support")) {
+ Duration::ZERO
+ } else {
+ Duration::from_millis(300)
+ },
}
}
@@ -1825,6 +1826,10 @@ impl Buffer {
tx.try_send(()).ok();
}
}
+
+ pub fn set_group_interval(&mut self, group_interval: Duration) {
+ self.history.group_interval = group_interval;
+ }
}
#[cfg(any(test, feature = "test-support"))]
@@ -1929,10 +1934,6 @@ impl Buffer {
assert!(!self.text().contains("\r\n"));
}
- pub fn set_group_interval(&mut self, group_interval: Duration) {
- self.history.group_interval = group_interval;
- }
-
pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
let end = self.clip_offset(rng.random_range(start_offset..=self.len()), Bias::Right);
let start = self.clip_offset(rng.random_range(start_offset..=end), Bias::Right);