Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lsp): code lenses #5063

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft

Conversation

matoous
Copy link
Contributor

@matoous matoous commented Dec 8, 2022

This PR provides initial (limited) implementation of LSP code lens1. The purpose is to provide ground for future improvements and experimentation.

Code Lens

From the VS Code features docs:

The essence of the feature is "actionable contextual information interspersed" in your source code. That's quite a mouthful. Let me break it down for you. CodeLens are links in your code:
Actionable - You can click on the link and something happens.
Contextual - The links are close to the code they are representing.
Interspersed - The links located throughout your source.

Implementation

This PR strafes a little bit from the standard approach to code lens to limit the scope of the initial PR. Instead of showing the code lens close the location that they apply to (via for example virtual text) this PR provides only a code lens picker that provides overview of all code lenses for specific file. The code lenses can be scrolled through, showing preview of the part of the file that they apply to, and executed.

Support

The support for code lens seems limited among certain LSPs but there are already nice features that can be achieved via code lenses (some of them listed below). The biggest limitation is that a lot of language servers rely on client-side command execution which is usually solved via plugins.

  • golang
    • generate, vendor, update dependency, and more.
    • test execution isn't supported2
  • rust-analyzer
    • run for tests and main - requires client side execuity
    • references/implementations (show number of references/implementations and can be opened to view them, disabled by default) - requires client side execution
  • deno
    • run test support - requires client side execution

(didn't check other languages so far).

Future work

As mentioned above this implementation is limited and doesn't provide Code Lens as they should be provided - contextually - close to the code that they apply for. Here's non-exhaustive list of improvements I would like to implement in follow-up PRs or in follow-up commits here (not yet decided on the full scope):

  • display code lense in the gutter (e.g. using in the diagnostic gutter)
  • request lens automatically and update them on idle timeout/document save
  • highlight the range that the lens applies to
  • configuration option to disable code-lense
  • show the lens title in a virtual text (e.g. at the end of the line with the range that they apply to) once Rework text rendering and integrate softwrap rendering #5008 lands
  • add command to display lens(es) under cursor (space + l?) menu (e.g. same look as code completion)
  • implement codeLens/resolve
  • implement workspace/codeLens/refresh server request

Showcase

Here's showcase of what's missing:

Screen.Recording.2022-12-08.at.11.43.53.mov

You can see that the information about implementation/references needs to be resolved via the codeLens/resolve and that rust-analyzer doesn't support executing commands (on the server side) so the commands need to be executed client side.


Related/fixes: #3005
Related: #3272

Footnotes

  1. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeLens

  2. https://github.com/golang/go/issues/36787

@pascalkuthe pascalkuthe added the A-language-server Area: Language server client label Dec 8, 2022
@sigmaSd
Copy link
Contributor

sigmaSd commented Dec 8, 2022

rust-analyzer doesn't support executing commands (on the server side) so the commands need to be executed client side.

This is not specific to rust-analyzer, I think that other lsps work the same way (especially for test codelens), for example I know its the case with deno lsp.

I think this would require plugins to handle, because executing the commands is lsp dependent

@matoous
Copy link
Contributor Author

matoous commented Dec 8, 2022

@sigmaSd yes, indeed, you are right. Rust for example returns rust-analyzer.showReferences which is custom extension command which would indeed require plugins. I will push a few more changes but otherwise I guess this will need to be put on hold until the plugin system is available. Other option would be for the commands to be for now mapped to the shell via languages.toml configuration and the output being display the same way we do for :run-shell-command.

@matoous matoous changed the title feat(lsp): initital implementation of code lens feat(lsp): code lenses Dec 8, 2022
@pascalkuthe
Copy link
Member

pascalkuthe commented Dec 8, 2022

:sh currently does not return anything if the command returns an error (which is the interesting case for tests I would assume) aslo any tests that might want input will freeze the editor. I think for running tests to be a good experience we would need an integrated terminal #4649. Also going the sh route requires developing, maintaining and installing a separate CLI tool for each LSP command (these binaries don't exist yet) which I don't see people developing (and would only work for a subset of commands I guess).

How many servers actually support server side execution? If rust-analyzer is the odd-one out with client-only commands then this might be worth merging but if almost all LSPs only allow client-side command execution then I think this should probably wait for plugins.

@ayoub-benali
Copy link
Contributor

rust-analyzer doesn't support executing commands (on the server side) so the commands need to be executed client side.

This is not specific to rust-analyzer, I think that other lsps work the same way (especially for test codelens), for example I know its the case with deno lsp.

I think this would require plugins to handle, because executing the commands is lsp dependent

I can confirm that at least Metals also expects the client to run some code lens commands and they are implemented in the plugin for sublime for example.

@Esnos33
Copy link

Esnos33 commented Apr 26, 2023

Hi, I'm new to git and I have question. I already have helix 23.03 and in release notes there is information about Initial support for snippets, but #3005 bug is still there. This is how it is supposed to be? Automatic type annotation is one of best things in haskell.

@matoous
Copy link
Contributor Author

matoous commented May 24, 2023

Closing this until Helix has support for plugins that are prerequisit for this being useful.

@matoous matoous closed this May 24, 2023
@maralorn
Copy link

I have a question about this: It is my impression that there are code lenses which don’t need a plugin to work. I think haskell-language-server has some of those. Is that wrong? Or could we maybe implement this, but only show code lenses in the case where they don’t require a plugin?
Actually, haskell-language-server simply offers code actions for when you click on the code lens. And those code actions can already be used right now. I am primarily interested in the code lenses because they display useful information, even if you don’t want to activate them right now.

@alexaandru
Copy link

Similar to the above comment, in gopls there are code actions that are available after running code lenses and there already is support for code actions so we wouldn't need any plugins to use them.

For example, when in go.mod file, there is a code lense Check for upgrades which when run it will populate diagnostics with info about which packages can be upgraded. Then for each of those lines, there is a code action available to upgrade it. So code lenses alone would be a very valuable addition.

@matoous
Copy link
Contributor Author

matoous commented Nov 23, 2023

👋 let me take a look if I could revive this. Indeed, the support might vary language to language but for some languages this might be worthwhile even in limited capacity.

@maralorn
Copy link

Also: Even if Code lenses can’t be triggered it might still be useful to show them, right? And that part should always work without plugin support, right?

@maralorn
Copy link

I am test driving this and it works just fine with haskell-language-server. Of course it would be nice if the code lenses would auto-update, but this is good enough for me.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-language-server Area: Language server client A-plugin Area: Plugin system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing Code actions and code lenses (Haskell)
7 participants