1641 lines
66 KiB
EmacsLisp
1641 lines
66 KiB
EmacsLisp
;;; lsp-rust.el --- Rust Client settings -*- lexical-binding: t; -*-
|
||
|
||
;; Copyright (C) 2019 Ivan Yonchovski
|
||
|
||
;; Author: Ivan Yonchovski <yyoncho@gmail.com>
|
||
;; Keywords:
|
||
|
||
;; This program is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation, either version 3 of the License, or
|
||
;; (at your option) any later version.
|
||
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;; lsp-rust client
|
||
|
||
;;; Code:
|
||
|
||
(require 'lsp-mode)
|
||
(require 'ht)
|
||
(require 'dash)
|
||
(require 'lsp-semantic-tokens)
|
||
|
||
(defgroup lsp-rust nil
|
||
"LSP support for Rust, using Rust Language Server or rust-analyzer."
|
||
:group 'lsp-mode
|
||
:link '(url-link "https://github.com/rust-lang/rls")
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defgroup lsp-rust-rls nil
|
||
"LSP support for Rust, using Rust Language Server."
|
||
:group 'lsp-mode
|
||
:link '(url-link "https://github.com/rust-lang/rls")
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defgroup lsp-rust-analyzer nil
|
||
"LSP support for Rust, using rust-analyzer."
|
||
:group 'lsp-mode
|
||
:link '(url-link "https://github.com/rust-analyzer/rust-analyzer")
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defgroup lsp-rust-analyzer-semantic-tokens nil
|
||
"LSP semantic tokens support for rust-analyzer."
|
||
:group 'lsp-rust-analyzer
|
||
:link '(url-link "https://github.com/rust-analyzer/rust-analyzer")
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-server 'rust-analyzer
|
||
"Choose LSP server."
|
||
:type '(choice (const :tag "rls" rls)
|
||
(const :tag "rust-analyzer" rust-analyzer))
|
||
:group 'lsp-rust
|
||
:package-version '(lsp-mode . "6.2"))
|
||
|
||
;; RLS
|
||
|
||
(defcustom lsp-rust-rls-server-command '("rls")
|
||
"Command to start RLS."
|
||
:type '(repeat string)
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-library-directories '("~/.cargo/registry/src" "~/.rustup/toolchains")
|
||
"List of directories which will be considered to be libraries."
|
||
:risky t
|
||
:type '(repeat string)
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-sysroot nil
|
||
"If non-nil, use the given path as the sysroot for all rustc invocations
|
||
instead of trying to detect the sysroot automatically."
|
||
:type '(choice
|
||
(const :tag "None" nil)
|
||
(string :tag "Sysroot"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-target nil
|
||
"If non-nil, use the given target triple for all rustc invocations."
|
||
:type '(choice
|
||
(const :tag "None" nil)
|
||
(string :tag "Target"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-rustflags nil
|
||
"Flags added to RUSTFLAGS."
|
||
:type '(choice
|
||
(const :tag "None" nil)
|
||
(string :tag "Flags"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-clear-env-rust-log t
|
||
"Clear the RUST_LOG environment variable before running rustc or cargo."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-build-lib nil
|
||
"If non-nil, checks the project as if you passed the `--lib' argument to
|
||
cargo.
|
||
|
||
Mutually exclusive with, and preferred over, `lsp-rust-build-bin'. (Unstable)"
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-build-bin nil
|
||
"If non-nil, checks the project as if you passed `-- bin <build_bin>'
|
||
argument to cargo.
|
||
|
||
Mutually exclusive with `lsp-rust-build-lib'. (Unstable)"
|
||
:type '(choice
|
||
(const :tag "None" nil)
|
||
(string :tag "Binary"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-cfg-test nil
|
||
"If non-nil, checks the project as if you were running `cargo test' rather
|
||
than cargo build.
|
||
|
||
I.e., compiles (but does not run) test code."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-unstable-features nil
|
||
"Enable unstable features."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-wait-to-build nil
|
||
"Time in milliseconds between receiving a change notification
|
||
and starting build. If not specified, automatically inferred by
|
||
the latest build duration."
|
||
:type '(choice
|
||
(const :tag "Auto" nil)
|
||
(number :tag "Time"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-show-warnings t
|
||
"Show warnings."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-crate-blacklist [
|
||
"cocoa"
|
||
"gleam"
|
||
"glium"
|
||
"idna"
|
||
"libc"
|
||
"openssl"
|
||
"rustc_serialize"
|
||
"serde"
|
||
"serde_json"
|
||
"typenum"
|
||
"unicode_normalization"
|
||
"unicode_segmentation"
|
||
"winapi"
|
||
]
|
||
"A list of Cargo crates to blacklist."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-build-on-save nil
|
||
"Only index the project when a file is saved and not on change."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-features []
|
||
"List of features to activate.
|
||
Set this to `\"all\"` to pass `--all-features` to cargo."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-all-features nil
|
||
"Enable all Cargo features."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-no-default-features nil
|
||
"Do not enable default Cargo features."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-racer-completion t
|
||
"Enables code completion using racer."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-clippy-preference "opt-in"
|
||
"Controls eagerness of clippy diagnostics when available.
|
||
Valid values are (case-insensitive):
|
||
- \"off\": Disable clippy lints.
|
||
- \"opt-in\": Clippy lints are shown when crates specify `#![warn(clippy)]'.
|
||
- \"on\": Clippy lints enabled for all crates in workspace.
|
||
|
||
You need to install clippy via rustup if you haven't already."
|
||
:type '(choice
|
||
(const "on")
|
||
(const "opt-in")
|
||
(const "off"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-jobs nil
|
||
"Number of Cargo jobs to be run in parallel."
|
||
:type '(choice
|
||
(const :tag "Auto" nil)
|
||
(number :tag "Jobs"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-all-targets t
|
||
"Checks the project as if you were running cargo check --all-targets.
|
||
I.e., check all targets and integration tests too."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-target-dir nil
|
||
"When specified, it places the generated analysis files at the
|
||
specified target directory. By default it is placed target/rls
|
||
directory."
|
||
:type '(choice
|
||
(const :tag "Default" nil)
|
||
(string :tag "Directory"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-rustfmt-path nil
|
||
"When specified, RLS will use the Rustfmt pointed at the path
|
||
instead of the bundled one"
|
||
:type '(choice
|
||
(const :tag "Bundled" nil)
|
||
(string :tag "Path"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-build-command nil
|
||
"EXPERIMENTAL (requires `rust.unstable_features')
|
||
If set, executes a given program responsible for rebuilding save-analysis to be
|
||
loaded by the RLS. The program given should output a list of resulting .json
|
||
files on stdout.
|
||
|
||
Implies `rust.build_on_save': true."
|
||
:type '(choice
|
||
(const :tag "None" nil)
|
||
(string :tag "Command"))
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-full-docs nil
|
||
"Instructs cargo to enable full documentation extraction during
|
||
save-analysis while building the crate."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(defcustom lsp-rust-show-hover-context t
|
||
"Show additional context in hover tooltips when available. This
|
||
is often the type local variable declaration."
|
||
:type 'boolean
|
||
:group 'lsp-rust-rls
|
||
:package-version '(lsp-mode . "6.1"))
|
||
|
||
(lsp-register-custom-settings
|
||
'(("rust.show_hover_context" lsp-rust-show-hover-context t)
|
||
("rust.full_docs" lsp-rust-full-docs t)
|
||
("rust.build_command" lsp-rust-build-command)
|
||
("rust.rustfmt_path" lsp-rust-rustfmt-path)
|
||
("rust.target_dir" lsp-rust-target-dir)
|
||
("rust.all_targets" lsp-rust-all-targets t)
|
||
("rust.jobs" lsp-rust-jobs)
|
||
("rust.clippy_preference" lsp-rust-clippy-preference)
|
||
("rust.racer_completion" lsp-rust-racer-completion t)
|
||
("rust.no_default_features" lsp-rust-no-default-features t)
|
||
("rust.all_features" lsp-rust-all-features t)
|
||
("rust.features" lsp-rust-features)
|
||
("rust.build_on_save" lsp-rust-build-on-save t)
|
||
("rust.crate_blacklist" lsp-rust-crate-blacklist)
|
||
("rust.show_warnings" lsp-rust-show-warnings t)
|
||
("rust.wait_to_build" lsp-rust-wait-to-build)
|
||
("rust.unstable_features" lsp-rust-unstable-features t)
|
||
("rust.cfg_test" lsp-rust-cfg-test t)
|
||
("rust.build_bin" lsp-rust-build-bin)
|
||
("rust.build_lib" lsp-rust-build-lib t)
|
||
("rust.clear_env_rust_log" lsp-rust-clear-env-rust-log t)
|
||
("rust.rustflags" lsp-rust-rustflags)
|
||
("rust.target" lsp-rust-target)
|
||
("rust.sysroot" lsp-rust-sysroot)))
|
||
|
||
(defun lsp-clients--rust-window-progress (workspace params)
|
||
"Progress report handling.
|
||
PARAMS progress report notification data."
|
||
(-let [(&v1:ProgressParams :done? :message? :title) params]
|
||
(if (or done? (s-blank-str? message?))
|
||
(lsp-workspace-status nil workspace)
|
||
(lsp-workspace-status (format "%s - %s" title (or message? "")) workspace))))
|
||
|
||
(lsp-defun lsp-rust--rls-run ((&Command :arguments? params))
|
||
(-let* (((&rls:Cmd :env :binary :args :cwd) (lsp-seq-first params))
|
||
(default-directory (or cwd (lsp-workspace-root) default-directory) ))
|
||
(compile
|
||
(format "%s %s %s"
|
||
(s-join " " (ht-amap (format "%s=%s" key value) env))
|
||
binary
|
||
(s-join " " args)))))
|
||
|
||
(lsp-register-client
|
||
(make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-rust-rls-server-command))
|
||
:activation-fn (lsp-activate-on "rust")
|
||
:priority (if (eq lsp-rust-server 'rls) 1 -1)
|
||
:initialization-options '((omitInitBuild . t)
|
||
(cmdRun . t))
|
||
:notification-handlers (ht ("window/progress" 'lsp-clients--rust-window-progress))
|
||
:action-handlers (ht ("rls.run" 'lsp-rust--rls-run))
|
||
:library-folders-fn (lambda (_workspace) lsp-rust-library-directories)
|
||
:initialized-fn (lambda (workspace)
|
||
(with-lsp-workspace workspace
|
||
(lsp--set-configuration
|
||
(lsp-configuration-section "rust"))))
|
||
:server-id 'rls))
|
||
|
||
|
||
;; rust-analyzer
|
||
(defcustom lsp-rust-analyzer-server-command '("rust-analyzer")
|
||
"Command to start rust-analyzer."
|
||
:type '(repeat string)
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-library-directories '("~/.cargo/registry/src" "~/.rustup/toolchains")
|
||
"List of directories which will be considered to be libraries."
|
||
:risky t
|
||
:type '(repeat string)
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-server-format-inlay-hints t
|
||
"Whether to ask rust-analyzer to format inlay hints itself. If
|
||
active, the various inlay format settings are not used."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-hide-closure-initialization nil
|
||
"Whether to hide inlay type hints for `let` statements that initialize
|
||
to a closure. Only applies to closures with blocks, same as
|
||
`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-hide-named-constructor nil
|
||
"Whether to hide inlay type hints for constructors."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-max-inlay-hint-length nil
|
||
"Max inlay hint length."
|
||
:type 'integer
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-chaining-hints nil
|
||
"Whether to show inlay type hints for method chains. These
|
||
hints will be formatted with the type hint formatting options, if
|
||
the mode is not configured to ask the server to format them."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-enable "never"
|
||
"Whether to show elided lifetime inlay hints."
|
||
:type '(choice
|
||
(const "never")
|
||
(const "always")
|
||
(const "skip_trivial"))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names nil
|
||
"When showing elided lifetime inlay hints, whether to use
|
||
parameter names or numeric placeholder names for the lifetimes."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-closure-return-type-hints nil
|
||
"Whether to show closure return type inlay hints for closures
|
||
with block bodies."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-parameter-hints nil
|
||
"Whether to show function parameter name inlay hints at the call site."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-display-reborrow-hints "never"
|
||
"Whether to show inlay type hints for compiler inserted reborrows."
|
||
:type '(choice
|
||
(const "always")
|
||
(const "never")
|
||
(const "mutable"))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-binding-mode-hints nil
|
||
"Whether to show inlay type hints for binding modes."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-closing-brace-hints t
|
||
"Whether to show inlay hints after a closing `}` to indicate what item it
|
||
belongs to."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-closing-brace-hints-min-lines 25
|
||
"Minimum number of lines required before the `}` until the hint is shown
|
||
\(set to 0 or 1 to always show them)."
|
||
:type 'integer
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lru-capacity nil
|
||
"Number of syntax trees rust-analyzer keeps in memory."
|
||
:type 'integer
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-target nil
|
||
"Compilation target (target triple)."
|
||
:type '(choice
|
||
(string :tag "Target")
|
||
(const :tag "None" nil))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-watch-enable t
|
||
"Enable Cargo watch."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-watch-command "check"
|
||
"Cargo watch command."
|
||
:type 'string
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-watch-args []
|
||
"Extra arguments for `cargo check`."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-override-command []
|
||
"Advanced option, fully override the command rust-analyzer uses for checking.
|
||
The command should include `--message=format=json` or similar option."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-check-all-targets t
|
||
"Enables --all-targets for `cargo check`."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-checkonsave-features []
|
||
"List of features to activate.
|
||
Set this to `\"all\"` to pass `--all-features` to cargo."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-unset-test []
|
||
"force rust-analyzer to unset `#[cfg(test)]` for the specified crates."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-use-client-watching t
|
||
"Use client watching"
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-exclude-globs []
|
||
"Exclude globs"
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-exclude-dirs []
|
||
"These directories will be ignored by rust-analyzer."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-macro-expansion-method 'lsp-rust-analyzer-macro-expansion-default
|
||
"Use a different function if you want formatted macro expansion results and
|
||
syntax highlighting."
|
||
:type 'function
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.2.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-diagnostics-enable t
|
||
"Whether to show native rust-analyzer diagnostics."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-diagnostics-enable-experimental nil
|
||
"Whether to show native rust-analyzer diagnostics that are still experimental
|
||
\(might have more false positives than usual)."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-diagnostics-disabled []
|
||
"List of native rust-analyzer diagnostics to disable."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-diagnostics-warnings-as-hint []
|
||
"List of warnings that should be displayed with hint severity."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-diagnostics-warnings-as-info []
|
||
"List of warnings that should be displayed with info severity."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(define-obsolete-variable-alias
|
||
'lsp-rust-analyzer-cargo-load-out-dirs-from-check
|
||
'lsp-rust-analyzer-cargo-run-build-scripts
|
||
"8.0.0")
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-run-build-scripts t
|
||
"Whether to run build scripts (`build.rs`) for more precise code analysis."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-rustfmt-extra-args []
|
||
"Additional arguments to rustfmt."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-rustfmt-override-command []
|
||
"Advanced option, fully override the command rust-analyzer uses
|
||
for formatting."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-rustfmt-rangeformatting-enable nil
|
||
"Enables the use of rustfmt's unstable range formatting command for the
|
||
`textDocument/rangeFormatting` request. The rustfmt option is unstable and only
|
||
available on a nightly build."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-completion-add-call-parenthesis t
|
||
"Whether to add parenthesis when completing functions."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-completion-add-call-argument-snippets t
|
||
"Whether to add argument snippets when completing functions."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-completion-postfix-enable t
|
||
"Whether to show postfix snippets like `dbg`, `if`, `not`, etc."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-call-info-full t
|
||
"Whether to show function name and docs in parameter hints."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-proc-macro-enable t
|
||
"Enable Proc macro support.
|
||
Implies `lsp-rust-analyzer-cargo-run-build-scripts'"
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "6.3.2"))
|
||
|
||
(defcustom lsp-rust-analyzer-import-prefix "plain"
|
||
"The path structure for newly inserted paths to use.
|
||
Valid values are:
|
||
- \"plain\": Insert import paths relative to the current module, using up to
|
||
one `super' prefix if the parent module contains the requested item.
|
||
- \"by_self\": Prefix all import paths with `self' if they don't begin with
|
||
`self', `super', `crate' or a crate name.
|
||
- \"by_crate\": Force import paths to be absolute by always starting
|
||
them with `crate' or the crate name they refer to."
|
||
:type '(choice
|
||
(const "plain")
|
||
(const "by_self")
|
||
(const "by_crate"))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-import-granularity "crate"
|
||
"How imports should be grouped into use statements."
|
||
:type '(choice
|
||
(const "crate" :doc "Merge imports from the same crate into a single use statement. This kind of nesting is only supported in Rust versions later than 1.24.")
|
||
(const "module" :doc "Merge imports from the same module into a single use statement.")
|
||
(const "item" :doc "Don’t merge imports at all, creating one import per item.")
|
||
(const "preserve" :doc "Do not change the granularity of any imports. For auto-import this has the same effect as `\"item\"'"))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-cargo-auto-reload t
|
||
"Automatically refresh project info via `cargo metadata' on `Cargo.toml' changes."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts t
|
||
"Use `RUSTC_WRAPPER=rust-analyzer' when running build scripts to avoid
|
||
compiling unnecessary things."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-completion-auto-import-enable t
|
||
"Toggles the additional completions that automatically add imports when
|
||
completed. `lsp-completion-enable-additional-text-edit' must be non-nil
|
||
for this feature to be fully enabled."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-completion-auto-self-enable t
|
||
"Toggles the additional completions that automatically show method calls
|
||
and field accesses with self prefixed to them when inside a method."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-import-enforce-granularity nil
|
||
"Whether to enforce the import granularity setting for all files.
|
||
If set to nil rust-analyzer will try to keep import styles consistent per file."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-imports-merge-glob t
|
||
"Whether to allow import insertion to merge new imports into single path
|
||
glob imports like `use std::fmt::*;`."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-import-group t
|
||
"Group inserted imports by the following order:
|
||
https://rust-analyzer.github.io/manual.html#auto-import.
|
||
Groups are separated by newlines."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-highlighting-strings t
|
||
"Use semantic tokens for strings."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-rustc-source nil
|
||
"Path to the Cargo.toml of the rust compiler workspace."
|
||
:type '(choice
|
||
(file :tag "Path")
|
||
(const :tag "None" nil))
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-linked-projects []
|
||
"Disable project auto-discovery in favor of explicitly specified set of
|
||
projects. Elements must be paths pointing to `Cargo.toml`, `rust-project.json`,
|
||
or JSON objects in `rust-project.json` format."
|
||
:type 'lsp-string-vector
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-experimental-proc-attr-macros t
|
||
"Whether to enable experimental support for expanding proc macro attributes."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defun lsp-rust-analyzer--make-init-options ()
|
||
"Init options for rust-analyzer"
|
||
`(:diagnostics (:enable ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable)
|
||
:enableExperimental ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable-experimental)
|
||
:disabled ,lsp-rust-analyzer-diagnostics-disabled
|
||
:warningsAsHint ,lsp-rust-analyzer-diagnostics-warnings-as-hint
|
||
:warningsAsInfo ,lsp-rust-analyzer-diagnostics-warnings-as-info)
|
||
:imports (:granularity (:enforce ,(lsp-json-bool lsp-rust-analyzer-import-enforce-granularity)
|
||
:group ,lsp-rust-analyzer-import-granularity)
|
||
:group ,(lsp-json-bool lsp-rust-analyzer-import-group)
|
||
:merge (:glob ,(lsp-json-bool lsp-rust-analyzer-imports-merge-glob))
|
||
:prefix ,lsp-rust-analyzer-import-prefix)
|
||
:lruCapacity ,lsp-rust-analyzer-lru-capacity
|
||
:checkOnSave (:enable ,(lsp-json-bool lsp-rust-analyzer-cargo-watch-enable)
|
||
:command ,lsp-rust-analyzer-cargo-watch-command
|
||
:extraArgs ,lsp-rust-analyzer-cargo-watch-args
|
||
:allTargets ,(lsp-json-bool lsp-rust-analyzer-check-all-targets)
|
||
:features ,lsp-rust-analyzer-checkonsave-features
|
||
:overrideCommand ,lsp-rust-analyzer-cargo-override-command)
|
||
:files (:exclude ,lsp-rust-analyzer-exclude-globs
|
||
:watcher ,(if lsp-rust-analyzer-use-client-watching "client" "notify")
|
||
:excludeDirs ,lsp-rust-analyzer-exclude-dirs)
|
||
:cargo (:allFeatures ,(lsp-json-bool lsp-rust-all-features)
|
||
:noDefaultFeatures ,(lsp-json-bool lsp-rust-no-default-features)
|
||
:features ,lsp-rust-features
|
||
:target ,lsp-rust-analyzer-cargo-target
|
||
:runBuildScripts ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts)
|
||
; Obsolete, but used by old Rust-Analyzer versions
|
||
:loadOutDirsFromCheck ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts)
|
||
:autoreload ,(lsp-json-bool lsp-rust-analyzer-cargo-auto-reload)
|
||
:useRustcWrapperForBuildScripts ,(lsp-json-bool lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts)
|
||
:unsetTest ,lsp-rust-analyzer-cargo-unset-test)
|
||
:rustfmt (:extraArgs ,lsp-rust-analyzer-rustfmt-extra-args
|
||
:overrideCommand ,lsp-rust-analyzer-rustfmt-override-command
|
||
:rangeFormatting (:enable ,(lsp-json-bool lsp-rust-analyzer-rustfmt-rangeformatting-enable)))
|
||
:lens (:debug (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-debug-enable))
|
||
:enable ,(lsp-json-bool lsp-rust-analyzer-lens-enable)
|
||
;; :forceCustomCommands ,(lsp-json-bool lsp-rust-analyzer-lens-force-custom-commands)
|
||
:implementations (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-implementations-enable))
|
||
;; :location ,lsp-rust-analyzer-lens-location
|
||
:references (:adt (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-adt-enable))
|
||
:enumVariant (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-enum-variant-enable))
|
||
:method (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-method-enable))
|
||
:trait (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-trait-enable)))
|
||
:run (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-run-enable)))
|
||
|
||
:inlayHints (:bindingModeHints ,(lsp-json-bool lsp-rust-analyzer-binding-mode-hints)
|
||
:chainingHints ,(lsp-json-bool lsp-rust-analyzer-display-chaining-hints)
|
||
:closingBraceHints (:enable ,(lsp-json-bool lsp-rust-analyzer-closing-brace-hints)
|
||
:minLines ,lsp-rust-analyzer-closing-brace-hints-min-lines)
|
||
:closureReturnTypeHints ,(lsp-json-bool lsp-rust-analyzer-display-closure-return-type-hints)
|
||
:lifetimeElisionHints (:enable ,lsp-rust-analyzer-display-lifetime-elision-hints-enable
|
||
:useParameterNames ,(lsp-json-bool lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names))
|
||
:maxLength ,lsp-rust-analyzer-max-inlay-hint-length
|
||
:parameterHints ,(lsp-json-bool lsp-rust-analyzer-display-parameter-hints)
|
||
:reborrowHints ,lsp-rust-analyzer-display-reborrow-hints
|
||
:renderColons ,(lsp-json-bool lsp-rust-analyzer-server-format-inlay-hints)
|
||
:typeHints (:enable ,(lsp-json-bool lsp-inlay-hint-enable)
|
||
:hideClosureInitialization ,(lsp-json-bool lsp-rust-analyzer-hide-closure-initialization)
|
||
:hideNamedConstructor ,(lsp-json-bool lsp-rust-analyzer-hide-named-constructor)))
|
||
:completion (:addCallParenthesis ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-parenthesis)
|
||
:addCallArgumentSnippets ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-argument-snippets)
|
||
:postfix (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-postfix-enable))
|
||
:autoimport (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-import-enable))
|
||
:autoself (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-self-enable)))
|
||
:callInfo (:full ,(lsp-json-bool lsp-rust-analyzer-call-info-full))
|
||
:procMacro (:enable ,(lsp-json-bool lsp-rust-analyzer-proc-macro-enable))
|
||
:rustcSource ,lsp-rust-analyzer-rustc-source
|
||
:linkedProjects ,lsp-rust-analyzer-linked-projects
|
||
:highlighting (:strings ,(lsp-json-bool lsp-rust-analyzer-highlighting-strings))
|
||
:experimental (:procAttrMacros ,(lsp-json-bool lsp-rust-analyzer-experimental-proc-attr-macros))))
|
||
|
||
(defconst lsp-rust-notification-handlers
|
||
'(("rust-analyzer/publishDecorations" . (lambda (_w _p)))))
|
||
|
||
(defconst lsp-rust-action-handlers
|
||
'())
|
||
|
||
(define-derived-mode lsp-rust-analyzer-syntax-tree-mode special-mode "Rust-Analyzer-Syntax-Tree"
|
||
"Mode for the rust-analyzer syntax tree buffer.")
|
||
|
||
(defun lsp-rust-analyzer-syntax-tree ()
|
||
"Display syntax tree for current buffer."
|
||
(interactive)
|
||
(-let* ((root (lsp-workspace-root default-directory))
|
||
(params (lsp-make-rust-analyzer-syntax-tree-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:range? (if (use-region-p)
|
||
(lsp--region-to-range (region-beginning) (region-end))
|
||
(lsp--region-to-range (point-min) (point-max)))))
|
||
(results (lsp-send-request (lsp-make-request
|
||
"rust-analyzer/syntaxTree"
|
||
params))))
|
||
(let ((buf (get-buffer-create (format "*rust-analyzer syntax tree %s*" root)))
|
||
(inhibit-read-only t))
|
||
(with-current-buffer buf
|
||
(lsp-rust-analyzer-syntax-tree-mode)
|
||
(erase-buffer)
|
||
(insert results)
|
||
(goto-char (point-min)))
|
||
(pop-to-buffer buf))))
|
||
|
||
(define-derived-mode lsp-rust-analyzer-status-mode special-mode "Rust-Analyzer-Status"
|
||
"Mode for the rust-analyzer status buffer.")
|
||
|
||
(defun lsp-rust-analyzer-status ()
|
||
"Displays status information for rust-analyzer."
|
||
(interactive)
|
||
(-let* ((root (lsp-workspace-root default-directory))
|
||
(params (lsp-make-rust-analyzer-analyzer-status-params
|
||
:text-document (lsp--text-document-identifier)))
|
||
(results (lsp-send-request (lsp-make-request
|
||
"rust-analyzer/analyzerStatus"
|
||
params))))
|
||
(let ((buf (get-buffer-create (format "*rust-analyzer status %s*" root)))
|
||
(inhibit-read-only t))
|
||
(with-current-buffer buf
|
||
(lsp-rust-analyzer-status-mode)
|
||
(erase-buffer)
|
||
(insert results)
|
||
(pop-to-buffer buf)))))
|
||
|
||
(defun lsp-rust-analyzer-view-item-tree ()
|
||
"Show item tree of rust file."
|
||
(interactive)
|
||
(-let* ((params (lsp-make-rust-analyzer-view-item-tree
|
||
:text-document (lsp--text-document-identifier)))
|
||
(results (lsp-send-request (lsp-make-request
|
||
"rust-analyzer/viewItemTree"
|
||
params))))
|
||
(let ((buf (get-buffer-create "*rust-analyzer item tree*"))
|
||
(inhibit-read-only t))
|
||
(with-current-buffer buf
|
||
(special-mode)
|
||
(erase-buffer)
|
||
(insert (lsp--render-string results "rust"))
|
||
(pop-to-buffer buf)))))
|
||
|
||
(defun lsp-rust-analyzer-view-hir ()
|
||
"View Hir of function at point."
|
||
(interactive)
|
||
(-let* ((params (lsp-make-rust-analyzer-expand-macro-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:position (lsp--cur-position)))
|
||
(results (lsp-send-request (lsp-make-request
|
||
"rust-analyzer/viewHir"
|
||
params))))
|
||
(let ((buf (get-buffer-create "*rust-analyzer hir*"))
|
||
(inhibit-read-only t))
|
||
(with-current-buffer buf
|
||
(special-mode)
|
||
(erase-buffer)
|
||
(insert results)
|
||
(pop-to-buffer buf)))))
|
||
|
||
(defun lsp-rust-analyzer-join-lines ()
|
||
"Join selected lines into one, smartly fixing up whitespace and trailing commas."
|
||
(interactive)
|
||
(let* ((params (lsp-make-rust-analyzer-join-lines-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:ranges (vector (if (use-region-p)
|
||
(lsp--region-to-range (region-beginning) (region-end))
|
||
(lsp--region-to-range (point) (point))))))
|
||
(result (lsp-send-request (lsp-make-request "experimental/joinLines" params))))
|
||
(lsp--apply-text-edits result 'code-action)))
|
||
|
||
(defun lsp-rust-analyzer-reload-workspace ()
|
||
"Reload workspace, picking up changes from Cargo.toml"
|
||
(interactive)
|
||
(lsp--cur-workspace-check)
|
||
(lsp-send-request (lsp-make-request "rust-analyzer/reloadWorkspace")))
|
||
|
||
(defcustom lsp-rust-analyzer-download-url
|
||
(format "https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/%s"
|
||
(pcase system-type
|
||
('gnu/linux "rust-analyzer-x86_64-unknown-linux-gnu.gz")
|
||
('darwin (if (string-match "^aarch64-.*" system-configuration)
|
||
"rust-analyzer-aarch64-apple-darwin.gz"
|
||
"rust-analyzer-x86_64-apple-darwin.gz"))
|
||
('windows-nt "rust-analyzer-x86_64-pc-windows-msvc.gz")))
|
||
"Automatic download url for Rust Analyzer"
|
||
:type 'string
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(defcustom lsp-rust-analyzer-store-path (f-join lsp-server-install-dir
|
||
"rust"
|
||
(if (eq system-type 'windows-nt)
|
||
"rust-analyzer.exe"
|
||
"rust-analyzer"))
|
||
"The path to the file in which `rust-analyzer' will be stored."
|
||
:type 'file
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
(lsp-dependency
|
||
'rust-analyzer
|
||
`(:download :url lsp-rust-analyzer-download-url
|
||
:decompress :gzip
|
||
:store-path lsp-rust-analyzer-store-path
|
||
:set-executable? t)
|
||
'(:system "rust-analyzer"))
|
||
|
||
(lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?))
|
||
(lsp-rust-analyzer-run (lsp-seq-first arguments?)))
|
||
|
||
(lsp-defun lsp-rust--analyzer-show-references
|
||
((&Command :title :arguments? [_uri _filepos references]))
|
||
(lsp-show-xrefs (lsp--locations-to-xref-items references) nil
|
||
(s-contains-p "reference" title)))
|
||
|
||
(declare-function dap-debug "ext:dap-mode" (template) t)
|
||
|
||
(lsp-defun lsp-rust--analyzer-debug-lens ((&Command :arguments? [args]))
|
||
(lsp-rust-analyzer-debug args))
|
||
|
||
;; Semantic tokens
|
||
|
||
;; Modifier faces
|
||
(defface lsp-rust-analyzer-documentation-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for documentation items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-declaration-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for declaration items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-definition-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for definition items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-static-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for static items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-abstract-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for abstract items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-deprecated-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for deprecated items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-readonly-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for readonly items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-default-library-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for default-library items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-async-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for async items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-attribute-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for attribute items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-callable-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for callable items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-constant-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for constant items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-consuming-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for consuming items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-control-flow-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for control-flow items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-crate-root-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for crate-root items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-injected-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for injected items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-intra-doc-link-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for intra-doc-link items.")
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
|
||
(defface lsp-rust-analyzer-library-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for library items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-mutable-modifier-face
|
||
'((t :underline t))
|
||
"The face modification to use for mutable items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-public-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for public items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-reference-modifier-face
|
||
'((t :bold t))
|
||
"The face modification to use for reference items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-trait-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for trait items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
(defface lsp-rust-analyzer-unsafe-modifier-face
|
||
'((t nil))
|
||
"The face modification to use for unsafe items."
|
||
:group 'lsp-rust-analyzer-semantic-tokens)
|
||
|
||
|
||
;; ---------------------------------------------------------------------
|
||
;; Semantic token modifier face customization
|
||
|
||
(defcustom lsp-rust-analyzer-documentation-modifier 'lsp-rust-analyzer-documentation-modifier-face
|
||
"Face for semantic token modifier for `documentation' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-declaration-modifier 'lsp-rust-analyzer-declaration-modifier-face
|
||
"Face for semantic token modifier for `declaration' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-definition-modifier 'lsp-rust-analyzer-definition-modifier-face
|
||
"Face for semantic token modifier for `definition' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-static-modifier 'lsp-rust-analyzer-static-modifier-face
|
||
"Face for semantic token modifier for `static' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-abstract-modifier 'lsp-rust-analyzer-abstract-modifier-face
|
||
"Face for semantic token modifier for `abstract' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-deprecated-modifier 'lsp-rust-analyzer-deprecated-modifier-face
|
||
"Face for semantic token modifier for `deprecated' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-readonly-modifier 'lsp-rust-analyzer-readonly-modifier-face
|
||
"Face for semantic token modifier for `readonly' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-default-library-modifier 'lsp-rust-analyzer-default-library-modifier-face
|
||
"Face for semantic token modifier for `default' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-async-modifier 'lsp-rust-analyzer-async-modifier-face
|
||
"Face for semantic token modifier for `async' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-attribute-modifier 'lsp-rust-analyzer-attribute-modifier-face
|
||
"Face for semantic token modifier for `attribute' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-callable-modifier 'lsp-rust-analyzer-callable-modifier-face
|
||
"Face for semantic token modifier for `callable' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-constant-modifier 'lsp-rust-analyzer-constant-modifier-face
|
||
"Face for semantic token modifier for `constant' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-consuming-modifier 'lsp-rust-analyzer-consuming-modifier-face
|
||
"Face for semantic token modifier for `consuming' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-control-flow-modifier 'lsp-rust-analyzer-control-flow-modifier-face
|
||
"Face for semantic token modifier for `control_flow' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-crate-root-modifier 'lsp-rust-analyzer-crate-root-modifier-face
|
||
"Face for semantic token modifier for `crate_root' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-injected-modifier 'lsp-rust-analyzer-injected-modifier-face
|
||
"Face for semantic token modifier for `injected' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-intra-doc-link-modifier 'lsp-rust-analyzer-intra-doc-link-modifier-face
|
||
"Face for semantic token modifier for `intra_doc_link' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-library-modifier 'lsp-rust-analyzer-library-modifier-face
|
||
"Face for semantic token modifier for `library' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-mutable-modifier 'lsp-rust-analyzer-mutable-modifier-face
|
||
"Face for semantic token modifier for `mutable' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-public-modifier 'lsp-rust-analyzer-public-modifier-face
|
||
"Face for semantic token modifier for `public' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-reference-modifier 'lsp-rust-analyzer-reference-modifier-face
|
||
"Face for semantic token modifier for `reference' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-trait-modifier 'lsp-rust-analyzer-trait-modifier-face
|
||
"Face for semantic token modifier for `trait' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-unsafe-modifier 'lsp-rust-analyzer-unsafe-modifier-face
|
||
"Face for semantic token modifier for `unsafe' attribute."
|
||
:type 'face
|
||
:group 'lsp-rust-analyzer-semantic-tokens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
;; ---------------------------------------------------------------------
|
||
|
||
|
||
(defun lsp-rust-analyzer--semantic-modifiers ()
|
||
"Mapping between rust-analyzer keywords and fonts to apply.
|
||
The keywords are sent in the initialize response, in the semantic
|
||
tokens legend."
|
||
`(
|
||
("documentation" . ,lsp-rust-analyzer-documentation-modifier)
|
||
("declaration" . ,lsp-rust-analyzer-declaration-modifier)
|
||
("definition" . ,lsp-rust-analyzer-definition-modifier)
|
||
("static" . ,lsp-rust-analyzer-static-modifier)
|
||
("abstract" . ,lsp-rust-analyzer-abstract-modifier)
|
||
("deprecated" . ,lsp-rust-analyzer-deprecated-modifier)
|
||
("readonly" . ,lsp-rust-analyzer-readonly-modifier)
|
||
("default_library" . ,lsp-rust-analyzer-default-library-modifier)
|
||
("async" . ,lsp-rust-analyzer-async-modifier)
|
||
("attribute" . ,lsp-rust-analyzer-attribute-modifier)
|
||
("callable" . ,lsp-rust-analyzer-callable-modifier)
|
||
("constant" . ,lsp-rust-analyzer-constant-modifier)
|
||
("consuming" . ,lsp-rust-analyzer-consuming-modifier)
|
||
("control_flow" . ,lsp-rust-analyzer-control-flow-modifier)
|
||
("crate_root" . ,lsp-rust-analyzer-crate-root-modifier)
|
||
("injected" . ,lsp-rust-analyzer-injected-modifier)
|
||
("intra_doc_link" . ,lsp-rust-analyzer-intra-doc-link-modifier)
|
||
("library" . ,lsp-rust-analyzer-library-modifier)
|
||
("mutable" . ,lsp-rust-analyzer-mutable-modifier)
|
||
("public" . ,lsp-rust-analyzer-public-modifier)
|
||
("reference" . ,lsp-rust-analyzer-reference-modifier)
|
||
("trait" . ,lsp-rust-analyzer-trait-modifier)
|
||
("unsafe" . ,lsp-rust-analyzer-unsafe-modifier)))
|
||
|
||
(lsp-register-client
|
||
(make-lsp-client
|
||
:new-connection (lsp-stdio-connection
|
||
(lambda ()
|
||
`(,(or (executable-find
|
||
(cl-first lsp-rust-analyzer-server-command))
|
||
(lsp-package-path 'rust-analyzer)
|
||
"rust-analyzer")
|
||
,@(cl-rest lsp-rust-analyzer-server-command))))
|
||
:activation-fn (lsp-activate-on "rust")
|
||
:priority (if (eq lsp-rust-server 'rust-analyzer) 1 -1)
|
||
:initialization-options 'lsp-rust-analyzer--make-init-options
|
||
:notification-handlers (ht<-alist lsp-rust-notification-handlers)
|
||
:action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single)
|
||
("rust-analyzer.debugSingle" #'lsp-rust--analyzer-debug-lens)
|
||
("rust-analyzer.showReferences" #'lsp-rust--analyzer-show-references)
|
||
("rust-analyzer.triggerParameterHints" #'lsp--action-trigger-parameter-hints))
|
||
:library-folders-fn (lambda (_workspace) lsp-rust-analyzer-library-directories)
|
||
:semantic-tokens-faces-overrides `(:discard-default-modifiers t
|
||
:modifiers
|
||
,(lsp-rust-analyzer--semantic-modifiers))
|
||
:server-id 'rust-analyzer
|
||
:custom-capabilities `((experimental . ((snippetTextEdit . ,(and lsp-enable-snippet (featurep 'yasnippet))))))
|
||
:download-server-fn (lambda (_client callback error-callback _update?)
|
||
(lsp-package-ensure 'rust-analyzer callback error-callback))))
|
||
|
||
(defun lsp-rust-switch-server (&optional lsp-server)
|
||
"Switch priorities of lsp servers, unless LSP-SERVER is already active."
|
||
(interactive)
|
||
(let ((current-server (if (> (lsp--client-priority (gethash 'rls lsp-clients)) 0)
|
||
'rls
|
||
'rust-analyzer)))
|
||
(unless (eq lsp-server current-server)
|
||
(dolist (server '(rls rust-analyzer))
|
||
(when (natnump (setf (lsp--client-priority (gethash server lsp-clients))
|
||
(* (lsp--client-priority (gethash server lsp-clients)) -1)))
|
||
(message (format "Switched to server %s." server)))))))
|
||
|
||
;; inlay hints
|
||
|
||
(defcustom lsp-rust-analyzer-debug-lens-extra-dap-args
|
||
'(:MIMode "gdb" :miDebuggerPath "gdb" :stopAtEntry t :externalConsole :json-false)
|
||
"Extra arguments to pass to DAP template when debugging a test from code lens.
|
||
|
||
As a rule of the thumb, do not add extra keys to this plist unless you exactly
|
||
what you are doing, it might break the \"Debug test\" lens otherwise.
|
||
|
||
See dap-mode documentation and cpptools documentation for the extra variables
|
||
meaning."
|
||
:type 'plist
|
||
:group 'lsp-rust-analyzer
|
||
:package-version '(lsp-mode . "8.0.0"))
|
||
|
||
;; lenses
|
||
|
||
(defgroup lsp-rust-analyzer-lens nil
|
||
"LSP lens support for Rust when using rust-analyzer.
|
||
|
||
Lenses are (depending on your configuration) clickable links to
|
||
the right of function definitions and the like. These display
|
||
some useful information in their own right and/or perform a
|
||
shortcut action when clicked such as displaying uses of that
|
||
function or running an individual test.
|
||
"
|
||
:prefix "lsp-rust-analyzer-lens-"
|
||
:group 'lsp-rust-analyzer
|
||
:link '(url-link "https://emacs-lsp.github.io/lsp-mode/")
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-debug-enable t
|
||
"Enable or disable the Debug lens."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-enable t
|
||
"Master-enable of lenses in Rust files."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
;; This customisation "works" in that it works as described, but the default is fine and changing it
|
||
;; from the default will either stop lenses working or do nothing.
|
||
;;
|
||
;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun
|
||
;; lsp-rust-analyzer--make-init-options too or it'll not do anything.
|
||
|
||
;; (defcustom lsp-rust-analyzer-lens-force-custom-commands t
|
||
;; "Internal config: use custom client-side commands even when the
|
||
;; client doesn't set the corresponding capability."
|
||
;; :type 'boolean
|
||
;; :group 'lsp-rust-analyzer-lens
|
||
;; :package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-implementations-enable t
|
||
"Enable or disable the Implementations lens.
|
||
|
||
The Implementations lens shows `NN implementations' to the right
|
||
of the first line of an enum, struct, or union declaration. This
|
||
is the count of impl blocks, including derived traits. Clicking
|
||
on it gives a list of the impls of that type.
|
||
"
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
;; The valid range of values for this is documented in the rust-lang/rust-analyzer repository at the
|
||
;; path "editors/code/package.json"; the TL:DR is that it's "above_name" or "above_whole_item".
|
||
;; However, setting it to "above_whole_item" causes lenses to disappear in Emacs. I suspect this
|
||
;; feature has only ever been tested in some other IDE and it's broken in Emacs. So I've disabled it
|
||
;; for now.
|
||
;;
|
||
;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun
|
||
;; lsp-rust-analyzer--make-init-options too or it'll not do anything.
|
||
|
||
;; (defcustom lsp-rust-analyzer-lens-location "above_name"
|
||
;; "Where to render annotations."
|
||
;; :type '(choice
|
||
;; (const :tag "Above name" "above_name")
|
||
;; (const :tag "Above whole item" "above_whole_item")
|
||
;; :group 'lsp-rust-analyzer-lens
|
||
;; :package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-references-adt-enable nil
|
||
"Enable or disable the References lens on enums, structs, and traits.
|
||
|
||
The References lens shows `NN references` to the right of the
|
||
first line of each enum, struct, or union declaration. This is
|
||
the count of uses of that type. Clicking on it gives a list of
|
||
where that type is used."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-references-enum-variant-enable nil
|
||
"Enable or disable the References lens on enum variants.
|
||
|
||
The References lens shows `NN references` to the right of the
|
||
first (or only) line of each enum variant. This is the count of
|
||
uses of that enum variant. Clicking on it gives a list of where
|
||
that enum variant is used."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-references-method-enable nil
|
||
"Enable or disable the References lens on functions.
|
||
|
||
The References lens shows `NN references` to the right of the
|
||
first line of each function declaration. This is the count of
|
||
uses of that function. Clicking on it gives a list of where that
|
||
function is used."
|
||
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-references-trait-enable nil
|
||
"Enable or disable the References lens on traits.
|
||
|
||
The References lens shows `NN references` to the right of the
|
||
first line of each trait declaration. This is a count of uses of
|
||
that trait. Clicking on it gives a list of where that trait is
|
||
used.
|
||
|
||
There is some overlap with the Implementations lens which slows
|
||
all of the trait's impl blocks, but this also shows other uses
|
||
such as imports and dyn traits."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defcustom lsp-rust-analyzer-lens-run-enable t
|
||
"Enable or disable the Run lens."
|
||
:type 'boolean
|
||
:group 'lsp-rust-analyzer-lens
|
||
:package-version '(lsp-mode . "8.0.1"))
|
||
|
||
(defun lsp-rust-analyzer-initialized? ()
|
||
(when-let ((workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name))))
|
||
(eq 'initialized (lsp--workspace-status workspace))))
|
||
|
||
(defun lsp-rust-analyzer-expand-macro ()
|
||
"Expands the macro call at point recursively."
|
||
(interactive)
|
||
(-if-let* ((params (lsp-make-rust-analyzer-expand-macro-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:position (lsp--cur-position)))
|
||
(response (lsp-request
|
||
"rust-analyzer/expandMacro"
|
||
params))
|
||
((&rust-analyzer:ExpandedMacro :expansion) response))
|
||
(funcall lsp-rust-analyzer-macro-expansion-method expansion)
|
||
(lsp--error "No macro found at point, or it could not be expanded.")))
|
||
|
||
(defun lsp-rust-analyzer-macro-expansion-default (result)
|
||
"Default method for displaying macro expansion."
|
||
(let* ((root (lsp-workspace-root default-directory))
|
||
(buf (get-buffer-create (get-buffer-create (format "*rust-analyzer macro expansion %s*" root)))))
|
||
(with-current-buffer buf
|
||
(let ((inhibit-read-only t))
|
||
(erase-buffer)
|
||
(insert (lsp--render-string result "rust"))
|
||
(special-mode)))
|
||
(pop-to-buffer buf)))
|
||
|
||
;; runnables
|
||
(defvar lsp-rust-analyzer--last-runnable nil)
|
||
|
||
(defun lsp-rust-analyzer--runnables ()
|
||
(lsp-send-request (lsp-make-request
|
||
"experimental/runnables"
|
||
(lsp-make-rust-analyzer-runnables-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:position? (lsp--cur-position)))))
|
||
|
||
(defun lsp-rust-analyzer--select-runnable ()
|
||
(lsp--completing-read
|
||
"Select runnable:"
|
||
(if lsp-rust-analyzer--last-runnable
|
||
(cons lsp-rust-analyzer--last-runnable
|
||
(-remove (-lambda ((&rust-analyzer:Runnable :label))
|
||
(equal label (lsp-get lsp-rust-analyzer--last-runnable :label)))
|
||
(lsp-rust-analyzer--runnables)))
|
||
(lsp-rust-analyzer--runnables))
|
||
(-lambda ((&rust-analyzer:Runnable :label)) label)))
|
||
|
||
|
||
(defun lsp-rust-analyzer--common-runner (runnable)
|
||
"Execute a given RUNNABLE.
|
||
|
||
Extract the arguments, prepare the minor mode (cargo-process-mode if possible)
|
||
and run a compilation"
|
||
(-let* (((&rust-analyzer:Runnable :kind :label :args) runnable)
|
||
((&rust-analyzer:RunnableArgs :cargo-args :executable-args :workspace-root? :expect-test?) args)
|
||
(default-directory (or workspace-root? default-directory)))
|
||
(if (not (string-equal kind "cargo"))
|
||
(lsp--error "'%s' runnable is not supported" kind)
|
||
(compilation-start
|
||
(string-join (append (when expect-test? '("env" "UPDATE_EXPECT=1"))
|
||
(list "cargo") cargo-args
|
||
(when executable-args '("--")) executable-args '()) " ")
|
||
|
||
;; cargo-process-mode is nice, but try to work without it...
|
||
(if (functionp 'cargo-process-mode) 'cargo-process-mode nil)
|
||
(lambda (_) (concat "*" label "*"))))))
|
||
|
||
|
||
(defun lsp-rust-analyzer-run (runnable)
|
||
"Select and run a RUNNABLE action."
|
||
(interactive (list (lsp-rust-analyzer--select-runnable)))
|
||
(when (lsp-rust-analyzer--common-runner runnable)
|
||
(setq lsp-rust-analyzer--last-runnable runnable)))
|
||
|
||
(defun lsp-rust-analyzer-debug (runnable)
|
||
"Select and debug a RUNNABLE action."
|
||
(interactive (list (lsp-rust-analyzer--select-runnable)))
|
||
(unless (featurep 'dap-cpptools)
|
||
(user-error "You must require `dap-cpptools'"))
|
||
(-let (((&rust-analyzer:Runnable
|
||
:args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args)
|
||
:label) runnable))
|
||
(pcase (aref cargo-args 0)
|
||
("run" (aset cargo-args 0 "build"))
|
||
("test" (when (-contains? (append cargo-args ()) "--no-run")
|
||
(cl-callf append cargo-args (list "--no-run")))))
|
||
(->> (append (list (executable-find "cargo"))
|
||
cargo-args
|
||
(list "--message-format=json"))
|
||
(s-join " ")
|
||
(shell-command-to-string)
|
||
(s-lines)
|
||
(-keep (lambda (s)
|
||
(condition-case nil
|
||
(-let* ((json-object-type 'plist)
|
||
((msg &as &plist :reason :executable) (json-read-from-string s)))
|
||
(when (and executable (string= "compiler-artifact" reason))
|
||
executable))
|
||
(error))))
|
||
(funcall
|
||
(lambda (artifact-spec)
|
||
(pcase artifact-spec
|
||
(`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed"))
|
||
(`(,spec) spec)
|
||
(_ (user-error "Multiple compilation artifacts are not supported")))))
|
||
(list :type "cppdbg"
|
||
:request "launch"
|
||
:name label
|
||
:args executable-args
|
||
:cwd workspace-root?
|
||
:sourceLanguages ["rust"]
|
||
:program)
|
||
(append lsp-rust-analyzer-debug-lens-extra-dap-args)
|
||
(dap-debug))))
|
||
|
||
(defun lsp-rust-analyzer-rerun (&optional runnable)
|
||
(interactive (list (or lsp-rust-analyzer--last-runnable
|
||
(lsp-rust-analyzer--select-runnable))))
|
||
(lsp-rust-analyzer-run (or runnable lsp-rust-analyzer--last-runnable)))
|
||
|
||
;; goto parent module
|
||
(cl-defun lsp-rust-find-parent-module (&key display-action)
|
||
"Find parent module of current module."
|
||
(interactive)
|
||
(lsp-find-locations "experimental/parentModule" nil :display-action display-action))
|
||
|
||
(defun lsp-rust-analyzer-open-cargo-toml (&optional new-window)
|
||
"Open the closest Cargo.toml from the current file.
|
||
|
||
Rust-Analyzer LSP protocol documented here and added in November 2020
|
||
https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-cargotoml
|
||
|
||
If NEW-WINDOW (interactively the prefix argument) is non-nil,
|
||
open in a new window."
|
||
(interactive "P")
|
||
(-if-let (workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name)))
|
||
(-if-let* ((response (with-lsp-workspace workspace
|
||
(lsp-send-request (lsp-make-request
|
||
"experimental/openCargoToml"
|
||
(lsp-make-rust-analyzer-open-cargo-toml-params
|
||
:text-document (lsp--text-document-identifier))))))
|
||
((&Location :uri :range) response))
|
||
(funcall (if new-window #'find-file-other-window #'find-file)
|
||
(lsp--uri-to-path uri))
|
||
(lsp--warn "Couldn't find a Cargo.toml file or your version of rust-analyzer doesn't support this extension"))
|
||
(lsp--error "OpenCargoToml is an extension available only with rust-analyzer")))
|
||
|
||
(defun lsp-rust-analyzer-open-external-docs ()
|
||
"Open a URL for documentation related to the current TextDocumentPosition.
|
||
|
||
Rust-Analyzer LSP protocol documented here
|
||
https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-external-documentation"
|
||
(interactive)
|
||
(-if-let* ((params (lsp-make-rust-analyzer-open-external-docs-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:position (lsp--cur-position)))
|
||
(url (lsp-request "experimental/externalDocs" params)))
|
||
(browse-url url)
|
||
(lsp--warn "Couldn't find documentation URL or your version of rust-analyzer doesn't support this extension")))
|
||
|
||
(defun lsp-rust-analyzer--related-tests ()
|
||
"Get runnable test items related to the current TextDocumentPosition.
|
||
Calls a rust-analyzer LSP extension endpoint that returns a wrapper over
|
||
Runnable[]."
|
||
(lsp-send-request (lsp-make-request
|
||
"rust-analyzer/relatedTests"
|
||
(lsp--text-document-position-params))))
|
||
|
||
(defun lsp-rust-analyzer--select-related-test ()
|
||
"Call the endpoint and ask for user selection.
|
||
|
||
Cannot reuse `lsp-rust-analyzer--select-runnable' because the runnables endpoint
|
||
responds with Runnable[], while relatedTests responds with TestInfo[],
|
||
which is a wrapper over runnable. Also, this method doesn't set
|
||
the `lsp-rust-analyzer--last-runnable' variable."
|
||
(-if-let* ((resp (lsp-rust-analyzer--related-tests))
|
||
(runnables (seq-map
|
||
#'lsp:rust-analyzer-related-tests-runnable
|
||
resp)))
|
||
(lsp--completing-read
|
||
"Select test: "
|
||
runnables
|
||
#'lsp:rust-analyzer-runnable-label)))
|
||
|
||
(defun lsp-rust-analyzer-related-tests (runnable)
|
||
"Execute a RUNNABLE test related to the current document position.
|
||
|
||
Rust-Analyzer LSP protocol extension
|
||
https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#related-tests"
|
||
(interactive (list (lsp-rust-analyzer--select-related-test)))
|
||
(if runnable
|
||
(lsp-rust-analyzer--common-runner runnable)
|
||
(lsp--info "There are no tests related to the symbol at point")))
|
||
|
||
(defun lsp-rust-analyzer-move-item (direction)
|
||
"Move item under cursor or selection in some DIRECTION"
|
||
(let* ((params (lsp-make-rust-analyzer-move-item-params
|
||
:text-document (lsp--text-document-identifier)
|
||
:range (if (use-region-p)
|
||
(lsp--region-to-range (region-beginning) (region-end))
|
||
(lsp--region-to-range (point) (point)))
|
||
:direction direction))
|
||
(edits (lsp-request "experimental/moveItem" params)))
|
||
(lsp--apply-text-edits edits 'code-action)))
|
||
|
||
(defun lsp-rust-analyzer-move-item-up ()
|
||
"Move item under cursor or selection up"
|
||
(interactive)
|
||
(lsp-rust-analyzer-move-item "Up"))
|
||
|
||
(defun lsp-rust-analyzer-move-item-down ()
|
||
"Move item under cursor or selection down"
|
||
(interactive)
|
||
(lsp-rust-analyzer-move-item "Down"))
|
||
|
||
(lsp-consistency-check lsp-rust)
|
||
|
||
(provide 'lsp-rust)
|
||
;;; lsp-rust.el ends here
|