From 6f3ec2bb91b60e5c856d0aadf9fc04d545bd938d Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Fri, 11 Sep 2026 17:58:34 +0700 Subject: [PATCH] Keep the indicator, eldoc and the cache to buffers that asked for them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things the first cut got wrong by being global when it had no business being. The modeline entry was added to `mode-line-misc-info' at load. It returns nil outside a Flan buffer, so it was invisible — but it was still evaluated on every redisplay of every buffer in the session, for someone who loads the client and then spends the afternoon in dired. It is installed buffer-locally by `flan-dev-setup' now, which already runs in exactly the buffers that want it. The `derived-mode-p' guard stays: cheap, and it keeps the function honest wherever it is called from. `flan-dev-setup' switched eldoc on. Contributing a documentation source is this file's business; whether eldoc runs at all is the user's, and turning it on overrules someone who has `global-eldoc-mode' off deliberately. It is on by default, so nearly everyone gets the same behaviour either way. And a reconnect forgot the name cache without asking for it again. An empty cache is honest but silent — eldoc goes quiet, M-. falls through to whatever else is registered, and nothing says why — until the next install happens to refill it. It refreshes straight after reconnecting, which is safe from there because the connection is live by that point and the request does not come back round through the same function. --- emacs/flan-dev.el | 22 +++++++++++++++++++--- emacs/test-flan-dev.el | 13 +++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/emacs/flan-dev.el b/emacs/flan-dev.el index 19c4b69..51e1289 100644 --- a/emacs/flan-dev.el +++ b/emacs/flan-dev.el @@ -179,6 +179,12 @@ that quietly did nothing, which is why it is on." ;; A restarted daemon is a rebuilt program: everything known ;; about its names was about the last one. (flan-dev--forget-defs) + ;; And asked again straight away. An empty cache is honest + ;; but silent: eldoc would go quiet and M-. would fall through + ;; to some other backend until the next install happened to + ;; refill it. Safe to call from here — the connection is live + ;; by now, so it does not come back through this function. + (ignore-errors (flan-dev-refresh-defs)) (message "flan dev: reconnected to %s" (abbreviate-file-name flan-dev--socket))) (error @@ -254,8 +260,11 @@ mistake, so it is distinguished from never having connected." (_ (propertize " flan:off" 'face 'shadow 'help-echo "Not connected (C-c C-z)"))))) -;; Appended rather than prepended: this is the least urgent thing in the line. -(add-to-list 'mode-line-misc-info '(:eval (flan-dev-mode-line)) t) +;; Installed buffer-locally by `flan-dev-setup', not globally. A global entry +;; would evaluate on every redisplay of every buffer in the session — dired, +;; eshell, everything — to return nil, for someone who may never open a .flan +;; file at all. The `derived-mode-p' guard above stays anyway: cheap, and it +;; keeps the function honest wherever it is called from. ;;;###autoload (defun flan-show-output () @@ -533,8 +542,15 @@ Installed from here rather than from `flan-mode', which must keep working for someone editing Flan with no program running and this file never loaded." (add-hook 'completion-at-point-functions #'flan-dev-completion-at-point nil t) (add-hook 'xref-backend-functions #'flan-dev-xref-backend nil t) + ;; Registered, not switched on. Contributing a source is this file's + ;; business; whether eldoc runs at all is the user's, and turning it on for + ;; someone who has `global-eldoc-mode' off is overruling a decision they made + ;; on purpose. It is on by default, so this is what almost everyone gets. (add-hook 'eldoc-documentation-functions #'flan-dev-eldoc-function nil t) - (eldoc-mode 1)) + (unless (member '(:eval (flan-dev-mode-line)) mode-line-misc-info) + ;; Appended rather than prepended: the least urgent thing in the line. + (setq-local mode-line-misc-info + (append mode-line-misc-info '((:eval (flan-dev-mode-line))))))) (add-hook 'flan-mode-hook #'flan-dev-setup) diff --git a/emacs/test-flan-dev.el b/emacs/test-flan-dev.el index cf2692c..116f208 100644 --- a/emacs/test-flan-dev.el +++ b/emacs/test-flan-dev.el @@ -54,6 +54,14 @@ is written instead — the real `message' call the real command makes." (string-match-p "live" (flan-dev-mode-line)))) (test-flan--check "and says nothing in a buffer that is not Flan's" (with-temp-buffer (null (flan-dev-mode-line)))) + ;; Buffer-locally, so that someone who loads this and never opens a .flan + ;; file is not evaluating it on every redisplay of every buffer they have. + (test-flan--check "the indicator is in this buffer's modeline" + (member '(:eval (flan-dev-mode-line)) mode-line-misc-info)) + (test-flan--check "and not in everyone else's" + (with-temp-buffer + (not (member '(:eval (flan-dev-mode-line)) + mode-line-misc-info)))) ;; A daemon restarted while Emacs was not looking is the ordinary case. The ;; socket outlives this connection, so dropping the process and asking again @@ -67,6 +75,11 @@ is written instead — the real `message' call the real command makes." (test-flan--check "the next request reconnects on its own" (and (process-live-p flan-dev--connection) (member "step" (plist-get r :fns))))) + ;; ...and knows the program's names again. An empty cache after a reconnect + ;; is honest but silent: eldoc goes quiet and M-. falls through to another + ;; backend, with nothing said about why. + (test-flan--check "and knows the program's names again" + (assoc "step" flan-dev--defs)) ;; But a socket nobody is listening on is refused by name, rather than ;; retried forever or reported as some other failure.