Skip to content

editor: Fix LSP extension commands failing at end of file#52651

Merged
SomeoneToIgnore merged 3 commits intozed-industries:mainfrom
florian-trehaut:troubleshoot/switch-source-header-2026-03-29
Mar 30, 2026
Merged

editor: Fix LSP extension commands failing at end of file#52651
SomeoneToIgnore merged 3 commits intozed-industries:mainfrom
florian-trehaut:troubleshoot/switch-source-header-2026-03-29

Conversation

@florian-trehaut
Copy link
Copy Markdown
Contributor

@florian-trehaut florian-trehaut commented Mar 29, 2026

Context

Closes #51330

When the cursor is at the very end of a file, find_specific_language_server_in_selection in crates/editor/src/lsp_ext.rs silently skips the selection because the anchor's buffer_id is None. This causes editor: switch source header (clangd) and rust-analyzer extension commands (expand macro, open docs, open playground) to do nothing.

The fix falls back to the singleton buffer's ID when the anchor has no buffer_id.

How to Review

Single file change in crates/editor/src/lsp_ext.rs. The diff is small — pre-compute the singleton buffer ID, then use it as fallback in the filter_map closure. An integration test verifies the fix.

Self-Review Checklist

  • Reviewed own diff for quality, security, and reliability
  • No unsafe blocks
  • Tests pass (639 editor tests, 0 failures)
  • Manual testing: switch source header works at beginning, middle, and end of C++ file

Test Plan

  • New integration test: test_find_language_server_at_end_of_file — verifies find_specific_language_server_in_selection returns Some at both beginning and end of file
  • Confirmed the test fails without the fix (assertion on "should find language server at end of file")
  • Manual: open a C++ file with clangd, place cursor at very end, run switch source header — now correctly opens the header
  • Manual: verify it still works at beginning and middle of file (non-regression)
  • cargo test -p editor — 639 passed, 0 failed

Release Notes:

  • Fixed editor: switch source header and other LSP extension commands not working when the cursor is at the very end of a file.
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Mar 29, 2026
@zed-codeowner-coordinator zed-codeowner-coordinator Bot requested a review from a team March 29, 2026 08:11
@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 Mar 29, 2026
@zed-codeowner-coordinator zed-codeowner-coordinator Bot requested review from SomeoneToIgnore and as-cii and removed request for a team March 29, 2026 08:11
When the cursor is at the very end of a file, the selection anchor's
`buffer_id` can be `None`, causing `find_specific_language_server_in_selection`
to silently skip the selection. This affects `switch source header` (clangd)
and rust-analyzer commands (expand macro, open docs, open playground).

Fall back to the singleton buffer's ID when the anchor has no `buffer_id`.

Closes zed-industries#51330

Release Notes:

- Fixed `editor: switch source header` and other LSP extension commands not
  working when the cursor is at the very end of a file.
@florian-trehaut florian-trehaut force-pushed the troubleshoot/switch-source-header-2026-03-29 branch from b150dae to 71f3593 Compare March 29, 2026 08:42
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 for the fix, this is a very nice catch overall meaning there's a lot of places like this elsewhere.
The most important one most probably is the diagnostics-related code as there were reports of diagnostics not shown on the very edge of the file?

Either way, let's adjust the code for a proper multi buffer coordinate contract find_specific_language_server_in_selection exposes and merge this.

Comment thread crates/editor/src/lsp_ext.rs Outdated
Comment thread crates/editor/src/lsp_ext.rs Outdated
@florian-trehaut florian-trehaut marked this pull request as draft March 30, 2026 09:31
Use MultiBufferSnapshot::buffer_id_for_anchor to resolve buffer IDs,
which properly handles anchors with None buffer_id through
excerpt_containing. This replaces the custom resolve_anchor_to_buffer
helper with the existing multi-buffer API.

Merge all filtering logic into a single find_map to avoid borrow
checker issues with cx, using a scoped block to drop the multi-buffer
borrow before calling buffer.update.

