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

lsp-rust: add semantic token modifiers #3668

Merged
merged 1 commit into from
Oct 10, 2022

Conversation

alanz
Copy link
Contributor

@alanz alanz commented Aug 9, 2022

This is more of a proof-of-concept than anything else.

It works for the "mutable" modifier, adding an underline. This matches
what the VsCode client does, but clashes with the lsp-mode default for
read vs write highlighted variables. The rest have a no-operation face
assigned, but need to be there to get the numbers right.

It is based on the approach in lsp-terraform.el. I tried setting it
in the client registration as per lsp-clojure.el, but the final
mapping of fonts to indexes does not work for some reason,
as the call to lsp--semantic-tokens-initialize-workspace does not get
the correct value from (lsp-semantic-tokens--modifier-faces-for client),
despite them being set elsewhere. I suspect a timing or update problem.

I set (setq lsp-semantic-tokens-enable t) in (use-package lsp-mode in my personal init file to enable this.

@github-actions github-actions bot added client One or more of lsp-mode language clients rust labels Aug 9, 2022
Comment on lines 1297 to 1300
(defvar font-lock-documentation-modifier-face 'font-lock-nop-face
"Face name to use for documentation items.")

(defvar font-lock-declaration-modifier-face 'font-lock-nop-face
Copy link
Member

@yyoncho yyoncho Aug 16, 2022

Choose a reason for hiding this comment

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

does it make sense to move these in lsp-semantic-tokens? Also, can you at least prefix them with lsp- and if these are rust specific you can prefix with lsp-rust

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am prefixing them with lsp-rust-analyzer. I see there are already other faces defined in lsp-rust.el, such as lsp-rust-analyzer-inlay-face. Perhaps they should stay here, to keep all the rust config in one place.

clients/lsp-rust.el Outdated Show resolved Hide resolved
@sebastiansturm
Copy link
Contributor

I missed the fact that lsp-terraform-ls uses lsp-terraform-ls--set-tokens; that should probably be cleaned up in a separate PR; I can do that tomorrow or on the weekend.
As for the present PR: there already is an option :semantic-tokens-faces-overrides for lsp-register-client that should allow you to define type and modifier faces on a per-client basis, cf. lsp-clojure.el. In your case, replacing :types by :modifiers and pasting in your list of face definitions should just work. Could you please try that and adapt your PR accordingly (unless of course you find some bug along the way that first needs fixing)? thanks!

@alanz
Copy link
Contributor Author

alanz commented Aug 16, 2022

there already is an option :semantic-tokens-faces-overrides for lsp-register-client

I tried this first, and could not get it to work. See my description in the initial PR comment (#3668 (comment)). I agree it would be the cleanest way to do it.

Note that lsp-clojure sets the fonts only, not modifiers.

@sebastiansturm
Copy link
Contributor

oh, sorry! I'll have a look this evening; if the face overrides don't work out of the box, that should at least be easy enough to fix

@alanz
Copy link
Contributor Author

alanz commented Aug 17, 2022

if the face overrides don't work out of the box, that should at least be easy enough to fix

I think the problem is in lsp-semantic-tokens--replace-alist-values. It only replaces fonts for the set of modifiers already in lsp-semantic-token-modifier-faces, when called from lsp-semantic-tokens--modifier-faces-for. So perhaps those parameters should be swapped, or the ones in the new modifiers list should be added to the set.

@sebastiansturm
Copy link
Contributor

good catch, thank you! Just wanted to start debugging and then I noticed you already found the culprit :) I opened a mini-pr but haven't tested it yet

@@ -945,7 +946,9 @@ or JSON objects in `rust-project.json` format."
:library-folders-fn (lambda (_workspace) lsp-rust-analyzer-library-directories)
:after-open-fn (lambda ()
(when lsp-rust-analyzer-server-display-inlay-hints
(lsp-rust-analyzer-inlay-hints-mode)))
(lsp-rust-analyzer-inlay-hints-mode))
(when lsp-semantic-tokens-enable
Copy link
Member

Choose a reason for hiding this comment

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

Does this work for you ?

I tried this approach in terraform mode and I could see that the terraform language server was not getting initialized with the proper values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does work for me for lsp-rust and rust-analyzer using my branch https://github.com/alanz/lsp-mode/tree/semantic-tokens-plus-optimise-modifiers which is a combination of #3668 and #3670

Copy link
Member

Choose a reason for hiding this comment

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

I tried again and these are my observations:

  • The buffer local variable is actually set properly.
  • The terraform language server is not initialized with the right values. I believe the after-open-fn is too late in the lifecycle process to change the initialization values.

It could be that your other changes in your branch may cause this to work. I will wait till your changes are merged, before giving it an attempt again.

I think a more proper fix for this would be to allow proper initialization in the make-lsp-client function itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It might relate to the initial capability negotiation. The rust language server ignores the capabilities the client sends, and always returns a fixed modifiers legend (fixed for the given version of the language server).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that's probably it.

Copy link
Member

@psibi psibi left a comment

Choose a reason for hiding this comment

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

Minor comment.

@psibi
Copy link
Member

psibi commented Aug 19, 2022

I missed the fact that lsp-terraform-ls uses lsp-terraform-ls--set-tokens; that should probably be cleaned up in a separate PR; I can do that tomorrow or on the weekend.
As for the present PR: there already is an option :semantic-tokens-faces-overrides for lsp-register-client that should allow you to define type and modifier faces on a per-client basis, cf. lsp-clojure.el.

@sebastiansturm I tried the approach for terraform today and for some reason it doesn't seem to be working. The language server is not getting initialized with the right values. I can test your PR with terraform ls server, if you get to it.

@sebastiansturm
Copy link
Contributor

@psibi I changed my PR to take face overrides into account when sending out client capabilities; I'd appreciate it if you could test that against terraform ls (with appropriate face overrides used in lsp-register-client)

@psibi
Copy link
Member

psibi commented Sep 2, 2022

@sebastiansturm Thanks! I tested your PR against terraform and left my comment here: #3680 (comment)

@alanz
Copy link
Contributor Author

alanz commented Oct 3, 2022

What still has to happen to get this PR to land?

@sebastiansturm
Copy link
Contributor

I think it's fine, though I'd prefer it to use semantic token overrides, which in turn requires #3680 (and that one still requires an approving review). I'll ping the other thread

@alanz
Copy link
Contributor Author

alanz commented Oct 6, 2022

I think it's fine, though I'd prefer it to use semantic token overrides, which in turn requires #3680 (and that one still requires an approving review). I'll ping the other thread

I updated this to use the overrides, hopefully we can now land it. Except I see some stray changes came in with the rebase. Will update.

@@ -926,6 +927,37 @@ or JSON objects in `rust-project.json` format."
(lsp-defun lsp-rust--analyzer-debug-lens ((&Command :arguments? [args]))
(lsp-rust-analyzer-debug args))

(defun lsp-rust-analyzer--semantic-modifiers ()
Copy link
Contributor

Choose a reason for hiding this comment

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

first, thanks a lot for your patience! Sorry the PR has been blocked so long. I'm fine with your PR as-is, though I wonder if there's a reason this is a defun as opposed to a variable, defcustom or something? Not trying to be annoying here, honest question :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The simple answer is I repurposed the prior version, and changed the function name to plug it into a new place. I will take a look when I have time to make it something more idiomatic.

This is more of a proof-of-concept than anything else.

It works for the "mutable" modifier, adding an underline. This matches
what the VsCode client does, but clashes with the lsp-mode default for
read vs write highlighted variables.

The "reference" modifier has the bold attribute set.

The rest have a no-operation face assigned, but need to be there to
get the font caluclation numbers right, and to be customized by users.
@alanz
Copy link
Contributor Author

alanz commented Oct 9, 2022

I made a variable for each specific semantic modifier, since the set of modifiers is fixed for a given version of rust-analyzer, and has not changed yet.

Rather than having a fallback default font that does nothing, I made a face for each font, so you can use describe-char to understand what modifiers are active.

@sebastiansturm
Copy link
Contributor

thanks, that's very thorough :). LGTM, though personally I'd probably still have used a defvar/defcustom instead of a defun for lsp-rust-analyzer--semantic-modifiers (or perhaps even a defconst if each of its entries is now separately customizable -- not sure). I'm fine with merging this as-is; @yyoncho / @ericdallo : do you have a strong opinion on the use of defun here?

@ericdallo
Copy link
Member

Both are ok to me, but personally, I'd use a variable or const for better performance trading CPU for memory

@alanz
Copy link
Contributor Author

alanz commented Oct 10, 2022

From my side I would like to see it land, and then the exact custom process can be optimized. Probably not by me :)

@ericdallo ericdallo merged commit 759fb79 into emacs-lsp:master Oct 10, 2022
yyoncho pushed a commit to yyoncho/lsp-mode that referenced this pull request Oct 24, 2022
This is more of a proof-of-concept than anything else.

It works for the "mutable" modifier, adding an underline. This matches
what the VsCode client does, but clashes with the lsp-mode default for
read vs write highlighted variables.

The "reference" modifier has the bold attribute set.

The rest have a no-operation face assigned, but need to be there to
get the font caluclation numbers right, and to be customized by users.
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.

None yet

5 participants