Skip to content

editor: Fix jumbled auto-imports when completing with multiple cursors#50320

Merged
SomeoneToIgnore merged 1 commit intozed-industries:mainfrom
theonly1me:main
Mar 16, 2026
Merged

editor: Fix jumbled auto-imports when completing with multiple cursors#50320
SomeoneToIgnore merged 1 commit intozed-industries:mainfrom
theonly1me:main

Conversation

@theonly1me
Copy link
Copy Markdown
Contributor

When accepting an autocomplete suggestion with multiple active cursors using CMD+D, Zed applies the primary completion edit to all cursors. However, the overlap check for LSP additionalTextEdits only verifies the replace range of the newest cursor.

If user has a cursor inside an existing import statement at the top of the file and another cursor further down, Zed fails to detect the overlap at the top of the file. When the user auto-completes the import statement ends up jumbled.

This fix updates the completion logic to calculate the commit ranges for all active cursors and passes them to the LSP store. The overlap check now iterates over all commit ranges to ensure auto-imports are correctly discarded if they intersect with any of the user's multi-cursor edits.

Closes #50314

Before

Screen.Recording.2026-02-27.at.21.14.12.mov

After

Screen.Recording.2026-02-27.at.21.16.10.mov

Before you mark this PR as ready for review, make sure that you have:

  • Added a solid test coverage and/or screenshots from doing manual testing
  • Done a self-review taking into account security and performance aspects
  • Aligned any UI changes with the UI checklist

Release Notes:

  • Fixed an issue where accepting an autocomplete suggestion with multiple cursors could result in duplicated or jumbled text in import statements.

@cla-bot
Copy link
Copy Markdown

cla-bot bot commented Feb 27, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @theonly1me on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@zed-community-bot zed-community-bot bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Feb 27, 2026
@theonly1me
Copy link
Copy Markdown
Contributor Author

@cla-bot check

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Feb 27, 2026
@cla-bot
Copy link
Copy Markdown

cla-bot bot commented Feb 27, 2026

The cla-bot has been summoned, and re-checked this pull request!

@theonly1me
Copy link
Copy Markdown
Contributor Author

Just bumping this, this bug is pretty annoying when performing refactors, would be great if someone can take a look at the fix!

@SomeoneToIgnore
Copy link
Copy Markdown
Contributor

https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#sending-changes mentions that the tests have to be included, this alone (missing in this PR) is worth a thousand bumps.

@theonly1me
Copy link
Copy Markdown
Contributor Author

theonly1me commented Mar 3, 2026

main/CONTRIBUTING.md#sending-changes mentions that the tests have to be included, this alone (missing in this PR) is worth a thousand bumps.

@SomeoneToIgnore Thanks for responding, I've added a unit test now - 0c0c741 (updated test, so the scenario is more realistic).

To clarify, I did review CONTRIBUTING.md as well as the PR template before opening this PR. The guideline says:

"Include tests. For UI changes, consider updating visual regression tests."
"If it changes the UI, attach screenshots or screen recordings."

And the PR template says:

"Added a solid test coverage and/or screenshots from doing manual testing"

Since this is an editor change, I included before / after video recordings in the description, which satisfies that criteria. I understand that a unit test may be more desirable, but the original PR wasn't missing what the guidelines ask for.

@SomeoneToIgnore
Copy link
Copy Markdown
Contributor

Superb, thank you so much for the quick update.

Videos are great overall and very useful, thank you for adding these, yet their purpose is to assess visual changes mostly (e.g. mouse interactions with the UI, tree-sitter highlight updates, UI changes, etc.).

The logic is great to show this way, but it's definitely not enough to call it "tested" after a single video, as the code is changed quite rapidly with dozens of PRs each day.

@theonly1me
Copy link
Copy Markdown
Contributor Author

Superb, thank you so much for the quick update.

Videos are great overall and very useful, thank you for adding these, yet their purpose is to assess visual changes mostly (e.g. mouse interactions with the UI, tree-sitter highlight updates, UI changes, etc.).

The logic is great to show this way, but it's definitely not enough to call it "tested" after a single video, as the code is changed quite rapidly with dozens of PRs each day.

@SomeoneToIgnore that's fair, I'll make sure to add unit tests for any future PRs.

@theonly1me
Copy link
Copy Markdown
Contributor Author

theonly1me commented Mar 3, 2026

