From 1c4c9d759a2e32856db3fd03e906057c8d81fa0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Thu, 16 Apr 2026 09:28:16 +0100 Subject: [PATCH] Eglot: add shutdown/reconnect bindings to eglot-list-connections buffer * lisp/progmodes/eglot.el (eglot-list-connections-mode-map): New defvar. * lisp/progmodes/eglot.el (eglot--list-connections-entries): New function, extracted from eglot-list-connections. * lisp/progmodes/eglot.el (eglot--list-connections-cmd): New macro. * lisp/progmodes/eglot.el (eglot-shutdown-listed-connection) (eglot-reconnect-listed-connection): New commands. * lisp/progmodes/eglot.el (eglot-list-connections): Use eglot--list-connections-entries. * doc/misc/eglot.texi: Document eglot-list-connections and new keys. * etc/EGLOT-NEWS: Announce. --- doc/misc/eglot.texi | 7 +++++ etc/EGLOT-NEWS | 7 +++++ lisp/progmodes/eglot.el | 62 ++++++++++++++++++++++++++++++----------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi index 68829a733c5..e6ca177c726 100644 --- a/doc/misc/eglot.texi +++ b/doc/misc/eglot.texi @@ -713,6 +713,13 @@ 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-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. + @item M-x eglot-rename This command renames the program symbol (a.k.a.@: @dfn{identifier}) at point to another name. It prompts for the new name of the symbol, and diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS index 81becb41eba..cdbe4cc2c22 100644 --- a/etc/EGLOT-NEWS +++ b/etc/EGLOT-NEWS @@ -17,6 +17,13 @@ This refers to https://github.com/joaotavora/eglot/issues/. That is, to look up issue github#1234, go to https://github.com/joaotavora/eglot/issues/1234. + +* Changes to upcoming Eglot + +** New commands for the 'M-x eglot-list-connections' major mode + +'k' shuts down and 'r' reconnects the server on the current line. + * Changes in Eglot 1.23 (2/4/2026) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 6e7d0dcf7a1..c357e23ad12 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -4938,6 +4938,13 @@ If NOERROR, return predicate, else erroring function." ;;; List connections mode +(defvar eglot-list-connections-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "k" #'eglot-shutdown-listed-connection) + (define-key map "r" #'eglot-reconnect-listed-connection) + map) + "Keymap for `eglot-list-connections-mode'.") + (define-derived-mode eglot-list-connections-mode tabulated-list-mode "" "Eglot mode for listing server connections. \\{eglot-list-connections-mode-map}" @@ -4947,6 +4954,25 @@ If NOERROR, return predicate, else erroring function." ("Modes" 20) ("Invocation" 32)]) (tabulated-list-init-header)) +(defun eglot--list-connections-entries () + "Compute `tabulated-list-entries' for the connections list buffer." + (mapcar + (lambda (server) + (list server + `[,(or (plist-get (eglot--server-info server) :name) + (jsonrpc-name server)) + ,(eglot-project-nickname server) + ,(format "%s" (length (eglot--managed-buffers server))) + ,(mapconcat #'symbol-name + (eglot--major-modes server) + ", ") + ,(let ((c (process-command + (jsonrpc--process server)))) + (if (consp c) (mapconcat #'identity c " ") + "network"))])) + (cl-reduce #'append + (hash-table-values eglot--servers-by-project)))) + (defun eglot-list-connections () "List currently active Eglot connections." (interactive) @@ -4955,26 +4981,24 @@ If NOERROR, return predicate, else erroring function." (let ((inhibit-read-only t)) (erase-buffer) (eglot-list-connections-mode) - (setq-local tabulated-list-entries - (mapcar - (lambda (server) - (list server - `[,(or (plist-get (eglot--server-info server) :name) - (jsonrpc-name server)) - ,(eglot-project-nickname server) - ,(format "%s" (length (eglot--managed-buffers server))) - ,(mapconcat #'symbol-name - (eglot--major-modes server) - ", ") - ,(let ((c (process-command - (jsonrpc--process server)))) - (if (consp c) (mapconcat #'identity c " ") - "network"))])) - (cl-reduce #'append - (hash-table-values eglot--servers-by-project)))) + (setq-local tabulated-list-entries #'eglot--list-connections-entries) (revert-buffer) (pop-to-buffer (current-buffer))))) +(cl-defmacro eglot--list-connections-cmd (name s doc &body body) + (declare (indent 2) (debug (sexp sexp sexp &rest form))) + `(defun ,name () + ,doc (interactive) + (if-let* ((,s (tabulated-list-get-id))) + (progn ,@body (tabulated-list-revert)) + (user-error "No server on this line")))) + +(eglot--list-connections-cmd eglot-shutdown-listed-connection s + "Shutdown Eglot server on current line" (eglot-shutdown s)) + +(eglot--list-connections-cmd eglot-reconnect-listed-connection s + "Reconnect Eglot server on current line" (eglot-reconnect s)) + ;;; Inlay hints (defface eglot-inlay-hint-face '((t (:height 0.8 :inherit shadow))) @@ -5634,6 +5658,10 @@ lock machinery calls us again." eglot-stderr-buffer)) (function-put sym 'command-modes '(eglot--managed-mode))) +(dolist (sym '(eglot-shutdown-listed-connection + eglot-reconnect-listed-connection)) + (function-put sym 'command-modes '(eglot-list-connections-mode))) + (provide 'eglot)