Skip to content

editor: Use a single newline between each copied line from a multi-cursor selection#41204

Merged
ConradIrwin merged 3 commits intozed-industries:mainfrom
seanstrom:seanstrom/fix-multi-selection-line-copy-newline-spacing
Nov 13, 2025
Merged

editor: Use a single newline between each copied line from a multi-cursor selection#41204
ConradIrwin merged 3 commits intozed-industries:mainfrom
seanstrom:seanstrom/fix-multi-selection-line-copy-newline-spacing

Conversation

@seanstrom
Copy link
Contributor

Closes #40923

Release Notes:

  • Fixed the amount of newlines between copied lines from a multi-cursor selection of multiple full-line copies.

Zed-Multi-Selection-Line-Copy.mp4

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Oct 26, 2025
@seanstrom seanstrom force-pushed the seanstrom/fix-multi-selection-line-copy-newline-spacing branch from a83b36e to 0bdb5f2 Compare October 26, 2025 04:28
@seanstrom seanstrom changed the title fix(editor): use a single newline between each copied line from a multi-cursor selection fix(editor): Use a single newline between each copied line from a multi-cursor selection Oct 26, 2025
@seanstrom seanstrom changed the title fix(editor): Use a single newline between each copied line from a multi-cursor selection editor: Use a single newline between each copied line from a multi-cursor selection Oct 26, 2025
@SomeoneToIgnore SomeoneToIgnore self-assigned this Oct 27, 2025
@seanstrom seanstrom force-pushed the seanstrom/fix-multi-selection-line-copy-newline-spacing branch from 0bdb5f2 to 7728370 Compare November 3, 2025 16:52
@seanstrom
Copy link
Contributor Author

One problem that I'm noticing with this change:

  • Seems like the editor crashes when attempting to paste into multiple cursors after copying multiple entire lines with multi-cursors.
    • Not sure what the root cause is, but perhaps the do_paste handler is expecting some of the newlines that were made conditional with this change.
    • I'll attempt some more debugging and exploring to see what's the expected format of clipboard content.

@seanstrom
Copy link
Contributor Author

I've posted a fix to the crash, but the code itself is not worthy to be merged 😄

But here's my notes on what I've found when digging through the code for do_copy and do_paste:

  • Prior to my changes in this code, we would always add a newline (after the first selection) for each selection. Which meant that copying two entire lines would produce an extra newline between the lines.
    • I thought this was a bug, since this extra newline is not counted in the selection length, but it seems to be an intentional padding between selections, since the do_paste handler seems to sometimes account for this extra newline when pasting.
    • Here's the code snipped for the extra newline:

      zed/crates/editor/src/editor.rs

      Lines 12507 to 12512 in 4724aa5

      for trimmed_range in trimmed_selections {
      if is_first {
      is_first = false;
      } else {
      text += "\n";
      }
  • With my initial changes, I was conditionally adding that extra newline, since the current logic for copying entire lines will copy the entire line + plus the very beginning of the next line (effectively copying the newline).
    • However this would lead to a crash, because that intentional piece of newline padding would not be present during the do_paste operation, which would cause an out-of-bounds crash because the do_paste handler is expecting the extra newline.
    • Here's the snippet that leads to an out-of-bounds crash:

      zed/crates/editor/src/editor.rs

      Lines 12582 to 12587 in 4724aa5

      if let Some(clipboard_selection) = clipboard_selections.get(ix) {
      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;
      original_indent_column = Some(clipboard_selection.first_line_indent);
      • Notice how we're doing:
          let end_offset = start_offset + clipboard_selection.len;
          // ...
          start_offset = end_offset + 1;
  • I've tried modifying the do_paste handler, instead of changing do_copy, but I was running into some issues with properly extracting the clipboard selections without the extra newline and pasting their contents into the correct cursor positions.
    • The solution would essentially allow for the extra newlines, and when the clipboard selections count did not match the current cursor count, it would attempt to scan over the clipboard text and create new editor edits for each clipboard selection (effectively removing the extra newline).

That all being said, I'm wondering what the best approach would be to resolve this issue.

  • Do we keep this extra newline padding in the clipboard contents and allow the paste handler to strip it out?
  • Or do we adapt the paste handler to not assume there's an extra newline?

Copy link
Contributor

@SomeoneToIgnore SomeoneToIgnore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's quite an investigation for such small change, thank you for checking on all this!

Logically, it seems that we should fix the receiving end too: we should copy into the buffer the "right" text already, as the user might want to paste elsewhere, and unintuitive extra newlines would be there if not trimmed.

As a bonus, something similar happens on the Vim emulation side?

if let Some(clipboard_selections) = &clipboard_selections {
if let Some(clipboard_selection) = clipboard_selections.get(ix) {
let end_offset = start_offset + clipboard_selection.len;
let text = text[start_offset..end_offset].to_string();
start_offset = end_offset + 1;
(text, Some(clipboard_selection.first_line_indent))
} else {
("".to_string(), first_selection_indent_column)
}
} else {
(text.to_string(), first_selection_indent_column)
};

I would start with test(s): as you have a way to reproduce this and it's a panic.
Not sure I can help more, as there's no specific about the panic per se — removing +1 seems logical.

@seanstrom seanstrom force-pushed the seanstrom/fix-multi-selection-line-copy-newline-spacing branch from 1540cc3 to 492b1be Compare November 7, 2025 17:37
@seanstrom
Copy link
Contributor Author

@SomeoneToIgnore thanks for the feedback!

I've pushed up another change that handles the editor commands for Cut, Copy, and Paste. I've also revised the tests based on your suggestions, and added a new test for the Cut command.

I've started looking into the Vim commands too, since it seems they also add an extra newline between multi-cursor selections of entire lines (using visual mode with line selection).

Should I continue to make more changes in this PR for the Vim commands?
And is there anywhere else I should check that could be affected by these editor changes?

@SomeoneToIgnore
Copy link
Contributor

Thank you for the fix, this looks good as the first glance, but I hope for @ConradIrwin to check the Vim part first to see what should we do about it.

@ConradIrwin
Copy link
Member

Thanks for the offer! If you'd like to make the same changes to vim mode, happy to accept a second PR, but no need to block on that. I also don't think it's super urgent as I haven't (yet) had any complaints about this – vim users are a little less likely to use multi-cursor actions like this)

@ConradIrwin ConradIrwin merged commit 1936f16 into zed-industries:main Nov 13, 2025
24 checks passed
@seanstrom seanstrom deleted the seanstrom/fix-multi-selection-line-copy-newline-spacing branch November 13, 2025 18:18
11happy pushed a commit to 11happy/zed that referenced this pull request Dec 1, 2025
…rsor selection (zed-industries#41204)

Closes zed-industries#40923

Release Notes:

- Fixed the amount of newlines between copied lines from a multi-cursor
selection of multiple full-line copies.

---


https://github.com/user-attachments/assets/ab7474d6-0e49-4c29-9700-7692cd019cef
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lines copied with multi-cusor pastes with extra newlines

3 participants