Eglot: add M-x eglot-describe-connection

Also add more bindings to M-x eglot-list-connections

* lisp/progmodes/eglot.el (eglot-list-connections-mode-map): Add
bindings for e, w, RET.
(eglot-events-buffer-of-listed-connection)
(eglot-show-workspace-configuration-of-listed-connection)
(eglot-describe-listed-connection): New commands.
(eglot-describe-connection): New command.

* doc/misc/eglot.texi: Document new keys and eglot-describe-connection.

* etc/EGLOT-NEWS: Announce.
This commit is contained in:
João Távora
2026-04-17 00:18:31 +01:00
parent f6bb77270f
commit cbbe2b5f55
3 changed files with 144 additions and 8 deletions

View File

@@ -713,12 +713,19 @@ Emacs session. As with @code{eglot-shutdown}, invoking this command
with a prefix argument avoids killing the buffers used for
communications with the language servers.
@item M-x eglot-describe-connection
This command pops up a detailed description buffer for the current
connection, outlining aspects such as the LSP server name and version,
the project name and root path, among others.
@item M-x eglot-list-connections
This command pops up a buffer listing all active Eglot connections,
showing aspects such as the server name, project, number of managed
buffers, major modes, and the server invocation. In this buffer,
@kbd{k} shuts down the server on the current line and @kbd{r}
reconnects to it.
@kbd{k} shuts down the server on the current line, @kbd{r} reconnects
to it, @kbd{e} visits its events buffer, @kbd{w} shows its workspace
configuration, and @kbd{RET} describes the connection with
@code{eglot-describe-connection}.
@item M-x eglot-rename
This command renames the program symbol (a.k.a.@: @dfn{identifier}) at

View File

@@ -20,9 +20,17 @@ https://github.com/joaotavora/eglot/issues/1234.
* Changes to upcoming Eglot
** New commands for the 'M-x eglot-list-connections' major mode
** New command 'M-x eglot-describe-connection'
'k' shuts down and 'r' reconnects the server on the current line.
Pops up a detailed description buffer for the current connection,
outlining aspects such as the LSP server name and version, the project
name and root path, among others.
** Improvements to 'M-x eglot-list-connections'
New key bindings: 'k' shuts down, 'r' reconnects, 'e' visits the events
buffer, 'w' shows workspace configuration, and 'RET' invokes
'eglot-describe-connection'.
* Changes in Eglot 1.23 (2/4/2026)

View File

