Package: emacs;
Reported by: Eshel Yaron <me <at> eshelyaron.com>
Date: Wed, 17 Jan 2024 19:45:02 UTC
Severity: minor
Tags: patch
View this message in rfc822 format
From: João Távora <joaotavora <at> gmail.com> To: Eshel Yaron <me <at> eshelyaron.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 68547 <at> debbugs.gnu.org Subject: bug#68547: [PATCH] ; Fix 'mode-line-format-right-align' with ElDoc Date: Sat, 20 Jan 2024 18:08:35 +0000
On Sat, Jan 20, 2024 at 3:33 PM Eshel Yaron <me <at> eshelyaron.com> wrote: > Then I tried the following (somewhat pathological) use case: > > 0. Setup: (keymap-global-set "C-x w a" #'windmove-swap-states-left) > 1. Open two buffers in two windows side by side. > 2. Say `M-: (car `, to show info in the mode line of the left window. > 3. Without quitting the minibuffer, use `C-x o` to switch to the right > window, followed by `C-x w a` to switch the buffers in the left and > right windows. > 4. Return to the minibuffer and type `nil) RET` or something like that > to exit the minibuffer. > 5. The `mode-line-format` of the left buffer is becomes nil, i.e. no mode line. > > Shuffling `mode-line-format` around is really tricky :( Indeed. Your case is pathological, but not particularly hard to trigger. Given the consequences are somewhat dire (vanished mode-line) , it should most definitely be handled. Try this version, please. Only difference is it uses a setq-local for eldoc--saved-mlf instead of a setq. Please give it as much testing as you can. João diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 912a7357ca7..1ba4e6a006f 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -182,7 +182,7 @@ eldoc-current-idle-delay "Idle time delay currently in use by timer. This is used to determine if `eldoc-idle-delay' is changed by the user.") -(defvar eldoc-message-function #'eldoc-minibuffer-message +(defvar eldoc-message-function #'eldoc--minibuffer-message "The function used by `eldoc--message' to display messages. It should receive the same arguments as `message'.") @@ -292,43 +292,42 @@ eldoc-schedule-timer (setq eldoc-current-idle-delay eldoc-idle-delay) (timer-set-idle-time eldoc-timer eldoc-idle-delay t)))) -(defvar eldoc-mode-line-string nil) -(put 'eldoc-mode-line-string 'risky-local-variable t) - -(defun eldoc-minibuffer-message (format-string &rest args) +(defvar eldoc--saved-mlf nil + "Saved `mode-line-format' used in `eldoc--minibuffer-message'.") +(defun eldoc--minibuffer-message (format-string &rest args) "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed. This function displays the message produced by formatting ARGS with FORMAT-STRING on the mode line when the current buffer is a minibuffer. Otherwise, it displays the message like `message' would." - (if (or (bound-and-true-p edebug-mode) (minibufferp)) - (progn - (add-hook 'post-command-hook #'eldoc-minibuffer--cleanup) - (with-current-buffer - (window-buffer - (or (window-in-direction 'above (minibuffer-window)) - (minibuffer-selected-window) - (get-largest-window))) - (when (and mode-line-format - (not (and (listp mode-line-format) - (assq 'eldoc-mode-line-string mode-line-format)))) - (setq mode-line-format - (funcall - (if (listp mode-line-format) #'append #'list) - (list "" '(eldoc-mode-line-string - (" " eldoc-mode-line-string " "))) - mode-line-format))) - (setq eldoc-mode-line-string - (when (stringp format-string) - (apply #'format-message format-string args))) - (force-mode-line-update))) - (apply #'message format-string args))) - -(defun eldoc-minibuffer--cleanup () - (unless (or (bound-and-true-p edebug-mode) (minibufferp)) - (setq eldoc-mode-line-string nil - ;; https://debbugs.gnu.org/16920 - eldoc-last-message nil) - (remove-hook 'post-command-hook #'eldoc-minibuffer--cleanup))) + (cond ((bound-and-true-p edebug-mode) + (eldoc--message-in-mode-line 'edebug-mode-hook format-string args)) + ((minibufferp) + (eldoc--message-in-mode-line 'minibuffer-exit-hook format-string args)) + (t + (apply #'message format-string args)))) + +(defun eldoc--message-in-mode-line (hook format-string args) + (with-current-buffer + (window-buffer + (or (window-in-direction 'above (minibuffer-window)) + (minibuffer-selected-window) + (get-largest-window))) + (let ((buf (current-buffer))) + (cl-labels ((cleanup () + (with-current-buffer buf + (remove-hook hook #'cleanup) + (setq mode-line-format eldoc--saved-mlf + eldoc--saved-mlf nil)))) + (add-hook hook #'cleanup) + (setq-local eldoc--saved-mlf (or eldoc--saved-mlf mode-line-format)) + (when format-string + (setq-local + mode-line-format + (funcall (if (listp eldoc--saved-mlf) #'cons #'list) + (and format-string + (apply #'format-message format-string args)) + eldoc--saved-mlf))) + (force-mode-line-update))))) (make-obsolete 'eldoc-message "use `eldoc-documentation-functions' instead." "eldoc-1.1.0") -- João Távora
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.