26

In Emacs, there are some cases where I would like to prevent messages from appearing in the minibuffer, mainly pertaining to "Beginning/End of buffer" and "Text is read-only".

Is there any way I can prevent these messages from appearing in the minibuffer?

Also, is there some significant reason I might not want to disable these? At face value, I can just as easily look at the row number and buffer write status on the modeline.

1
  • 2
    There is no reason why you'd need those messages, no. The reason why those messages exist is to try and make sure that every command has some visible effect: when the command's expected visible effect can't be performed, we instead emit a message, so you can tell that the command was indeed run.
    – Stefan
    Mar 9, 2017 at 14:57

5 Answers 5

26

In Emacs 25, you can suppress minibuffer messages by binding inhibit-message to a non-nil value:

(let ((inhibit-message t))
  (message "Listen to me, you!"))
6
  • Does this work on primitives called from C as well? Apr 11, 2016 at 14:20
  • 1
    It should, as the C function message1 calls message3, which respects this variable. Apr 11, 2016 at 15:48
  • Useful for supressing the annoying mu4e "Retreiving mail..." message: (let ((inhibit-message t)) (message make-progress-reporter)) Apr 19, 2018 at 21:07
  • 1
    This doesn't work for me on Emacs 26.1, oddly enough. Any idea why? Apr 4, 2019 at 14:42
  • 1
    @ChristianHudon I just tested in Emacs 26.1 and master with no init file, and it works for me in both places. Note that message returns the message string, so maybe you are seeing the returned string when evaluating the code. If you eval this code in a keybinding, then no message will be printed (except in the Messages buffer). Apr 28, 2019 at 23:10
9

In Emacs 25 and probably in some earlier versions, the cleanest way of doing this is as follows:

First define:

(defun suppress-messages (old-fun &rest args)
  (cl-flet ((silence (&rest args1) (ignore)))
    (advice-add 'message :around #'silence)
    (unwind-protect
         (apply old-fun args)
      (advice-remove 'message #'silence))))

Then if you want to suppress all the messages produced by some-function you do:

(advice-add 'some-function :around #'suppress-messages)

For instance, I suppress the message "Ispell process killed" produced by the function ispell-kill-ispell (in ispell.el.gz) by writing:

(advice-add 'ispell-kill-ispell :around #'suppress-messages)

If you ever need to re-enable the messages then run:

(advice-remove 'some-function #'suppress-messages)

A few of things to note:

1) All messages produced by some-function will be suppressed as will all messages produced by any lisp function the function calls.

2) Messages produced by C code will not be supressed but that is probably all for the best.

3) You need to make sure -*- lexical-binding: t -*- is contained in the first line of your .el file.

But how do you find out which function called message? You could grep through the code as someone else suggested, but it's easier to let Emacs do the work for you.

If you define:

(defun who-called-me? (old-fun format &rest args)
  (let ((trace nil) (n 1) (frame nil))
      (while (setf frame (backtrace-frame n))
        (setf n     (1+ n) 
              trace (cons (cadr frame) trace)) )
      (apply old-fun (concat "<<%S>>\n" format) (cons trace args))))

and then do:

(advice-add 'message :around #'who-called-me?)

you will get a backtrace added to the message. From this you can easily see where the message was generated.

You can reverse this with:

(advice-remove 'message #'who-called-me?)

An alternative approach would be to advise the message function and test to see if you want to print the message or not. This is simple if the message in question is a fixed string. E.g. to suppress "Ispell process killed" you could define:

(defun suppress-ispell-message (old-fun format &rest args)
  (if (string= format "Ispell process killed")
         (ignore)
    (apply old-fun format args)))

and then do:

(advice-add 'message :around #'suppress-ispell-message)

This approach soon gets very messy if the message is anything complicated.

9

You can sort of do this from Lisp code. Why "sort of"? Because MESSAGE is a primitive, defined in C, instead of a Lisp function, and, per the Emacs Lisp reference manual, calls to primitives from C code ignore advice.

Therefore, in order to really do a proper job of implementing the functionality you desire, you would need to redefine the MESSAGE primitive as a Lisp function; once you've done so, you can then advise it with code which obtains the string MESSAGE would echo to the minibuffer, compares it with a list of messages you don't want to see, and then calls or doesn't call MESSAGE depending on the result. In theory, this could be accomplished by e.g. (defvar *message-prim* (symbol-function 'message)), and then (defun message (format &rest args) ... (funcall *message-prim* format args)) -- but SYMBOL-FUNCTION given a primitive argument returns something that isn't actually callable, so the FUNCALL signals a VOID-FUNCTION condition.

However, even if that worked, it still wouldn't really do the trick, because redefining a primitive only guarantees that the redefinition will be used when the function is called from Lisp code; calls in C code may still use the primitive definition. (It is possible for C code to call into Emacs Lisp, and such cases will see the redefinition; it is also, of course, possible for C code to call C code, and such cases will see the original definition.)

I'm vaguely contemplating patching the C code and recompiling Emacs to provide proper message suppression functionality; I don't really need that functionality, but it might prove an interesting exercise, especially since I'm not a C hacker. In the meantime, here's something I whipped up which, when dropped into a file, included from one of your init files, and customized to your taste, will suppress messages originating from Lisp code which exactly match the strings you list for suppression. As long as suppression is enabled, these messages will never appear in the minibuffer; you have the option of whether to suppress them from the *Messages* buffer as well.

;; message-suppression.el
;; a quick hack by Aaron ([email protected]), 2013-11-12
;; half a solution for http://superuser.com/questions/669701/emacs-disable-some-minibuffer-messages
;; NB this does nothing until you 
;; M-x customize-group RET message-suppression RET
;; and adjust to taste

(defgroup message-suppression nil
  "Customization options for selective message suppression."
  :prefix "message-suppression")

(defcustom message-suppression-enabled nil
  "Whether or not to suppress messages listed in
`message-suppress-these'."
  :group 'message-suppression
  :tag "Suppress some messages?"
  :type '(choice (const :tag "No" nil)
                 (const :tag "Yes" t)))

(defcustom message-suppression-to-messages-buffer t
  "Whether or not to insert messages suppressed from the
minibuffer into the *Messages* buffer."
  :group 'message-suppression
  :tag "Insert suppressed messages into *Messages* buffer?"
  :type '(choice (const :tag "No" nil)
                 (const :tag "Yes" t)))

(defcustom message-suppression-these nil
  "A list of messages which the `message-except-these' advice
should suppress from being echoed in the minibuffer. Messages
are matched by `member', i.e., only exact strings match.

NB! Per the Emacs manual, calls from C code to primitives (such
as `message') ignore advice entirely, which means some messages
cannot be suppressed by this mechanism. ('Advising
Functions' in the Emacs Lisp Reference Manual, q.v.)"
  :group 'message-suppression
  :tag "Messages to suppress"
  :type '(repeat (string))
  :link '(info-link "(elisp)Advising Functions"))

(defadvice message (around message-suppress-advice)
  "Suppress messages listed in `message-suppress-these' from being
  echoed in the minibuffer."
  (let ((message-string nil)
        (current-buffer nil))
    (if (and message-suppression-enabled
             (length (ad-get-args 0))
             (stringp (car (ad-get-args 0)))
             ;; message-string doesn't get set until here because `format'
             ;; will complain if its first argument isn't a string
             (setq message-string (apply 'format (ad-get-args 0)))
             (member message-string
                     message-suppression-these))
        ;; we won't call `message', but we might echo to *Messages*
        (and message-suppression-to-messages-buffer
             (progn
               (setq current-buffer (current-buffer))
               (switch-to-buffer (get-buffer-create "*Messages*"))
               (goto-char (point-max))
               (insert (make-string 1 10))
               (insert message-string)
               (switch-to-buffer current-buffer)))
      ad-do-it)))

(ad-activate 'message)

I've tested this to work with messages which are actually generated from Lisp code, e.g. the "You didn't specify a function" complaint echoed by DESCRIBE-FUNCTION when you give it an empty string argument. Unfortunately, the messages you mention wanting to suppress, such as "Beginning of buffer", "End of buffer", and "Text is read-only", appear all to originate from C code, which means you won't be able to suppress them by this method.

If I ever do get around to the source patch, it'll (probably) be against Emacs 24.3, and I'll update this answer with information on how to go about using it.

2

You are apparently asking for a way to selectively inhibit certain messages. The answer for that is that you would need to redefine or advise the code that issues those particular messages.

To prevent all messages, for example for the duration of some code, you can use flet or cl-flet to redefine function message locally to (function) ignore. Or use the technique used in edt-electric-helpify: save the original definition of message, fset to ignore, re-fset it back to the original def (though it is better to use unwind-protect if you do that).

2
  • Sorry, but would you be able to help me on how I can search for these error messages? At this point, it almost feels like it's more trouble disabling the messages than there is from keeping them.
    – user152809
    Nov 5, 2013 at 19:50
  • 1
    To search for "these error messages", use grep or A in Dired. Search for the error message text in the Emacs Lisp source files (and possibly also in the Emacs C files, if you have them available). HTH.
    – Drew
    Nov 5, 2013 at 21:13
2

This works for suppressing "Beginning of buffer" and "End of buffer" and doesn't require emacs 25.

; Suppress "Beginning of buffer" and "End of buffer" messages
(defadvice previous-line (around silencer activate)
  (condition-case nil
    ad-do-it
    ((beginning-of-buffer))))

(defadvice next-line (around silencer activate)
  (condition-case nil
    ad-do-it
    ((end-of-buffer))))

Inspired by https://lists.gnu.org/archive/html/help-gnu-emacs/2015-12/msg00189.html but uses "defadvice" for more compatibility.

You must log in to answer this question.