Strengthen test assertions to verify the specific server ID, language,
buffer identity, and file presence.
@florian-trehaut florian-trehaut force-pushed the troubleshoot/switch-source-header-2026-03-29 branch from f4607eb to 92061af Compare March 30, 2026 10:06
@florian-trehaut florian-trehaut marked this pull request as ready for review March 30, 2026 10:06
@zed-codeowner-coordinator zed-codeowner-coordinator Bot requested review from a team and Veykril and removed request for a team March 30, 2026 10:06
@florian-trehaut
Copy link
Copy Markdown
Contributor Author

Thanks for taking the time to review this! I've addressed all the feedback:

  • Replaced resolve_anchor_to_buffer with MultiBufferSnapshot::buffer_id_for_anchor, which already handles buffer_id: None through excerpt_containing internally
  • Merged everything into a single find_map with a scoped block to avoid borrow checker issues with cx
  • Kept the tail fallback
  • Strengthened test assertions: server ID, language, buffer identity, file presence, all in a shared closure

About the diagnostics code you mentioned, I'd be happy to look into that as a follow-up if you can point me to the relevant area.

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, I have pushed another small fix on top to avoid extra snapshot-related creation costs.


I've rechecked the diagnostics-related idea of mine and that does not seem related to this particular issue: #22473

Yet, I think if you check for text_anchor.buffer_id field usages, some of them may come out wrong, e.g.

if Some(buffer_id) != cursor.text_anchor.buffer_id {
return None;
}
let buffer = self.buffer.read(cx).buffer(buffer_id)?;

or even

pub fn text_anchor_for_position<T: ToOffset>(
&self,
position: T,
cx: &App,
) -> Option<(Entity<Buffer>, language::Anchor)> {
let snapshot = self.read(cx);
let anchor = snapshot.anchor_before(position);
let buffer = self
.buffers
.get(&anchor.text_anchor.buffer_id?)?
.buffer
.clone();
Some((buffer, anchor.text_anchor))
}

are quite suspicious already.

@SomeoneToIgnore SomeoneToIgnore enabled auto-merge (squash) March 30, 2026 11:11
@SomeoneToIgnore SomeoneToIgnore merged commit 2b4c217 into zed-industries:main Mar 30, 2026
30 checks passed
piper-of-dawn pushed a commit to piper-of-dawn/zed that referenced this pull request Apr 25, 2026
…ries#52651)

## Context

Closes zed-industries#51330

When the cursor is at the very end of a file,
`find_specific_language_server_in_selection` in
`crates/editor/src/lsp_ext.rs` silently skips the selection because the
anchor's `buffer_id` is `None`. This causes `editor: switch source
header` (clangd) and rust-analyzer extension commands (`expand macro`,
`open docs`, `open playground`) to do nothing.

The fix falls back to the singleton buffer's ID when the anchor has no
`buffer_id`.

## How to Review

Single file change in `crates/editor/src/lsp_ext.rs`. The diff is small
— pre-compute the singleton buffer ID, then use it as fallback in the
`filter_map` closure. An integration test verifies the fix.

## Self-Review Checklist

- [x] Reviewed own diff for quality, security, and reliability
- [x] No unsafe blocks
- [x] Tests pass (639 editor tests, 0 failures)
- [x] Manual testing: switch source header works at beginning, middle,
and end of C++ file

## Test Plan

- [x] New integration test: `test_find_language_server_at_end_of_file` —
verifies `find_specific_language_server_in_selection` returns `Some` at
both beginning and end of file
- [x] Confirmed the test fails without the fix (assertion on "should
find language server at end of file")
- [x] Manual: open a C++ file with clangd, place cursor at very end, run
`switch source header` — now correctly opens the header
- [x] Manual: verify it still works at beginning and middle of file
(non-regression)
- [x] `cargo test -p editor` — 639 passed, 0 failed

Release Notes:

- Fixed `editor: switch source header` and other LSP extension commands
not working when the cursor is at the very end of a file.

---------

Co-authored-by: Florian Trehaut <florian.trehaut@hillcode.fr>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
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

4 participants