Subject: bug#71823: 31.0.50; project-mode-line and eglot duplicate project-name in mode-line

From: [email-masked]
Date: Sun, 30 Jun 2024 12:51:25 +0000 (UTC)

João Távora <[email-masked]> writes:
> On Sat, Jun 29, 2024, 15:24 Spencer Baugh <[email-masked]> wrote:
>
>  Or, here's an alternative idea, more aggressive:
>
>  What if Eglot just sets project-mode-line=t in eglot-managed buffers, and removes the project-name from the Eglot entry
>  entirely?
>
>  Then the language identifier would be the major mode, the project identifier would be project-mode-line, and the eglot status
>  indicator would just be for the status of the server.
>
> Works for me, it's in line with Eglot's policy of setting other modes when managing buffers. Show a patch. 

Attached.

I do think this is a great way to resolve this - now that
project-mode-line exists, using it deletes one small bit of
eglot-specific functionality, which is in line with the Eglot design
philosophy.

The only issue is that this was only added to mode-line-format in Emacs
30, so we can only use it in Emacs 30 or later.

The attached patch detects that with:

+    (when (member '(project-mode-line project-mode-line-format) mode-line-format)

but I'm also totally fine with:

+    (when (version<= "30" emacs-version)

Or I guess we could sidestep the issue if project.el itself ensured,
when loaded, that mode-line-format contains project-mode-line.  eglot
itself does this with eglot--mode-line-format, running the following at
load time:

  (add-to-list 'mode-line-misc-info
             `(eglot--managed-mode (" [" eglot--mode-line-format "] ")))

Juri, any opinion?

> But also, my idea of eglot-mode-line-format should be alsoh considered. AFAICT there no big technical hurdle, it's just relatively
> boring work and some naming decisions to make. And as I mentioned, it would fix more issues than just the one at hand.

Yes, I think that would also be useful as a separate patch.

>From 5b53ecc3db2356bcab3fd8b9d8583de6a6adcef2 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <[email-masked]>
Date: Sun, 30 Jun 2024 08:27:43 -0400
Subject: [PATCH] Use project-mode-line for the project nick in Eglot

The existence of project-mode-line now means that eglot can have
an indicator for the current project of the current buffer,
without using the eglot mode-line entry to do it.

This commit teaches eglot to (when possible) set
project-mode-line true in eglot-managed buffers and remove
project-name from the eglot mode line entry.

* lisp/progmodes/eglot.el (eglot--managed-mode): Set
project-mode-line if the project-mode-line entry is in
mode-line-format.
(eglot-menu): Always include eglot-server-menu as a submenu.
(eglot--mode-line-format): Don't include project-name when
project-mode-line is set. (bug#71823)
---
 lisp/progmodes/eglot.el | 74 ++++++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 35 deletions(-)

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index bb6b0281d9f..249dda7f3d8 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -7,7 +7,7 @@
 ;; Maintainer: João Távora <[email-masked]>
 ;; URL: https://github.com/joaotavora/eglot
 ;; Keywords: convenience, languages
-;; Package-Requires: ((emacs "26.3") (compat "27.1") (eldoc "1.14.0") (external-completion "0.1") (flymake "1.2.1") (jsonrpc "1.0.24") (project "0.9.8") (seq "2.23") (track-changes "1.2") (xref "1.6.2"))
+;; Package-Requires: ((emacs "26.3") (compat "27.1") (eldoc "1.14.0") (external-completion "0.1") (flymake "1.2.1") (jsonrpc "1.0.24") (project "0.11.0") (seq "2.23") (track-changes "1.2") (xref "1.6.2"))
 
 ;; This is a GNU ELPA :core package.  Avoid adding functionality
 ;; that is not available in the version of Emacs recorded above or any
@@ -2026,6 +2026,8 @@ eglot--managed-mode
     (eglot--setq-saving company-tooltip-align-annotations t)
     (eglot--setq-saving eldoc-documentation-strategy
                         #'eldoc-documentation-compose)
+    (when (member '(project-mode-line project-mode-line-format) mode-line-format)
+      (setq-local project-mode-line t))
     (unless (eglot--stay-out-of-p 'imenu)
       (add-function :before-until (local 'imenu-create-index-function)
                     #'eglot-imenu))
@@ -2161,10 +2163,24 @@ eglot-upgrade-eglot
       (package-delete existing t))
     (package-install (cadr (assoc 'eglot package-archive-contents)))))
 
+(easy-menu-define eglot-server-menu nil "Monitor server communication"
+  '("Debugging the server communication"
+    ["Reconnect to server" eglot-reconnect]
+    ["Quit server" eglot-shutdown]
+    "--"
+    ["LSP events buffer" eglot-events-buffer]
+    ["Server stderr buffer" eglot-stderr-buffer]
+    ["Customize event buffer size"
+     (lambda ()
+       (interactive)
+       (customize-variable 'eglot-events-buffer-size))]))
+
 (easy-menu-define eglot-menu nil "Eglot"
   `("Eglot"
     ;; Commands for getting information and customization.
     ["Customize Eglot" (lambda () (interactive) (customize-group "eglot"))]
+    ["Server" eglot-server-menu
+     :active (eglot-current-server)]
     "--"
     ;; xref like commands.
     ["Find definitions" xref-find-definitions
@@ -2211,18 +2227,6 @@ eglot-menu
     ["Quickfix" eglot-code-action-quickfix
      :visible (eglot-server-capable :codeActionProvider)]))
 
-(easy-menu-define eglot-server-menu nil "Monitor server communication"
-  '("Debugging the server communication"
-    ["Reconnect to server" eglot-reconnect]
-    ["Quit server" eglot-shutdown]
-    "--"
-    ["LSP events buffer" eglot-events-buffer]
-    ["Server stderr buffer" eglot-stderr-buffer]
-    ["Customize event buffer size"
-     (lambda ()
-       (interactive)
-       (customize-variable 'eglot-events-buffer-size))]))
-
 (defun eglot--mode-line-props (thing face defs &optional prepend)
   "Helper for function `eglot--mode-line-format'.
 Uses THING, FACE, DEFS and PREPEND."
@@ -2252,7 +2256,7 @@ eglot--mode-line-format
          'keymap (let ((map (make-sparse-keymap)))
                    (define-key map [mode-line down-mouse-1] eglot-menu)
                    map)))
-     (when nick
+     (when (and nick (not project-mode-line))
        `(":"
          ,(propertize
            nick
@@ -2261,28 +2265,28 @@ eglot--mode-line-format
            'help-echo (format "Project '%s'\nmouse-1: LSP server control menu" nick)
            'keymap (let ((map (make-sparse-keymap)))
                      (define-key map [mode-line down-mouse-1] eglot-server-menu)
-                     map))
-         ,@(when last-error
-             `("/" ,(eglot--mode-line-props
-                     "error" 'compilation-mode-line-fail
-                     '((mouse-3 eglot-clear-status  "Clear this status"))
-                     (format "An error occurred: %s\n" (plist-get last-error
-                                                                  :message)))))
-         ,@(when (cl-plusp pending)
-             `("/" ,(eglot--mode-line-props
-                     (format "%d" pending) 'warning
-                     '((mouse-3 eglot-forget-pending-continuations
-                                "Forget pending continuations"))
-                     "Number of outgoing, \
+                     map))))
+     (when last-error
+       `("/" ,(eglot--mode-line-props
+               "error" 'compilation-mode-line-fail
+               '((mouse-3 eglot-clear-status  "Clear this status"))
+               (format "An error occurred: %s\n" (plist-get last-error
+                                                            :message)))))
+     (when (cl-plusp pending)
+       `("/" ,(eglot--mode-line-props
+               (format "%d" pending) 'warning
+               '((mouse-3 eglot-forget-pending-continuations
+                          "Forget pending continuations"))
+               "Number of outgoing, \
 still unanswered LSP requests to the server\n")))
-         ,@(cl-loop for pr hash-values of (eglot--progress-reporters server)
-                    when (eq (car pr)  'eglot--mode-line-reporter)
-                    append `("/" ,(eglot--mode-line-props
-                                   (format "%s%%%%" (or (nth 4 pr) "?"))
-                                   'eglot-mode-line
-                                   nil
-                                   (format "(%s) %s %s" (nth 1 pr)
-                                           (nth 2 pr) (nth 3 pr))))))))))
+     (cl-loop for pr hash-values of (eglot--progress-reporters server)
+              when (eq (car pr)  'eglot--mode-line-reporter)
+              append `("/" ,(eglot--mode-line-props
+                             (format "%s%%%%" (or (nth 4 pr) "?"))
+                             'eglot-mode-line
+                             nil
+                             (format "(%s) %s %s" (nth 1 pr)
+                                     (nth 2 pr) (nth 3 pr))))))))
 
 (add-to-list 'mode-line-misc-info
              `(eglot--managed-mode (" [" eglot--mode-line-format "] ")))
-- 
2.44.0