helix
helix copied to clipboard
feat(lsp): code lenses
This PR provides initial (limited) implementation of LSP code lens^1. 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 supported^2
-
-
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):
- [x] 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
- [x] 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 https://github.com/helix-editor/helix/pull/5008 lands
- [x] 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:
https://user-images.githubusercontent.com/15747583/206426945-614f9fdc-7244-41bb-bca8-7a865e568601.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: https://github.com/helix-editor/helix/issues/3005 Related: https://github.com/helix-editor/helix/issues/3272
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
@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
.
: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.
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.
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.
Closing this until Helix has support for plugins that are prerequisit for this being useful.
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.
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.
👋 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.
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?
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!