From 0ecefe031ee8a5bd43d6d9a3e94e110cd1febf64 Mon Sep 17 00:00:00 2001 From: Dino Date: Tue, 13 Jan 2026 11:57:06 +0000 Subject: [PATCH] editor: Fix crash when pasting after copy and trim in visual line mode (#46640) When using the `editor::actions::CopyAndTrim` action with a multi-line selection in vim's Visual Line mode, pasting would crash Zed. The bug occurred because trimming splits a selection into per-line ranges, creating multiple `editor::ClipboardSelection` entries. However, when `is_entire_line` was true (Visual Line mode), no newline separators were added between these entries in the clipboard text. The paste code then assumed separators existed and read past the end of the text. The fix ensures newline separators are always added between trimmed line ranges, regardless of whether the original selection was in line mode. Closes #46616 Release Notes: - Fixed a crash when pasting after using `editor: copy and trim` in vim's Visual Line mode --- crates/editor/src/editor.rs | 5 +++-- crates/editor/src/editor_tests.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 1e91a8718139d08a95edc0d192fd25a7c75adbbf..3b78bff39142bcf5e7f5011599d50925e632ff4a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -13272,13 +13272,14 @@ impl Editor { trimmed_selections.push(start..end); } + let is_multiline_trim = trimmed_selections.len() > 1; for trimmed_range in trimmed_selections { if is_first { is_first = false; - } else if !prev_selection_was_entire_line { + } else if is_multiline_trim || !prev_selection_was_entire_line { text += "\n"; } - prev_selection_was_entire_line = is_entire_line; + prev_selection_was_entire_line = is_entire_line && !is_multiline_trim; let mut len = 0; for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) { text.push_str(chunk); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 99572e2b5f77af7fa2f061051c0e5c3d6f0d539a..fe0169cabf0ebdc1246c23c0e2cff2b79feb9bf1 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -7612,6 +7612,25 @@ if is_entire_line { ); } +#[gpui::test] +async fn test_copy_trim_line_mode(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + + cx.set_state(indoc! {" + « a + bˇ» + "}); + cx.update_editor(|editor, _window, _cx| editor.selections.set_line_mode(true)); + cx.update_editor(|editor, window, cx| editor.copy_and_trim(&CopyAndTrim, window, cx)); + + assert_eq!( + cx.read_from_clipboard().and_then(|item| item.text()), + Some("a\nb\n".to_string()) + ); +} + #[gpui::test] async fn test_paste_multiline(cx: &mut TestAppContext) { init_test(cx, |_| {});