The edit_prediction_context test that's failing seems to be flake as it is a different crate, unrelated to my changes and all 7 related to edit_prediction_context succeed when I run locally.

    FAIL [   0.928s] (1260/3940) edit_prediction_context edit_prediction_context_tests::test_assemble_excerpts
  stdout ───

    running 1 test
    test edit_prediction_context_tests::test_assemble_excerpts ... FAILED

    failures:

    failures:
        edit_prediction_context_tests::test_assemble_excerpts

    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.92s
    
  stderr ───

    thread 'edit_prediction_context_tests::test_assemble_excerpts' (53925) panicked at crates/edit_prediction_context/src/edit_prediction_context_tests.rs:313:13:
    assertion `left == right` failed
      left: "…\n    last_name: String,\n…\n        format!(\"{} {}\", self.first_name, self.last_name)\n    }\n…\n"
     right: "struct User {\n    first_name: String,\n    last_name: String,\n…\n}\n\nimpl User {\n…\n    pub fn full_name(&self) -> String {\n        format!(\"{} {}\", self.first_name, self.last_name)\n    }\n}\n"
    stack backtrace:
       0: __rustc::rust_begin_unwind
                 at /rustc/01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf/library/std/src/panicking.rs:689:5
       1: core::panicking::panic_fmt
                 at /rustc/01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf/library/core/src/panicking.rs:80:14
       2: core::panicking::assert_failed_inner
       3: core::panicking::assert_failed
                 at /Volumes/cache/Users/runner/.rustup/toolchains/1.93-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/panicking.rs:394:5
       4: edit_prediction_context::edit_prediction_context_tests::test_assemble_excerpts::__test_assemble_excerpts::{{closure}}
                 at ./src/edit_prediction_context_tests.rs:313:13
       5: <gpui::app::App as gpui::AppContext>::read_entity
                 at /Users/runner/work/zed/zed/crates/gpui/src/app.rs:2376:9
       6: <gpui::app::test_context::TestAppContext as gpui::AppContext>::read_entity
                 at /Users/runner/work/zed/zed/crates/gpui/src/app/test_context.rs:75:13
       7: gpui::app::entity_map::Entity<T>::read_with
                 at /Users/runner/work/zed/zed/crates/gpui/src/app/entity_map.rs:470:12
       8: edit_prediction_context::edit_prediction_context_tests::test_assemble_excerpts::__test_assemble_excerpts
                 at ./src/edit_prediction_context_tests.rs:292:16
       9: edit_prediction_context::edit_prediction_context_tests::test_assemble_excerpts::{{closure}}
                 at ./src/edit_prediction_context_tests.rs:162:1
      10: gpui::test::run_test::{{closure}}
                 at /Users/runner/work/zed/zed/crates/gpui/src/test.rs:57:17
      11: std::panicking::catch_unwind::do_call
                 at /Volumes/cache/Users/runner/.rustup/toolchains/1.93-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:581:40
      12: ___rust_try
      13: std::panicking::catch_unwind
                 at /Volumes/cache/Users/runner/.rustup/toolchains/1.93-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:544:19
      14: std::panic::catch_unwind
                 at /Volumes/cache/Users/runner/.rustup/toolchains/1.93-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panic.rs:359:14
      15: gpui::test::run_test
                 at /Users/runner/work/zed/zed/crates/gpui/src/test.rs:54:26
      16: edit_prediction_context::edit_prediction_context_tests::test_assemble_excerpts
                 at ./src/edit_prediction_context_tests.rs:162:1
      17: edit_prediction_context::edit_prediction_context_tests::test_assemble_excerpts::{{closure}}
                 at ./src/edit_prediction_context_tests.rs:162:14
      18: core::ops::function::FnOnce::call_once
                 at /Volumes/cache/Users/runner/.rustup/toolchains/1.93-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
      19: core::ops::function::FnOnce::call_once
                 at /rustc/01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf/library/core/src/ops/function.rs:250:5
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@SomeoneToIgnore
Copy link
Copy Markdown
Contributor

This is a test flak, the test had been added recently and needs some taking care of, the author seems to be aware of this.

Copy link
Copy Markdown
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.

Great, thank you for this.

Let's not wreck agent evals though, so one more change is needed.

When accepting an autocomplete suggestion with multiple active cursors using `CMD+D`, Zed applies the primary completion edit to all cursors. However, the overlap check for LSP `additionalTextEdits` only verifies the replace range of the newest cursor.

If user has a cursor inside an existing import statement at the top of the file and another cursor further down, Zed fails to detect the overlap at the top of the file. When the user auto-completes the import statement ends up jumbled.

This fix updates the completion logic to calculate the commit ranges for all active cursors and passes them to the LSP store. The overlap check now iterates over all commit ranges to ensure auto-imports are correctly discarded if they intersect with any of the user's multi-cursor edits.

Release Notes:

- Fixed an issue where accepting an autocomplete suggestion with multiple cursors could result in duplicated or jumbled text in import statements.
Copy link
Copy Markdown
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.

Thank you!

@SomeoneToIgnore SomeoneToIgnore enabled auto-merge (squash) March 16, 2026 09:43
@SomeoneToIgnore SomeoneToIgnore merged commit 949944a into zed-industries:main Mar 16, 2026
29 checks passed
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 first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LSP additionalTextEdits fail to detect overlaps with secondary cursors during completions

2 participants