-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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 Type Hints #5934
Feat: LSP Type Hints #5934
Conversation
1ee5692
to
e977c35
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to finally see the virtual text API put to use 🎉
Sadly I think you missunderstood the API somewhat and therefore had to do a bunch of unnecesassary changes. I designed the virtual text API very carefully (including with this usecase in mind) and the way you changed the API here makes it less efficent and less elegant.
The API is a bit abstract without an example and you are not the first person to be initially confused. I think the core of your misunderstanding is that you created a single layer (call to add_inline_annotations
) per inlay a hint
That are a lot of layers (and not efficent since every layers must be checked at every singel char when transvcersing the document) and I therefore you probably thaught that you needed to store these somewhere.
Instead the idea is that one layer corresponds to a single TYPE of virtual text.
Therefore it is possible to construct these layers on the fly in the text_annotations
functions and only store the contents of the layers. In your case there should only be the need for 4 layers. Constructing a Vec
of 4 elements on the fly is basically free and is how the API was supposed to be used.
I left a bunch of comments with more details.
Once you apply my suggestion the diff should reduce significantly and this should turn into a smaller PR.
e977c35
to
3f1b568
Compare
Yes, this is really confusing at first because there is pretty much zero doc in Helix about virtual text and annotations (or, if there is, it's absolutely not where I expect it to be, on the types and methods) so I was really confused, thanks for clarifying !
Yes, that approach is much better, I used it instead. I can't separate padding from the hints though, else it breaks in all kinds of ways: everything is squished together and unreadable.
Not really 😅 I added quite some docs for inlay hints in documents that re-inflated the count after reducing it, but still the MR is better than it was before thanks to you EDIT: I left a few comments open voluntarily, close them or answer as you want, for the others I either fixed the problem or changed the code too much to leave them as-is |
Huh that is odd, it shouldn't let me check.
Well you added quite a bit of docs and its still almost 25% smaller so I would call that a win :D |
I just implemented this myself and it worked fine for me.
|
let apply_inlay_hint_changes = |annotations: &mut Rc<[InlineAnnotation]>| { | ||
if let Some(data) = Rc::get_mut(annotations) { | ||
for inline in data.iter_mut() { | ||
inline.char_idx = changes.map_pos(inline.char_idx, Assoc::After); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neither Assoc::After
or Assoc::Before
works well here that is because both of these were designed for ranges where the start is mapped with Assoc::Before
and Assoc::After
. However for inlay hints we want something different. Inlay hints are bound to a single point so when that point is removed when also want to delete the inlay hint. For that you need to add a new variant Assoc::Point
which returns None
in case the position which contains char_idx
was removed/replaced.
For that to worth tough we need a way to remove InlineAnnotations
so the equivalent for Vec::retain
but for Rc<[T]>
which is not possible without a custom reference counted type (which we probably don't want to add here).
I am considering just switching TextAnnotations
back to using slices instead of Rc
which it originally did. I changed it to make the API easier to use/remove lifetime issues that occured in #5340 but I think those issues were actually resolved by something else so maybe a slice is a better choice afterall.
I don't have more time to look into this right now but you could start with implementing Assoc::Delete
and I will try to comeup with something in the next couple of days.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I want to do this in this PR. Nor that I am qualified to do it.
ChangeSet::map_pos()
currently unconditionnally returns a usize
, adding Assoc::Delete
or Assoc::Point
would need to change the return type to account for the deletion cleanly.
Instead I think this PR should either be blocked until map_pos
and Assoc::...
are better equipped or, if we don't want to block too long, make an issue for it and fix it later on since for now Assoc::After
works well enough (it probably has strange edge cases at the end of files but apart from that it should be okay for a v1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't feel confident working on this that's fine. I will create a PR myself in the next couple days that that you can then depend on. It's not that big of a change so I dlunt it will block this PR for long.
I think it is a requirement for this because without properly handeling this some odd effects do occur. For example if you delete two lines 2xd
then all inlay hints within those lines are moved to the start of the next line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually changed my mind on this. Mapping points doesn't work well in general. The right fix here would be to convert these points to ranges by expanding to the word at the specific position and then tracking that range (only removing it when empty just like we do for diagnostics).
I have a pretty good idea how to implement this but it's a bit more effort and I don't have the necessary time right now. In practice this not as large of a problem as I orginally tough because the type hints get refreshed relatively quickly (on idle timeout) so the artificats usually don't stick around for that long. So I think I can do the necessary refactors in a followup PR.
3f1b568
to
b96469d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed some of the comments, I'm gonna work on the bigger ones now
Hi and thanks for working on this! |
Those should probably be options. I agree that some of that sound nice, though I think implementing them in this MR would delay it too much: I would prefer having something working merged then refine it as user reports pop up :), that way we can both keep this MR relatively small (my time is sadly limited, the maintainers' time too) and account for lots of reports at once instead of just the people following this MR Does that sound good to you ? |
+1. I didn't notice this problem while using vscode, so there is a way to do it "right". |
Thanks for the work on this part of Helix, this is one of the features I really want to use.
If I compare it with VS code, the experience there is more pleasant because there is a delay after the last change until the LSP type hint is adjusted. I don't think it would be good to disable the LSP type hint in the current line or completely in insert mode, because I personally like to check the result value as I type and it's a welcome hint to see if the result is an option or already a T, especially if you're new to a project or using a new API. |
Hmm this isn't blocking but I've noticed that if I make a selection the code is selected but the hints aren't highlighted as a part of the selection. It's probably better this way, but do we get the same behaviour in VSCode and elsewhere? |
Yeah vscode behaves the same and it's very tricky to change because we do selectionswith syntax highlights. If we applied those to virtual text than virtual text would have the full style of the text (so syntax highlight color, dagnowtic underlines...) |
+1 This behaves similar to VSCode |
I can’t do anything about that, all inlay hints in Helix will behave like that due to how they’re rendered, though I agree it isn’t the most agreable. Writing a « dumb » fix here (offsetting by one) for type hints would break for arguments and hints at the end of a line |
It's not perfect but yeah as @poliorcetics said that's kind of just how the cursor works in helix. In insertmode we increase the selection size by one and insert before the cursor block. If you use block cursors its much more clear why it works the way it does: The selection extends one character after the virtual text. Maybe if we switch to zero width cursors oneday that could be solved but i am not sure about that. I could also do some evil trickery here to sepcical case bar cursors but I would rather not do that. |
I actually would like to see an optional patch for that (sorry can't do it myself just started learning rust) |
Since I am a non-ascii characters user, the block cursor is so unfriendly to Chinese characters that I hardly ever use it. The fact that this problem was not realized before means that it does not affect me much. Hope to become a better experience in the future. thanks |
(I'm won't do it in this MR but here is a potential solution):
I'm not certain how much work it would be to do that, or if it's even possible, but if it works it would probably solve most of the problematic cases ? EDIT: |
I've noticed this issue too, but given that it's a new feature that's also off by default we can resolve this in a follow up. A quick solution we could use: only display hints outside of insert mode. That would also address issues with the hints shifting the code around while you type. Not sure how desirable this would be, the hints are helpful when typing out method parameters. Though that's also resolved by signature help. It just seems to me that hints are more beneficial during reading the code (normal mode) than writing (insert mode). |
I don't know, things disappearing just before I start typing seems very jarring too.
I'm also reading code when I type some more, adding code is not done in a vacuum If we do this it should be an option, because it seems to me to be very much useless to only have type hints outside of insert mode |
I personally think this is a really bad idea. For example, when you're chaining method calls, it's often hard to remember what types the method will return, and being able to see it while in insert mode is very helpful. |
Unlike #6059, type hints is very useful in insert mode. We do not need additional option. |
Agreed, it was just an idea. |
so hyped for all the fantastic virtual text features coming down the pipeline. the next release is going to be off the charts! thanks to the maintainers and everyone involved <3 |
Awesome! |
I think inlay-hints theme text style should fallback to the comment style. |
* misc: missing inline, outdated link * doc: Add new theme keys and config option to book * fix: don't panic in Tree::try_get(view_id) Necessary for later, where we could be receiving an LSP response for a closed window, in which case we don't want to crash while checking for its existence * fix: reset idle timer on all mouse events * refacto: Introduce Overlay::new and InlineAnnotation::new * refacto: extract make_job_callback from Context::callback * feat: add LSP display_inlay_hint option to config * feat: communicate inlay hints support capabilities of helix to LSP server * feat: Add function to request range of inlay hint from LSP * feat: Save inlay hints in document, per view * feat: Update inlay hints on document changes * feat: Compute inlay hints on idle timeout * nit: Add todo's about inlay hints for later * fix: compute text annotations for current view in view.rs, not document.rs * doc: Improve Document::text_annotations() description * nit: getters don't use 'get_' in front * fix: Drop inlay hints annotations on config refresh if necessary * fix: padding theming for LSP inlay hints * fix: tracking of outdated inlay hints should not be dependant on document revision (because of undos and such) * fix: follow LSP spec and don't highlight padding as virtual text * config: add some LSP inlay hint configs
* misc: missing inline, outdated link * doc: Add new theme keys and config option to book * fix: don't panic in Tree::try_get(view_id) Necessary for later, where we could be receiving an LSP response for a closed window, in which case we don't want to crash while checking for its existence * fix: reset idle timer on all mouse events * refacto: Introduce Overlay::new and InlineAnnotation::new * refacto: extract make_job_callback from Context::callback * feat: add LSP display_inlay_hint option to config * feat: communicate inlay hints support capabilities of helix to LSP server * feat: Add function to request range of inlay hint from LSP * feat: Save inlay hints in document, per view * feat: Update inlay hints on document changes * feat: Compute inlay hints on idle timeout * nit: Add todo's about inlay hints for later * fix: compute text annotations for current view in view.rs, not document.rs * doc: Improve Document::text_annotations() description * nit: getters don't use 'get_' in front * fix: Drop inlay hints annotations on config refresh if necessary * fix: padding theming for LSP inlay hints * fix: tracking of outdated inlay hints should not be dependant on document revision (because of undos and such) * fix: follow LSP spec and don't highlight padding as virtual text * config: add some LSP inlay hint configs
do i need to use helix manually compiled on main to use this feature ? |
No this was released in 23.05 I believe, you just need to enable it in your config. And for some languages you might need to enable it on the actual language server. |
Since helix-editor/helix#5934 landed in 23.05 helix supports hints from the LSP. This PR change the hints colors to be the same as comments because otherwise they show the same colour as code which is confusing.
Add support for LSP type hints (merged in version 3.17 of the spec, a few month old now).
For now, I only added it in the main editor views, pickers do not have type hints.
Even if we decide they need to, I would prefer doing it in another PR since this one is already big
enough as it is.
I'll join a screen in a comment below, and if people could try it out with their LSPs and configs, it
would be very useful, since I pretty much only use Rust-Analyzer so testing may be somewhat limited still.
Closes #2070
EDIT: instructions to test