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

Update support for rust-analyzer's inlay hints #3404

Merged
merged 6 commits into from
Mar 24, 2022

Conversation

rjmac
Copy link

@rjmac rjmac commented Mar 15, 2022

I believe that this is no longer actually rust-analyzer-specific and
instead will work with any LSP backend that supports the draft inlay
hint feature, but I have no other backend to try with.

Fixes #3403

I believe that this is no longer actually rust-analyzer-specific and
instead will work with any LSP backend that supports the draft inlay
hint feature, but I have no other backend to try with.

Fixes emacs-lsp#3403
@github-actions github-actions bot added client One or more of lsp-mode language clients documentation rust labels Mar 15, 2022
(overlay (make-overlay start end nil 'front-advance 'end-advance)))
(-let* (((&rust-analyzer:InlayHint :position :label :kind) hint)
(pos (lsp--position-to-point position))
(overlay (make-overlay pos (+ pos 1) nil 'front-advance 'end-advance)))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually sure what that second parameter should be; pos doesn't work, but the position we get doesn't really have an end per se.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess would be that pos doesn't work because we set evaporate, which makes Emacs remove the hints when they have length 0. I don't know if that's necessary, since we also remove the overlays manually when we update them. Maybe @yyoncho knows more here

lsp-protocol.el Outdated
(defconst lsp/rust-analyzer-inlay-hint-kind-chaining-hint "ChainingHint")
(defconst lsp/rust-analyzer-inlay-hint-kind-type-hint 1)
(defconst lsp/rust-analyzer-inlay-hint-kind-param-hint 2)
(defconst lsp/rust-analyzer-inlay-hint-kind-chaining-hint nil)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nil seems like it's a bug in rust-analyzer? It feels like it should be 3 but it definitely isn't on my machine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so not a bug but an extension to the draft spec.

Copy link

@lnicola lnicola Mar 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So remove the formatting configuration options for them and the
codepath that handled rendering them separately.

Also, ask rust-analyzer not to pre-format the hints on its end so that
the formatting options on the elisp side are actually useful.
@rjmac
Copy link
Author

rjmac commented Mar 21, 2022

This week's r-a added a bunch of new inlay hint options. I'll take a look at adding support for turning them on to this PR sometime tonight.

* Lifetime elision hints
* Reborrow hints
* Closure return type hints

The way rust-analyzer is evolving, the emacs-side formatting looks
like it will become less and less useful, as these new hint types (and
indeed the already-existing chaining hint type) are not distinguished
in a way that the mode can determine; right now, I've left the support
in, but I've disabled it by default in preference to letting the
server format them.  In that case, the server provides a small amount
of formatting info (in particular, whether the inlay should be
formatted with padding on the left and/or right).
@rjmac
Copy link
Author

rjmac commented Mar 22, 2022

As I mentioned in that latest commit message, the emacs-side formatting of hints looks like it'll become less useful over time. The new inlay hint protocol doesn't appear to be expressive enough to tell us what these hints are (being restricted to "parameter" and "type") and indeed the new hints once again provide a null kind. What it does do is tell us about what padding should appear.

So anyway, I've undone the change where I asked rust-analyzer to never format the hints itself and made that configurable (defaulting to on). When it is on, the formatting and spacing stuff is all ignored - the code assumes that the label comes back pre-formatted and uses the paddingLeft and paddingRight fields in the response instead of a spacing configuration.

I'm not super happy with it, to be honest, but I thought I'd put it out there and see what other people have to say. My current inclination is to remove the elisp formatting code altogether, always have rust-analyzer format it, and use the kind field only to determine the exact font-face to display the inlay with, but I honestly have no extremely strong opinion about what it should do, and I'm really only a drive-by contributor, so I'll happily take input from anybody (especially regular maintainers!)

@rjmac
Copy link
Author

rjmac commented Mar 22, 2022

But all that said, if you're curious, here are the new lifetime elision, closure return type, and reborrowing hints showing up in Emacs:
image

@yyoncho
Copy link
Member

yyoncho commented Mar 22, 2022

@flodiebold @brotzeit willing to take a look?

@lnicola
Copy link

lnicola commented Mar 22, 2022

The new inlay hint protocol doesn't appear to be expressive enough to tell us what these hints are

Oof, @Veykril can we use parameter/parameter/type for those three? Lifetimes are parameters too.

@Veykril
Copy link

Veykril commented Mar 22, 2022

That sounds wrong to me, those kinds are solely meant for styling, with null falling back to the default styling the user chooses. I'm not sure what the problem here is though, null is a valid kind, the one that applies the default styling?

It's a classic case of the LSP being limited to only a few known things and not allowing custom kinds though which I believe is a serious flaw in the spec :/

Copy link
Contributor

@flodiebold flodiebold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM mostly. I agree that letting rust-analyzer format the hints is probably the way forward.

@@ -342,6 +342,13 @@ PARAMS progress report notification data."
:group 'lsp-rust-analyzer
:package-version '(lsp-mode . "6.2"))

(defcustom lsp-rust-analyzer-server-format-inlay-hints t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general I'd prefer if the defcustoms mirror the naming of the options in rust-analyzer, but I recognize it's too late here :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left that on the wrong line, it was referring to lsp-rust-analyzer-display-lifetime-elision-hints etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add defvaralias for those options and update the names to reflect the rust-analyzer options. It would certainly make things less confusing for users.

:chainingHints ,(lsp-json-bool lsp-rust-analyzer-display-chaining-hints)
:closureReturnTypeHints ,(lsp-json-bool lsp-rust-analyzer-display-closure-return-type-hints)
:lifetimeElisionHints ,lsp-rust-analyzer-display-lifetime-elision-hints
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the structure of this setting might change again soon (right, @Veykril ?), so maybe it's best to just leave it out

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you're right, that's rust-lang/rust-analyzer#11778. Hasn't actually happened yet, but I'm aware it almost certainly will.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that will change, I'll do that later today and let you know here again.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and changed one of the configs here https://github.com/rust-analyzer/rust-analyzer/pull/11789/files

Note that r-a might have to change a bunch of configs in the future for consistency ( we dug ourselves a bad hole here rust-lang/rust-analyzer#11790 )

(overlay (make-overlay start end nil 'front-advance 'end-advance)))
(-let* (((&rust-analyzer:InlayHint :position :label :kind) hint)
(pos (lsp--position-to-point position))
(overlay (make-overlay pos (+ pos 1) nil 'front-advance 'end-advance)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess would be that pos doesn't work because we set evaporate, which makes Emacs remove the hints when they have length 0. I don't know if that's necessary, since we also remove the overlays manually when we update them. Maybe @yyoncho knows more here

@rjmac
Copy link
Author

rjmac commented Mar 22, 2022

Ah ok, that makes more sense. Looking at it in that light, I think I can make it a fair bit less scattered-feeling today, then I'll consider the PR "done".

Robert Macomber added 3 commits March 22, 2022 22:34
Now we always rely on rust-analyzer for spacing info, but allow the
formatting within the label proper to be overridden emacs-side.
@rjmac
Copy link
Author

rjmac commented Mar 23, 2022

Ok, I'm pretty happy with the PR as it is now. I incorporated most of the feedback above, specifically:

  • The new-as-of-today lifetime hint configuration is used
  • The overlay creation code has been substantially simplified so there's really only one majro path through it. Spacing is now controlled purely by the padding values in the inlay information rust-analyzer returns rather than emacs-side config. I've left in emacs-side config for formatting "type" and "parameter" hints (default disabled, just letting rust-analyzer handle it) but always use the kind to determine which face to lay out the overlays in.
  • I didn't do the the defvaralias thing mainly because it wasn't obvious to me how it interacted with the customization system.

@brotzeit
Copy link
Member

I didn't do the the defvaralias thing mainly because it wasn't obvious to me how it interacted with the customization system.

AFAIK it shouldn't make a difference if we don't change :type for the new defcustom. But you don't have to apply it, maybe I'll update the names. I merge this now, thanks for your work.

@brotzeit brotzeit merged commit 704f9d6 into emacs-lsp:master Mar 24, 2022
@rksm
Copy link

rksm commented Mar 24, 2022

Thank you @rjmac, very much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client One or more of lsp-mode language clients documentation rust
Projects
None yet
Development

Successfully merging this pull request may close these issues.

lens-mode / inlayHints broken with rust-analyzer since 2022-03-04
7 participants