1

Running (async-shell-command "echo test") prints echo test: finished to the echo area upon completion. I am running a function in the background on a loop with a special handler, and the message is just distracting for me. How can I programmatically disable it for this invocation?

Normally I would do this with a local (let ((inhibit-message t)) …), but this is presumably happening in a continuation somewhere.

2 Answers 2

2

There are two versions of function (inhibit-sentinel-messages FUN &rest ARGS) defined in Section Code of inhibit-sentinel-messages of this answer. The first version wraps all sentinels started in FUN with set-process-sentinel into let blocks with inhibit-message t. The second version avoids sentinel messages completely by temporarily advising message with ignore.

You can use inhibit-sentinel-messages like so:

(inhibit-sentinel-messages #'async-shell-command "echo test")

If you also want to hide the *Async Shell Command* buffer you can use display-buffer-alist let-bound as follows:

(let ((display-buffer-alist (cons '("\\`\\*Async Shell Command\\*\\'" display-buffer-no-window) display-buffer-alist)))
  (inhibit-sentinel-messages #'async-shell-command "echo test"))

If you want to suppress sentinel messages in idle timers you need to use inhibit-sentinel-messages in the body of the timer function.

Example:

(setq my-counter 0)

(setq my-timer (run-with-idle-timer
        10 t
        (lambda ()
          (inhibit-sentinel-messages
           #'async-shell-command (format "echo test%d" (cl-incf my-counter))))))

Code of inhibit-sentinel-messages

Binding inhibit-message to t

This code avoids displaying the sentinel messages in the echo area. The sentinel messages are still output to the *Messages* buffer.

(defun inhibit-sentinel-messages (fun &rest args)
  "Inhibit messages in all sentinels started by fun."
  (cl-letf* ((old-set-process-sentinel (symbol-function 'set-process-sentinel))
         ((symbol-function 'set-process-sentinel)
          (lambda (process sentinel)
        (funcall
         old-set-process-sentinel
         process
         `(lambda (&rest args)
            (let ((inhibit-message t))
              (apply (quote ,sentinel) args)))))))
        (apply fun args)))

Temporarily advising message to ignore

This code avoids the generation of sentinel messages completely.

(defun inhibit-sentinel-messages (fun &rest args)
  "Inhibit messages in all sentinels started by fun."
  (cl-letf* ((old-set-process-sentinel (symbol-function 'set-process-sentinel))
         ((symbol-function 'set-process-sentinel)
          (lambda (process sentinel)
        (funcall
         old-set-process-sentinel
         process
         `(lambda (&rest args)
            (cl-letf (((symbol-function 'message) #'ignore))
              (apply (quote ,sentinel) args)))))))
        (apply fun args)))
4
  • This looks very promising, and indeed if I run (inhibit-sentinel-messages #'async-shell-command "echo test") it does not echo a finished message. However, if I run it in the background on a loop, it gives me finished messages again. Maybe there's a problem with repeated processes? Or perhaps something conflicting with idle timers? Commented Apr 30, 2019 at 18:29
  • Maybe it would be more reliable—if more dangerous—to simply filter the *Messages* buffer? Commented Apr 30, 2019 at 18:32
  • @MatthewPiziak inhibit-sentinel-messages works for me also in timer functions (with Emacs 26.1). I've added a usage example for an idle timer in the answer. I have also added another version of inhibit-sentinel-messages that avoids not only the display in the echo area but also the output in the message buffer.
    – Tobias
    Commented May 1, 2019 at 2:06
  • This works! Totally my fault. I had an extra (shell-command-sentinel process signal) in my handler for some reason. Commented May 1, 2019 at 18:26
0

This message is coming from the shell-command-sentinel function in simple.el. A nasty way of doing what you want would be to simply redefine the function like this:

(defun shell-command-sentinel (process signal)
  (when (memq (process-status process) '(exit signal))
    (shell-command--set-point-after-cmd (process-buffer process))))

which just removes the call to message, but would of course prevent the message from appearing with all shell commands. Obviously you could use a global variable to determine whether or not to suppress the message, but I don't know how you could tell when all of your asynchronous commands have finished running...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.