Subject: Re: bug#67393: 29.1; Slow to open file if autosave exists

From: Ihor Radchenko <[email-masked]>
Date: Mon, 25 Dec 2023 16:50:33 +0000

Eli Zaretskii <[email-masked]> writes:

>> Then, the "important" messages should be written in such a way that they
>> can be understood later, away from the immediate context of the message
>> trigger.
>
> I don't think I understand what this means in practice.  Can you show
> what will be displayed in the mini-window in this case, and how to
> make the "important" message stand out?

For example, the message "File exists, but cannot be read" from
`after-find-file' may be written as

"Opening file: <filename> exists, but cannot be read"

>> > How is this better than waiting for a second?
>> 
>> 1. Waiting for a second creates a temptation to press C-g without
>>    thinking and get the original message replaced with "Quit".
>> 
>> 2. The message can be read later (not just within one second). For
>>    example after a distraction in RL and being away from Emacs or a
>>    short moment.
>
> Again: how will this look in practice, including the dismissal action?

Try the following proof-of-concept code:

(defvar important-message-list nil)
(defun set-important-message (message)
  "Return the last message and previous important messages as one string.
Individual messages will be separated by a newline and the last message will be
separated by \"--\".
The previous messages will be displayed no longer than 'message-timeout property
seconds (if 0 - forever). The previous messages may be dismissed via
`remove-previous-message' command.
Note that this feature works best only when `resize-mini-windows'
is at its default value `grow-only'."
  (catch :continue
    (let ((last-message (car important-message-list))
	  (tail (cdr important-message-list)))
      (while last-message
	(let ((timeout (aref last-message 2)))
	  (cond
           ((= timeout 0) (throw :continue t))
	   ((> (float-time) (+ (aref last-message 0) timeout))
            (setq important-message-list (delete last-message important-message-list)))))
        (setq last-message (car tail)
              tail (cdr tail)))))
  (prog1
      (if important-message-list
	  (format "%s\n%s\n%s"
		  (mapconcat (lambda (m) (aref m 1))
			     (reverse important-message-list)
			     "\n")
		  (make-string (frame-width) ?─)
		  message)
	message)
    (when (get-text-property 0 'message-timeout message)
      (push (vector (float-time)
		    (substring-no-properties (copy-sequence message))
                    (get-text-property 0 'message-timeout message))
            important-message-list))))

(defun remove-previous-message (&optional n)
  "Remove the oldest important message displayed.
With numeric prefix argument N, remove N's message."
  (interactive "p")
  (unless important-message-list (user-error "No important messages are displayed."))
  (let ((target (nth (or (and n (1+ n)) 0))))
    (setq important-message-list (delete target important-message-list))))

(setq set-message-function #'set-important-message)

(message (propertize "This is a test!" 'message-timeout 0))
(message (propertize "This will disappear in 3 seconds" 'message-timeout 3))
(message "foo")
;; M-x remove-previous-message to remove the displayed message.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>