Ignoring batch mode, the message
function displays a message to the user in the echo area and logs it in the message log buffer (default *Messages*
).
If we're calling some code that we don't control (or sometimes even if we do), we might want to suppress either behavior. To do that:
To make
message
not show something in the echo area temporarily, let-bindinhibit-message
to non-nil.(let ((inhibit-message t)) ;; Logs but does not show in echo area (message "%s" "abc") (some-code-that-calls-message))
To make
message
not log messages to the log buffer, let bindmessage-log-max
to nil.(let ((message-log-max nil)) ;; Shows in echo area but does not log (message "%s" "abc") (some-code-that-calls-message))
Additionally, you can utilize inhibit-redisplay
to prevent intermediate messages from flashing to the user. This is something that builtin files.el should do but, uh, currently doesn't.
;; Emacs 29
(defun files--message (format &rest args)
;; ...
(apply #'message format args)
;; Redisplay can run here and flash the to-be-cleared message to the
;; user
(when save-silently (message nil)))
However, this is still not enough. The message
function will clear the echo area instead of leave it as-is when inhibit-message
is non-nil.
This is what the shut-up package is useful for. The shut-up
macro it provides temporarily rebinds message
to a function that only inserts the message to a temporary buffer and prevents it from doing anything to the echo area.
Examples
Our test code looks like this:
(progn
(message "Prior") ; simulate prior content in echo area
(run-at-time
1 nil
(lambda ()
;; The part being tested
(let ((inhibit-message t))
(message "...")))))
Let's abstract it a bit.
(defmacro k:test-message-inhibiting (&rest body)
(declare (indent 0))
`(progn
;; Put some prior content into the echo area, to see what happens
;; to existing content in the echo area.
;; If this is run in Org or with eval-last-sexp, they will both
;; display something in the echo area, which also works as the
;; prior content.
(message "Prior")
(run-at-time
1 nil
(lambda ()
,@body))))
Now let's start testing.
(k:test-message-inhibiting
(message "..."))
...
is shown in the echo area...
is written into*Messages*
(k:test-message-inhibiting
(let ((inhibit-message t))
(message "...")))
- The echo area is cleared
...
is written into*Messages*
(k:test-message-inhibiting
(let ((message-log-max nil))
(message "...")))
...
is shown in the echo area...
is not written into*Messages*
(k:test-message-inhibiting
(let ((inhibit-redisplay t))
(message "...")))
...
is shown in the echo area. Although redisplay doesn't happen within thelet
, the message is still written to the echo area (and haven't been overwritten), so the next redisplay still shows the message....
is written into*Messages*
(require 'shut-up)
(k:test-message-inhibiting
(shut-up
(message "...")))
- Echo area is untouched
*Messages*
is untouched