分享:在eglot中执行LSP Server支持的command

有部分LSP服务器需要额外进行 :workspace/executeCommand ,比如 metals 就需要执行 build-import 等,lsp-metals 内置了对这些命令的支持:

这里我在 eglot 上包装了一下,使其能够选择需要执行的命令:

  (defun my/eglot-enable-command-provider (orig-fn server)
    "Unconditionally add :executeCommandProvider to Eglot client capabilities."
    (let ((original-capabilities (funcall orig-fn server)))
      ;; Add or update :executeCommandProvider at the top level
      (plist-put original-capabilities
                 :executeCommandProvider '(:commands (:dynamicRegistration :json-false)))))
  (advice-add 'eglot-client-capabilities :around #'my/eglot-enable-command-provider)

  (defun my/eglot-execute-command (command)
    "Interactively execute a COMMAND supported by the current Eglot LSP server.
COMMAND is a string as advertised by the server. No arguments are passed."
    (interactive
     (let* ((server (eglot-current-server))
            (caps (eglot--capabilities server))
            (provider (plist-get caps :executeCommandProvider))
            (commands (and provider (plist-get provider :commands))))
       (list (completing-read "LSP Command: "
                              (or (cl-coerce commands 'list) '())
                              nil nil))))
    (eglot-execute (eglot-current-server) (list :command command)))

注意:这个函数是同步执行的,而且只支持无参命令,有参命令可以自行修改

使用效果如下:

7 个赞

查找引用(references)是一个非常重要的功能,但是 eglot/xref 默认没有绑定按键,所以我把这两个功能合在了一起,从而可以一键选择跳转到定义或者引用。

这里只在后端为 eglot 启用的情况下绑定,因为在有些后端上启用会导致噪声太多:

  (defun my/xref-combined-defs-and-refs (identifier)
    "Show both definitions and references of IDENTIFIER in the minibuffer.
This combines `xref-find-definitions' and `xref-find-references'
into a single unified list using the current xref backend."
    (interactive
     (list (xref--read-identifier "Identifier: ")))
    (let* ((backend (xref-find-backend)) ;; Detect current xref backend (e.g. eglot, lsp-mode, etags)
           (defs (condition-case nil
                     (xref-backend-definitions backend identifier)
                   (error nil)))
           (refs (condition-case nil
                     (xref-backend-references backend identifier)
                   (error nil)))
           (xrefs (append defs refs)))
      (if xrefs
          (xref--show-xrefs xrefs nil)
        (message "No definitions or references found."))))

(with-eval-after-load 'eglot
  (define-key eglot-mode-map (kbd "M-.") #'my/xref-combined-defs-and-refs))

效果如下:

对比 xref-find-references

PS: definition 在这个列表中也是有的,但是位置不确定。

3 个赞