From 53c7a2b96391a83fd452152eaf8caf37d6a4987b Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Tue, 3 Nov 2020 22:00:30 +0100 Subject: [PATCH 01/10] lsp-rust: support rust-analyzer.showReference lens Add a rust-analyzer specific :action-handler for the showReference lens, which leverages `lsp-show-xrefs'. Refactor: eliminate `lsp-execute-command', because it caused the :title to be lost, which is needed to distinguish between the "references" or "implementations" variants of that lens. Defining a new `lsp-interface' to destructure "rust-analyzer.showReference" was impossible, as the former doesn't support destructuring lists (the :arguments? paramter is a special, 3-element list.). --- clients/lsp-rust.el | 12 ++++++++++-- lsp-lens.el | 4 +--- lsp-mode.el | 5 +---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/clients/lsp-rust.el b/clients/lsp-rust.el index 29a88ee730c..760994325e8 100644 --- a/clients/lsp-rust.el +++ b/clients/lsp-rust.el @@ -295,7 +295,7 @@ PARAMS progress report notification data." (lsp-workspace-status nil workspace) (lsp-workspace-status (format "%s - %s" title (or message? "")) workspace)))) -(cl-defmethod lsp-execute-command (_server (_command (eql rls.run)) params) +(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 @@ -635,6 +635,13 @@ them with `crate` or the crate name they refer to." (lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?)) (lsp-rust-analyzer-run (lsp-seq-first arguments?))) +;; `lsp-interface' is unsuitable for ShowReference destructuring, as that code +;; action yields an array of three elements, not a map. +(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))) + (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection @@ -648,7 +655,8 @@ them with `crate` or the crate name they refer to." :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)) + :action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single) + ("rust-analyzer.showReferences" #'lsp-rust--analyzer-show-references)) :library-folders-fn (lambda (_workspace) lsp-rust-library-directories) :after-open-fn (lambda () (when lsp-rust-analyzer-server-display-inlay-hints diff --git a/lsp-lens.el b/lsp-lens.el index 16d5fa2a91c..925b63b971d 100644 --- a/lsp-lens.el +++ b/lsp-lens.el @@ -154,9 +154,7 @@ See `lsp-lens--schedule-refresh' for details." (lsp:command-command command?) (lambda () (interactive) - (lsp-execute-command server-id - (intern (lsp:command-command command?)) - (lsp:command-arguments? command?)))))) + (lsp--execute-command command?))))) (defun lsp-lens--display (lenses) "Show LENSES." diff --git a/lsp-mode.el b/lsp-mode.el index e2859f3c083..418935ba9f2 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -968,9 +968,6 @@ calling `remove-overlays'.") (defvar-local lsp--virtual-buffer-point-max nil) -(cl-defgeneric lsp-execute-command (server command arguments) - "Ask SERVER to execute COMMAND with ARGUMENTS.") - (defun lsp-elt (sequence n) "Return Nth element of SEQUENCE or nil if N is out of range." (cond @@ -5740,7 +5737,7 @@ REFERENCES? t when METHOD returns references." (lsp-request "workspace/executeCommand" params))) (defun lsp--send-execute-command (command &optional args) - "Execute workspace COMMAND with ARGS showing error if command is not mapped client-side." + "Create and send a 'workspace/executeCommand' message having command COMMAND and optional ARGS." (condition-case-unless-debug err (lsp-workspace-command-execute command args) (error From dd4d5b7bd41dc594eabf6180e5d4ab710fd3d709 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Tue, 3 Nov 2020 22:09:29 +0100 Subject: [PATCH 02/10] lsp-lens.el: fix byte-compile warnings --- lsp-lens.el | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lsp-lens.el b/lsp-lens.el index 925b63b971d..b27da6b81ae 100644 --- a/lsp-lens.el +++ b/lsp-lens.el @@ -145,16 +145,11 @@ See `lsp-lens--schedule-refresh' for details." (defun lsp-lens--create-interactive-command (command?) "Create an interactive COMMAND? for the lens." - (let ((server-id (->> (lsp-workspaces) - (cl-first) - (or lsp--cur-workspace) - (lsp--workspace-client) - (lsp--client-server-id)))) - (if (functionp (lsp:command-command command?)) - (lsp:command-command command?) - (lambda () - (interactive) - (lsp--execute-command command?))))) + (if (functionp (lsp:command-command command?)) + (lsp:command-command command?) + (lambda () + (interactive) + (lsp--execute-command command?)))) (defun lsp-lens--display (lenses) "Show LENSES." From 1767902606f433cbd3a9fd98c4b3285df13724f1 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 7 Nov 2020 21:44:44 +0100 Subject: [PATCH 03/10] Restore `lsp-execute-command' as an obsolete defun Its original function, being a `cl-defgeneric' that can be overriden per language server is gone; however, PRs were provided to eliminate all uses of it in that context. To remain backwards-compatible, it will still remain as an obsolete `defun' that calls `lsp--execute-command' internally. --- lsp-mode.el | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lsp-mode.el b/lsp-mode.el index 418935ba9f2..db368ab92cc 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -5209,6 +5209,16 @@ It will filter by KIND if non nil." (funcall action-handler action) (lsp--send-execute-command command arguments?))) +(defun lsp-execute-command (_ command arguments) + "Execute code action COMMAND with ARGUMENTS?. +Note that this function can now longer be overloaded using +`cl-defmethod', because that proved to be a liability. Use the +:action-handlers argument of `make-lsp-client' instead." + (lsp--execute-command + (lsp-make-command :command (symbol-name command) + :arguments? arguments))) +(make-obsolete #'lsp-execute-command #'lsp--execute-command "7.1.0") + (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?)) "Execute code action ACTION. If ACTION is not set it will be selected from `lsp-code-actions-at-point'. From 00a1a58816f02bb0c245cfcae51be8a2eab8fb89 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 7 Nov 2020 22:38:17 +0100 Subject: [PATCH 04/10] Fix byte-compile --- lsp-mode.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lsp-mode.el b/lsp-mode.el index db368ab92cc..0d8a62c227a 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -5209,7 +5209,7 @@ It will filter by KIND if non nil." (funcall action-handler action) (lsp--send-execute-command command arguments?))) -(defun lsp-execute-command (_ command arguments) +(defun lsp-execute-command (_server command arguments) "Execute code action COMMAND with ARGUMENTS?. Note that this function can now longer be overloaded using `cl-defmethod', because that proved to be a liability. Use the @@ -5217,7 +5217,8 @@ Note that this function can now longer be overloaded using (lsp--execute-command (lsp-make-command :command (symbol-name command) :arguments? arguments))) -(make-obsolete #'lsp-execute-command #'lsp--execute-command "7.1.0") +(make-obsolete 'lsp-execute-command "use `lsp--execute-command' instead." + "7.1.0") (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?)) "Execute code action ACTION. From 4e766bcdb49b71a2d4cfe7d9b018477bdd8d271f Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Fri, 20 Nov 2020 11:36:55 +0100 Subject: [PATCH 05/10] Remove `lsp-execute-command' as an obsolete defun Since it wouldn't do what it did previously (being an extension point), restoring that function doesn't actually improve backwards compatibility. Reverts 957a0567. --- lsp-mode.el | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lsp-mode.el b/lsp-mode.el index 0d8a62c227a..418935ba9f2 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -5209,17 +5209,6 @@ It will filter by KIND if non nil." (funcall action-handler action) (lsp--send-execute-command command arguments?))) -(defun lsp-execute-command (_server command arguments) - "Execute code action COMMAND with ARGUMENTS?. -Note that this function can now longer be overloaded using -`cl-defmethod', because that proved to be a liability. Use the -:action-handlers argument of `make-lsp-client' instead." - (lsp--execute-command - (lsp-make-command :command (symbol-name command) - :arguments? arguments))) -(make-obsolete 'lsp-execute-command "use `lsp--execute-command' instead." - "7.1.0") - (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?)) "Execute code action ACTION. If ACTION is not set it will be selected from `lsp-code-actions-at-point'. From dddb1621843bbc627d1d71106bfb7cd46200c4df Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Fri, 20 Nov 2020 11:56:13 +0100 Subject: [PATCH 06/10] Support `lsp-execute-command' `lsp-execute-command' now works as an extension point again, but a deprecation warning is shown if it is used to handle a command. To implement this, leverage `cl-no-applicable-method': call `lsp-execute-command' first, and then, if there is no implementation, go trough the handler hash tables as usual. --- lsp-mode.el | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lsp-mode.el b/lsp-mode.el index 418935ba9f2..f35a21d7b0e 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -968,6 +968,9 @@ calling `remove-overlays'.") (defvar-local lsp--virtual-buffer-point-max nil) +(cl-defgeneric lsp-execute-command (server command arguments) + "Ask SERVER to execute COMMAND with ARGUMENTS.") + (defun lsp-elt (sequence n) "Return Nth element of SEQUENCE or nil if N is out of range." (cond @@ -5205,9 +5208,18 @@ It will filter by KIND if non nil." (lsp-defun lsp--execute-command ((action &as &Command :command :arguments?)) "Parse and execute a code ACTION represented as a Command LSP type." - (-if-let* ((action-handler (lsp--find-action-handler command))) - (funcall action-handler action) - (lsp--send-execute-command command arguments?))) + (let ((server-id (->> (lsp-workspaces) + (cl-first) + (or lsp--cur-workspace) + (lsp--workspace-client) + (lsp--client-server-id)))) + (condition-case nil + (prog1 (lsp-execute-command server-id (intern command) arguments?) + (lsp--warn "`lsp-execute-command' is deprecated")) + (cl-no-applicable-method + (if-let ((action-handler (lsp--find-action-handler command))) + (funcall action-handler action) + (lsp--send-execute-command command arguments?)))))) (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?)) "Execute code action ACTION. From 84fadc59ddb32310c72ada26d4e4513d9d964b57 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 21 Nov 2020 18:05:29 +0100 Subject: [PATCH 07/10] `lsp-execute-command': use `make-obsolete' The proper way to mark a function as deprecated is to use `make-obsolete'; use that instead of `lsp--warn'. --- lsp-mode.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lsp-mode.el b/lsp-mode.el index f35a21d7b0e..948e8709d53 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -969,7 +969,8 @@ calling `remove-overlays'.") (defvar-local lsp--virtual-buffer-point-max nil) (cl-defgeneric lsp-execute-command (server command arguments) - "Ask SERVER to execute COMMAND with ARGUMENTS.") + "Ask SERVER to execute COMMAND with ARGUMENTS." + (declare (obsolete "use `make-lsp-client' with :action-handlers instead." "7.1.0"))) (defun lsp-elt (sequence n) "Return Nth element of SEQUENCE or nil if N is out of range." @@ -5214,8 +5215,7 @@ It will filter by KIND if non nil." (lsp--workspace-client) (lsp--client-server-id)))) (condition-case nil - (prog1 (lsp-execute-command server-id (intern command) arguments?) - (lsp--warn "`lsp-execute-command' is deprecated")) + (lsp-execute-command server-id (intern command) arguments?) (cl-no-applicable-method (if-let ((action-handler (lsp--find-action-handler command))) (funcall action-handler action) From d9a17fa99a409bbfe07d11a06337aa777a064739 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 21 Nov 2020 18:17:55 +0100 Subject: [PATCH 08/10] lsp-rust: remove redundant `lsp-interface' comment `lsp-interface' wasn't designed to destructure lists; stating that fact before `lsp-rust--analyzer-show-references' is as such redundant, since that is normal and not noteworthy. --- clients/lsp-rust.el | 2 -- 1 file changed, 2 deletions(-) diff --git a/clients/lsp-rust.el b/clients/lsp-rust.el index 760994325e8..7ff04f8f982 100644 --- a/clients/lsp-rust.el +++ b/clients/lsp-rust.el @@ -635,8 +635,6 @@ them with `crate` or the crate name they refer to." (lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?)) (lsp-rust-analyzer-run (lsp-seq-first arguments?))) -;; `lsp-interface' is unsuitable for ShowReference destructuring, as that code -;; action yields an array of three elements, not a map. (lsp-defun lsp-rust--analyzer-show-references ((&Command :title :arguments? [_uri _filepos references])) (lsp-show-xrefs (lsp--locations-to-xref-items references) nil From 1c0c2b87570116367b64caf74299f5c2674fea26 Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 28 Nov 2020 21:40:01 +0100 Subject: [PATCH 09/10] `lsp-lens--create-interactive-command': non-nil The COMMAND? argument of that function mustn't be nil, which is unclear from its name (?). Note that fact in its docstring. The name of that argument is still good though, because it refers to a field name in `CodeAction' and `CodeLens'. Based on a discussion with @kiennq. --- lsp-lens.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lsp-lens.el b/lsp-lens.el index b27da6b81ae..f1c0299f7ff 100644 --- a/lsp-lens.el +++ b/lsp-lens.el @@ -144,7 +144,9 @@ See `lsp-lens--schedule-refresh' for details." (define-key [mouse-1] (lsp-lens--create-interactive-command command)))) (defun lsp-lens--create-interactive-command (command?) - "Create an interactive COMMAND? for the lens." + "Create an interactive COMMAND? for the lens. +COMMAND? shall be an `&Command' (e.g. `&CodeLens' :command?) and +mustn't be nil." (if (functionp (lsp:command-command command?)) (lsp:command-command command?) (lambda () From 19bdc11ca61ab02b32e9d3b189658635d3f3d21f Mon Sep 17 00:00:00 2001 From: Nikita Bloshchanevich Date: Sat, 28 Nov 2020 21:51:06 +0100 Subject: [PATCH 10/10] Fix `byte-compile': `lsp-execute-command' Unlike previously assumed, calling `lsp-execute-command' causes byte-compile warnings, not just using it in `cl-defmethod'. Wrap the call in `with-no-warnings', since that should be the only use of that function. --- lsp-mode.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lsp-mode.el b/lsp-mode.el index 948e8709d53..91057d9d160 100755 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -5215,7 +5215,8 @@ It will filter by KIND if non nil." (lsp--workspace-client) (lsp--client-server-id)))) (condition-case nil - (lsp-execute-command server-id (intern command) arguments?) + (with-no-warnings + (lsp-execute-command server-id (intern command) arguments?)) (cl-no-applicable-method (if-let ((action-handler (lsp--find-action-handler command))) (funcall action-handler action)