diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index d6779d8a328b6b..0329763d03122b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -12520,7 +12520,7 @@ impl Editor { for trimmed_range in trimmed_selections { if is_first { is_first = false; - } else { + } else if !is_entire_line { text += "\n"; } let mut len = 0; @@ -12528,9 +12528,12 @@ impl Editor { text.push_str(chunk); len += chunk.len(); } - if add_trailing_newline { + if is_entire_line { + len -= 1; + } + if is_entire_line && add_trailing_newline { text.push('\n'); - len += 1; + len += 2; } clipboard_selections.push(ClipboardSelection { len, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 06fbd9d3381f70..5ea69095493f4e 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -26962,6 +26962,43 @@ 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\nline2\nline3\nˇ"); + + cx.update_editor(|e, window, cx| { + e.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0), + DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0), + DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0), + ]); + }); + }); + + 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_end_of_editor_context(cx: &mut TestAppContext) { init_test(cx, |_| {});