Skip to content

lsp: Resolve code lenses before surfacing them as code actions - #54175

Closed
aviatesk wants to merge 1 commit into
zed-industries:mainfrom
aviatesk:code-lens-resolve-ordering
Closed

lsp: Resolve code lenses before surfacing them as code actions#54175
aviatesk wants to merge 1 commit into
zed-industries:mainfrom
aviatesk:code-lens-resolve-ordering

Conversation

@aviatesk

Copy link
Copy Markdown
Collaborator

Code lens items are currently exposed through the code action menu. When a language server returns lenses lazily (rust-analyzer's N implementations etc.), they arrive with no command field until codeLens/resolve fills it in.
This caused two user-visible issues in the menu:

  1. The item's label displayed as "Unknown command" instead of the real title.
  2. Clicking the item dispatched to workspace/executeCommand instead of the intended client-side handler (references panel, runnable scheduler). try_handle_client_command runs before apply_code_action, so it saw command = None, returned false, and the action fell through to the generic apply path — by which point resolving the action was too late to redirect.

Resolve lazy lenses inline in Entity<Project>::code_actions so that by the time the menu renders (and by the time the user clicks), the command field is populated. refresh_code_actions is already 250ms debounced, and already-resolved actions short-circuit the new Project::resolve_code_action / LspStore::resolve_code_action, so the extra request only fires once the user has parked their cursor.

Notes on scope:
In this PR, codeLens/resolve fires whenever refresh_code_actions runs i.e. on every cursor row change (250 ms debounced), regardless of whether the user actually opens the code action menu. So that can produce unnecessary resolve requests.

The ideal would be to resolve lazily when the menu is opened, but this PR keeps the scope narrow to the correctness fix (lazy lenses showing "Unknown command" in the menu, and client-side command dispatch missing) so it's easy to review in isolation.

Separately: now that the inline code lens UI landed in #54100, it may be worth considering whether surfacing code lenses through the code action menu is still justified. Removing that feature would eliminate the eager-resolve overhead entirely, and the inline UI already covers the functionality. Happy to follow up on either of these in separate changes.

Self-Review Checklist:

  • I've reviewed my own diff for quality, security, and reliability
  • Unsafe blocks (if any) have justifying comments
  • The content is consistent with the UI/UX checklist
  • Tests cover the new/changed behavior
  • Performance impact has been considered and is acceptable

Release Notes:

  • Fixed code lens entries in the code action menu showing as "Unknown command" and failing to dispatch when clicked

Code lens items are currently exposed through the code action menu.
When a language server returns lenses lazily (rust-analyzer's
`N implementations` etc.), they arrive with no `command` field until
`codeLens/resolve` fills it in.
This caused two user-visible issues in the menu:
1. The item's label displayed as "Unknown command" instead of the
   real title.
2. Clicking the item dispatched to `workspace/executeCommand`
   instead of the intended client-side handler (references panel,
   runnable scheduler). `try_handle_client_command` runs before
   `apply_code_action`, so it saw `command = None`, returned false,
   and the action fell through to the generic apply path — by which
   point resolving the action was too late to redirect.

Resolve lazy lenses inline in `Entity<Project>::code_actions` so
that by the time the menu renders (and by the time the user clicks),
the `command` field is populated. `refresh_code_actions` is already
250ms debounced, and already-resolved actions short-circuit the new
`Project::resolve_code_action` / `LspStore::resolve_code_action`, so
the extra request only fires once the user has parked their cursor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Apr 17, 2026
@zed-codeowner-coordinator
zed-codeowner-coordinator Bot requested review from a team, Veykril and cameron1024 and removed request for a team April 17, 2026 12:07
@SomeoneToIgnore

SomeoneToIgnore commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Thank you, we try to do improve lens resolution in #54100 so most probably if we want to do it, we should do it there.

The new approach attempts to resolve the lens in the viewport eagerly, which presumably covers all action-related, selection-based cases this PR solves too?
The case when lens is invisible should be take care with the same resolve_visible_code_lenses in that branch, as long as lens are in the lsp store, which should happen on action request.

@aviatesk

Copy link
Copy Markdown
Collaborator Author

With #54100 landing the inline code lens UI, do we still need code lens items in the code action menu? If not, this PR isn't needed.

If we keep that surface, I think two things matter:

  • resolve_visible_code_lenses bails out when self.code_lens.is_none(), and code_lens defaults to "off". So for the default user the menu still shows "Unknown command" and the client-command dispatch still misfires. Should be a small fix, just flagging so it doesn't get missed.

  • The caller passes excerpt_range.context to resolve_visible_code_lenses, which is the whole excerpt (= the whole file for a single-buffer editor), not the viewport actually. With the menu as a consumer we can't narrow that since any cursor position needs to work. For files with many lens sites (rust-analyzer's N implementations, Run, Debug), that could be a lot of codeLens/resolve traffic upfront.

I'd rather drop the menu surface entirely in #54100. Keeping it means fixing both.

@SomeoneToIgnore

Copy link
Copy Markdown
Contributor

Thank you for flagging, we need to fix both either way I think.
Dropping the lens' actions from the menu seems ok, as no one before cared too much about the feature it seems, given it was not working.

@aviatesk
aviatesk deleted the code-lens-resolve-ordering branch April 20, 2026 09:14
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.

3 participants