@@ -12585,6 +12585,7 @@ impl Editor {
{
let max_point = buffer.max_point();
let mut is_first = true;
+ let mut prev_selection_was_entire_line = false;
for selection in &mut selections {
let is_entire_line =
(selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
@@ -12599,9 +12600,10 @@ impl Editor {
}
if is_first {
is_first = false;
- } else {
+ } else if !prev_selection_was_entire_line {
text += "\n";
}
+ prev_selection_was_entire_line = is_entire_line;
let mut len = 0;
for chunk in buffer.text_for_range(selection.start..selection.end) {
text.push_str(chunk);
@@ -12684,6 +12686,7 @@ impl Editor {
{
let max_point = buffer.max_point();
let mut is_first = true;
+ let mut prev_selection_was_entire_line = false;
for selection in &selections {
let mut start = selection.start;
let mut end = selection.end;
@@ -12742,9 +12745,10 @@ impl Editor {
for trimmed_range in trimmed_selections {
if is_first {
is_first = false;
- } else {
+ } else if !prev_selection_was_entire_line {
text += "\n";
}
+ prev_selection_was_entire_line = is_entire_line;
let mut len = 0;
for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
text.push_str(chunk);
@@ -12818,7 +12822,11 @@ impl Editor {
let end_offset = start_offset + clipboard_selection.len;
to_insert = &clipboard_text[start_offset..end_offset];
entire_line = clipboard_selection.is_entire_line;
- start_offset = end_offset + 1;
+ start_offset = if entire_line {
+ end_offset
+ } else {
+ end_offset + 1
+ };
original_indent_column = Some(clipboard_selection.first_line_indent);
} else {
to_insert = &*clipboard_text;
@@ -27375,6 +27375,60 @@ async fn test_copy_line_without_trailing_newline(cx: &mut TestAppContext) {
cx.assert_editor_state("line1\nline2\nˇ");
}
+#[gpui::test]
+async fn test_multi_selection_copy_with_newline_between_copied_lines(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ let mut cx = EditorTestContext::new(cx).await;
+
+ cx.set_state("ˇline1\nˇline2\nˇline3\n");
+
+ cx.update_editor(|e, window, cx| e.copy(&Copy, window, cx));
+
+ let clipboard_text = cx
+ .read_from_clipboard()
+ .and_then(|item| item.text().as_deref().map(str::to_string));
+
+ assert_eq!(
+ clipboard_text,
+ Some("line1\nline2\nline3\n".to_string()),
+ "Copying multiple lines should include a single newline between lines"
+ );
+
+ cx.set_state("lineA\nˇ");
+
+ cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
+
+ cx.assert_editor_state("lineA\nline1\nline2\nline3\nˇ");
+}
+
+#[gpui::test]
+async fn test_multi_selection_cut_with_newline_between_copied_lines(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ let mut cx = EditorTestContext::new(cx).await;
+
+ cx.set_state("ˇline1\nˇline2\nˇline3\n");
+
+ cx.update_editor(|e, window, cx| e.cut(&Cut, window, cx));
+
+ let clipboard_text = cx
+ .read_from_clipboard()
+ .and_then(|item| item.text().as_deref().map(str::to_string));
+
+ assert_eq!(
+ clipboard_text,
+ Some("line1\nline2\nline3\n".to_string()),
+ "Copying multiple lines should include a single newline between lines"
+ );
+
+ cx.set_state("lineA\nˇ");
+
+ cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
+
+ cx.assert_editor_state("lineA\nline1\nline2\nline3\nˇ");
+}
+
#[gpui::test]
async fn test_end_of_editor_context(cx: &mut TestAppContext) {
init_test(cx, |_| {});