@@ -4945,6 +4945,9 @@ If NOERROR, return predicate, else erroring function."
(let ((map (make-sparse-keymap)))
(define-key map "k" #'eglot-shutdown-listed-connection)
(define-key map "r" #'eglot-reconnect-listed-connection)
(define-key map "e" #'eglot-events-buffer-of-listed-connection)
(define-key map "w" #'eglot-show-workspace-configuration-of-listed-connection)
(define-key map (kbd "RET") #'eglot-describe-listed-connection)
map)
"Keymap for `eglot-list-connections-mode'.")
@@ -5002,6 +5005,120 @@ If NOERROR, return predicate, else erroring function."
(eglot--list-connections-cmd eglot-reconnect-listed-connection s
"Reconnect Eglot server on current line" (eglot-reconnect s))
(eglot--list-connections-cmd eglot-events-buffer-of-listed-connection s
"Show events buffer for Eglot server on current line"
(eglot-events-buffer s))
(eglot--list-connections-cmd eglot-show-workspace-configuration-of-listed-connection s
"Show workspace configuration for Eglot server on current line"
(save-current-buffer (eglot-show-workspace-configuration s)))
(eglot--list-connections-cmd eglot-describe-listed-connection server
"Describe Eglot server on current line in detail"
(eglot-describe-connection server))
(cl-defun eglot-describe-connection
(server &aux
(info (eglot--server-info server))
(project (eglot--project server))
(root (project-root project))
(managed (eglot--managed-buffers server))
(caps (eglot--capabilities server))
(watches (eglot--file-watches server))
(wsconf (eglot--workspace-configuration-plist server))
(sname (or (plist-get info :name) (jsonrpc-name server))))
"Describe SERVER in a dedicated buffer."
(interactive (list (eglot--current-server-or-lose)))
(with-current-buffer
(get-buffer-create (format "*EGLOT connection (%s/%s)*"
(eglot-project-nickname server) sname))
(let ((inhibit-read-only t))
(erase-buffer)
(special-mode)
(setq-local revert-buffer-function
(lambda (&rest _)
(eglot-describe-connection server)))
(cl-flet ((heading (str &optional first)
(unless first (insert "\n"))
(insert (propertize str 'face 'bold) "\n")))
(heading "Server" t)
(insert (format " Name: %s\n" sname))
(insert (format " Version: %s\n" (plist-get info :version)))
(heading "Project")
(insert (format " Nickname: %s\n" (eglot-project-nickname server)))
(insert (format " Root: %s\n" root))
(let ((expanded (expand-file-name root))
(trueroot (eglot--trueroot server)))
(unless (string= root expanded)
(insert (format " Expanded: %s\n" expanded)))
(unless (string= expanded trueroot)
(insert (format " Canonical: %s\n" trueroot))))
(insert (format " As lisp: %s\n" project))
(heading "Major modes")
(insert " "
(mapconcat #'symbol-name (eglot--major-modes server) ", ")
"\n")
(heading (format "Managed buffers (%d)" (length managed)))
(dolist (buf managed)
(if (buffer-live-p buf)
(let ((name (or (buffer-file-name buf) (buffer-name buf))))
(insert " ")
(insert-text-button name
'action (lambda (_) (pop-to-buffer buf))
'follow-link t)
(insert "\n"))
(insert " (dead buffer)\n")))
(heading "Capabilities")
(cl-loop
with enabled = (cl-loop for (k v) on caps by #'cddr
unless (eq v :json-false) collect k)
with col-width = (+ 1 (cl-reduce
#'max enabled :initial-value 0
:key (lambda (k) (length (symbol-name k)))))
for tail on enabled by #'cdddr
do (insert " ")
(cl-loop for k in (seq-take tail 3)
for name = (symbol-name k)
do (insert-text-button
name
'action (let ((v (plist-get caps k)))
(lambda (_)
(pp-eval-expression (list 'quote v))))
'follow-link t)
(insert (make-string (- col-width (length name)) ?\s)))
(insert "\n"))
(heading "Workspace configuration")
(if wsconf
(insert (with-temp-buffer
(insert (jsonrpc--json-encode wsconf))
(ignore-errors (require 'json) (json-pretty-print-buffer))
(replace-regexp-in-string "^" " " (buffer-string)))
"\n")
(insert " (none)\n"))
(heading "File watchers")
(if (zerop (hash-table-count watches))
(insert " (none)\n")
(maphash (lambda (id descs)
(insert (format " %s -> %d watcher%s\n" id
(length descs)
(if (= 1 (length descs)) "" "s"))))
watches))
(heading "Events buffer")
(insert " ")
(insert-text-button "Show events buffer"
'action (lambda (_) (eglot-events-buffer server))
'follow-link t)
(insert "\n")))
(goto-char (point-min))
(display-buffer (current-buffer))))
;;; Inlay hints
(defface eglot-inlay-hint-face '((t (:height 0.8 :inherit shadow)))
@@ -5658,11 +5775,15 @@ lock machinery calls us again."
eglot-reconnect
eglot-rename
eglot-signal-didChangeConfiguration
eglot-stderr-buffer))
eglot-stderr-buffer
eglot-describe-connection))
(function-put sym 'command-modes '(eglot--managed-mode)))
(dolist (sym '(eglot-shutdown-listed-connection
eglot-reconnect-listed-connection))
eglot-reconnect-listed-connection
eglot-events-buffer-of-listed-connection
eglot-show-workspace-configuration-of-listed-connection
eglot-describe-listed-connection))
(function-put sym 'command-modes '(eglot-list-connections-mode)))
(provide 'eglot)