Emacs - Disable Some Minibuffer Messages

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!"))

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.


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.

Tags:

Emacs