From 2482d7b317d04b483868321e518c7845d48b3a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= Date: Sat, 5 Mar 2022 15:50:47 +0100 Subject: [PATCH] Calculate possible code-actions kinds dynamically I thought the server must reply with a subset of the client's list of codeActionKind during the initialization. But it's clearly not the case. The typescript-language-server returns these [1]: ["source.fixAll.ts" "source.removeUnused.ts" "source.addMissingImports.ts" ...] The clangd server returns these [2]: ["quickfix" "refactor" "info"] (Additionally, in the current code there is a mismatch between what Eglot initially sent and the completing read arguemnt of eglot-code-actions. "source" and "refactor" is missing from `eglot-code-actions'. Was this intentional?) Now, Eglot plays safe, and offers the union of the two lists as possible completions in `eglot-code-actions'. [1]: https://github.com/joaotavora/eglot/issues/847#issuecomment-1059760171 [2]: https://github.com/joaotavora/eglot/issues/860 --- eglot.el | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/eglot.el b/eglot.el index 5b4d4196..86be12c5 100644 --- a/eglot.el +++ b/eglot.el @@ -644,7 +644,7 @@ treated as in `eglot-dbind'." (cl-defgeneric eglot-client-capabilities (server) "What the EGLOT LSP client supports for SERVER." - (:method (_s) + (:method (server) (list :workspace (list :applyEdit t @@ -696,12 +696,9 @@ treated as in `eglot-dbind'." :codeAction (list :dynamicRegistration :json-false :codeActionLiteralSupport - '(:codeActionKind - (:valueSet - ["quickfix" - "refactor" "refactor.extract" - "refactor.inline" "refactor.rewrite" - "source" "source.organizeImports"])) + `(:codeActionKind + ,`(:valueSet + ,(vconcat (eglot--code-action-kinds server)))) :isPreferredSupport t) :formatting `(:dynamicRegistration :json-false) :rangeFormatting `(:dynamicRegistration :json-false) @@ -758,7 +755,10 @@ treated as in `eglot-dbind'." :accessor eglot--saved-initargs) (inferior-process :documentation "Server subprocess started automatically." - :accessor eglot--inferior-process)) + :accessor eglot--inferior-process) + (code-action-kinds + :documentation "List of code-actions the client can request." + :accessor eglot--code-action-kinds)) :documentation "Represents a server. Wraps a process for LSP communication.") @@ -1138,6 +1138,9 @@ This docstring appeases checkdoc, that's all." (setf (eglot--major-mode server) managed-major-mode) (setf (eglot--language-id server) language-id) (setf (eglot--inferior-process server) autostart-inferior-process) + (setf (eglot--code-action-kinds server) + '("quickfix" "refactor" "refactor.extract" "refactor.inline" + "refactor.rewrite" "source" "source.organizeImports")) (run-hook-with-args 'eglot-server-initialized-hook server) ;; Now start the handshake. To honour `eglot-sync-connect' ;; maybe-sync-maybe-async semantics we use `jsonrpc-async-request' @@ -1170,6 +1173,14 @@ This docstring appeases checkdoc, that's all." (gethash project eglot--servers-by-project)) (setf (eglot--capabilities server) capabilities) (setf (eglot--server-info server) serverInfo) + (setf (eglot--code-action-kinds server) + (cl-remove-duplicates + (append + (plist-get + (plist-get capabilities :codeActionProvider) + :codeActionKinds) + (eglot--code-action-kinds server)) + :test 'equal)) (jsonrpc-notify server :initialized eglot--{}) (dolist (buffer (buffer-list)) (with-current-buffer buffer @@ -2829,9 +2840,9 @@ at point. With prefix argument, prompt for ACTION-KIND." (interactive `(,@(eglot--region-bounds) ,(and current-prefix-arg - (completing-read "[eglot] Action kind: " - '("quickfix" "refactor.extract" "refactor.inline" - "refactor.rewrite" "source.organizeImports"))))) + (completing-read + "[eglot] Action kind: " + (eglot--code-action-kinds (eglot--current-server-or-lose)))))) (unless (eglot--server-capable :codeActionProvider) (eglot--error "Server can't execute code actions!")) (let* ((server (eglot--current-server-or-lose))