messageを呼んでもエコーエリアや*Messages*バッファにメッセージを表示させたくない場合があります。
具体的にはrun-with-idle-timerを使ってrecentf-save-listをアイドル時に自動的に実行させるようにしているのですが、実行時にWrote /home/itiut/.emacs.d/.recentfというのがいちいちエコーエリアに表示されて少しうるさく感じます。
方法
defadviceを使ってmessageをフックさせて何かするとかも考えられるのですが、わりとベーシックな関数だと思われるのであまり弄りたくありません。
マクロのwith-temp-messageを使えばそれっぽく見せることができました。
(with-temp-message MESSAGE &rest BODY)は、BODYを実行している間はMESSAGEをエコーエリアに表示させておき、BODYの実行が完了したらエコーエリアに元のメッセージを復元してくれるというものです。
MESSAGEに(current-message)で現在のメッセージをセットすれば、BODYの実行時にも現在のメッセージが引き継がれ、BODY内でmessageが呼ばれてもBODYの実行が一瞬で完了するようであれば、あたかもメッセージがエコーエリアに表示されなかったように見えます。
そしてwith-temp-messageを使うときにmessage-log-maxをnilにしておくと、メッセージは*Messages*バッファに追記されません。
以上を元にwith-suppressed-messageというマクロを作成しました。
(defmacro with-suppressed-message (&rest body)
"Suppress new messages temporarily in the echo area and the `*Messages*' buffer while BODY is evaluated."
(declare (indent 0))
(let ((message-log-max nil))
`(with-temp-message (or (current-message) "") ,@body)))
with-temp-messageではMESSAGEがnilのときは元のメッセージをエコーエリアに復元してくないので、(current-message)がnilとなる場合には空文字列をMESSAGEにセットしています。
使用例
with-suppressed-message中でmessageを呼んでも、メッセージが表示されていないように見えます。
(with-suppressed-message
(message "foo")
(message "bar")
(message "baz"))
冒頭のrun-with-idle-timerの部分はこうなりました。
(run-with-idle-timer 30 t '(lambda ()
(with-suppressed-message (recentf-save-list))))