Skip to content

Instantly share code, notes, and snippets.

@casouri
Last active August 31, 2024 17:22
Show Gist options
  • Save casouri/0ad2c6e58965f6fd2498a91fc9c66501 to your computer and use it in GitHub Desktop.
Save casouri/0ad2c6e58965f6fd2498a91fc9c66501 to your computer and use it in GitHub Desktop.
Configuring eglot for rust-analyzer
;; How to translate LSP configuration examples into Eglot’s format:
;;
;; Usually LSP servers will say something like
;;
;; rust-analyzer.procMacro.attributes.enable (default: true)
;;
;; Translate that into a JSON LSP configuration, you get
;;
;; {
;; "rust-analyzer": {
;; "procMacro": {
;; "attributes": {
;; "enable": true
;; }
;; }
;; }
;; }
;;
;; In general the key at the root level must be the LSP server’s name,
;; so that one configuration can cover multiple servers. If the LSP
;; server’s documentation omitted the name part, remember to add it
;; yourself.
;;
;; Translate that into plist format that Eglot uses, you get
;;
;; (:rust-analyzer (:procMacro (:attributes (:enable t))))
;;
;; Keys translate to keywords (with the same spelling and case),
;; dictionaries translate to plists, arrays translate to vectors, true
;; translates to t, false translates to a special keyword :json-false,
;; null translates to nil, empty directory {} translates to eglot-{}.
;; Define a setup function that runs in the mode hook.
(defun setup-rust ()
"Setup for ‘rust-mode’."
;; Configuration taken from rust-analyzer’s manual:
;; https://rust-analyzer.github.io/manual.html#configuration
(setq-local eglot-workspace-configuration
;; Setting the workspace configuration for every
;; rust-mode buffer, you can also set it with dir-local
;; variables, should you want different configuration
;; per project/directory.
'(:rust-analyzer
( :procMacro ( :attributes (:enable t)
:enable t)
:cargo (:buildScripts (:enable t))
:diagnostics (:disabled ["unresolved-proc-macro"
"unresolved-macro-call"])))))
;; Run our setup function in ‘rust-mode-hook’.
(add-hook 'rust-mode-hook #'setup-rust)
;; Define a custom eglot LSP server for rust-analyzer because it
;; expects initializationOptions done a bit differently (see below).
(defclass eglot-rust-analyzer (eglot-lsp-server) ()
:documentation "A custom class for rust-analyzer.")
;; Rust-analyzer requires the workspaceConfiguration sent as
;; initializationOptions at startup time. See
;; https://github.com/joaotavora/eglot/discussions/845 and
;; rust-analyzer’s manual page.
(cl-defmethod eglot-initialization-options ((server eglot-rust-analyzer))
eglot-workspace-configuration)
;; Use our custom ‘eglot-rust-analyzer’ for ‘rust-mode’.
(add-to-list 'eglot-server-programs
'(rust-mode . (eglot-rust-analyzer "rust-analyzer")))
@Ralith
Copy link

Ralith commented Jul 30, 2023

The hacks for initializationOptions no longer seem to be necessary. I'm having success with:

(use-package eglot
  :hook ((rust-mode nix-mode) . eglot-ensure)
  :config (add-to-list 'eglot-server-programs
                       `(rust-mode . ("rust-analyzer" :initializationOptions
                                     ( :procMacro (:enable t)
                                       :cargo ( :buildScripts (:enable t)
                                                :features "all"))))))

@casouri
Copy link
Author

casouri commented Jul 31, 2023

That's good to hear 😄

@ethercflow
Copy link

Thank you all, these helps me a lot!

@ethercflow
Copy link

Hi @Ralith @casouri , sorry to bother you. I wrote below code in .dir-locals.el

((rustic-mode
  .((eglot-workspace-configuration
     . (:rust-analyzer
        ( :procMacro ( :attributes (:enable t)
                       :enable t)
          :cargo ( :buildScripts (:enable t)
                   :features "all")
          :diagnostics ( :disabled ["unresolved-proc-macro"
                                    "unresolved-macro-call"])))))))

From EGLOT events buffer, I see

[client-notification] Fri Nov 24 22:18:58 2023:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
          (:settings
           (:rust-analyzer
            (:procMacro
             (:attributes
              (:enable t)
              :enable t)
             :cargo
             (:buildScripts
              (:enable t)
              :features "all")
             :diagnostics
             (:disabled
              ["unresolved-proc-macro" "unresolved-macro-call"])))))
              
[client-reply] (id:1) Fri Nov 24 22:18:59 2023:
(:jsonrpc "2.0" :id 1 :result
          [(:procMacro
            (:attributes
             (:enable t)
             :enable t)
            :cargo
            (:buildScripts
             (:enable t)
             :features "all")
            :diagnostics
            (:disabled
             ["unresolved-proc-macro" "unresolved-macro-call"]))])

But Emacs still report rust-analyzer: code is inactive due to #[cfg] directives: tokio_unstable is disabled. Would you please give me a hand? Thanks a lot!

My test code is tokio: https://github.com/tokio-rs/tokio/blob/master/tokio/src/sync/mutex.rs#L130

@Ralith
Copy link

Ralith commented Nov 25, 2023

Looks sensible for me, but I've never tried to do anything workspace-specific. Maybe eglot and/or rust-analyzer are misbehaving?

@ethercflow
Copy link

@Ralith I found the reason: need to add: :cfgs (:tokio_unstable "") below :features "all". Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment