Answers:
在Emacs 25中,可以通过绑定inhibit-message
到非nil值来抑制迷你缓冲区消息:
(let ((inhibit-message t))
(message "Listen to me, you!"))
message1
调用的那样message3
,它应该尊重此变量。
(let ((inhibit-message t)) (message make-progress-reporter))
message
返回消息字符串,因此在评估代码时可能会看到返回的字符串。如果您在键盘绑定中评估此代码,则不会打印任何消息(“ 消息”缓冲区中除外)。
您可以从Lisp代码中做到这一点。为什么要“排序”?因为MESSAGE是用C定义的原语,而不是Lisp函数,并且根据Emacs Lisp参考手册,从C代码对原语的调用会忽略建议。
因此,为了真正正确地实现所需的功能,您需要将MESSAGE原语重新定义为Lisp函数。完成此操作之后,您可以使用代码建议它,该代码获取字符串MESSAGE将回显到微型缓冲区,将其与您不想看到的消息列表进行比较,然后调用或不调用MESSAGE,具体取决于结果。从理论上讲,这可以通过例如来实现(defvar *message-prim* (symbol-function 'message))
,然后(defun message (format &rest args) ... (funcall *message-prim* format args))
-但是给定原始参数的SYMBOL-FUNCTION返回的内容实际上是不可调用的,因此FUNCALL发出VOID-FUNCTION条件的信号。
但是,即使这样行之有效,它仍然无法真正解决问题,因为重新定义原语只能保证从Lisp代码调用该函数时将使用重新定义。C代码中的调用可能仍然使用基本定义。(C代码可以调用Emacs Lisp,这种情况将得到重新定义;当然,C代码也可以调用C代码,并且这种情况将看到原始定义。)
我正在模糊地考虑修补C代码并重新编译Emacs以提供适当的消息抑制功能。我实际上并不需要该功能,但是可能证明这是一个有趣的练习,特别是因为我不是C黑客。同时,我想出了一些建议,将它们放到一个文件中(包含在您的一个init文件中并根据您的喜好进行定制),将抑制源自Lisp代码的消息,这些消息与您列出的要抑制的字符串完全匹配。只要启用了抑制,这些消息就永远不会出现在迷你缓冲区中。您还可以选择是否也从*Messages*
缓冲区中禁止它们。
;; message-suppression.el
;; a quick hack by Aaron (me@aaron-miller.me), 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)
我已经对此进行了测试,以处理实际上是从Lisp代码生成的消息,例如,当您给它提供空字符串参数时,DESCRIBE-FUNCTION会回显“您未指定函数”的投诉。不幸的是,您提到的要禁止显示的消息,例如“ Beginning of buffer”,“ End of buffer”和“ Text is read-only”,似乎都是源自C代码,这意味着您将无法用这种方法压制它们。
如果我确实了解源代码补丁,那么它(可能)将针对Emacs 24.3,并且我将使用有关如何使用它的信息来更新此答案。
在Emacs 25以及可能在某些早期版本中,执行此操作的最简单方法如下:
首先定义:
(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))))
然后,如果要禁止显示some-function
您生成的所有消息,请执行以下操作:
(advice-add 'some-function :around #'suppress-messages)
例如,通过编写以下代码来抑制函数ispell-kill-ispell
(在中ispell.el.gz
)产生的消息“ Ispell process killed” :
(advice-add 'ispell-kill-ispell :around #'suppress-messages)
如果您需要重新启用消息,请运行:
(advice-remove 'some-function #'suppress-messages)
需要注意的几件事:
1)some-function
该函数产生的所有消息以及任何lisp函数产生的所有消息都将被抑制。
2)由C代码产生的消息将不会被抑制,但这可能是最好的。
3)您需要确保文件-*- lexical-binding: t -*-
的第一行中包含该.el
文件。
但是,如何找出调用了哪个函数message
呢?您可以按照其他人的建议遍历代码,但是让Emacs为您完成工作更容易。
如果您定义:
(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))))
然后执行:
(advice-add 'message :around #'who-called-me?)
您将获得回溯信息添加到消息。由此,您可以轻松查看消息的生成位置。
您可以使用以下方法来扭转这种情况:
(advice-remove 'message #'who-called-me?)
一种替代方法是建议message
功能并进行测试,以查看是否要打印消息。如果所讨论的消息是固定字符串,这很简单。例如,为了禁止“ Ispell进程被杀死”,您可以定义:
(defun suppress-ispell-message (old-fun format &rest args)
(if (string= format "Ispell process killed")
(ignore)
(apply old-fun format args)))
然后执行:
(advice-add 'message :around #'suppress-ispell-message)
如果消息很复杂,这种方法很快就会变得很混乱。
您显然正在寻求一种方法来有选择地禁止某些消息。答案是,您需要重新定义或建议发出那些特定消息的代码。
要阻止所有消息(例如在某些代码持续时间内),可以使用flet
或cl-flet
将函数message
本地重新定义为(function)ignore
。或者使用中所使用的技术edt-electric-helpify
:保存的原始定义message
,fset
来ignore
,重新fset
回原来的高清(虽然它是更好地使用unwind-protect
,如果你这样做)。
grep
或A
Dired。在Emacs Lisp源文件中搜索错误消息文本(如果可用,还可以在Emacs C文件中搜索)。HTH。
这适用于取消“缓冲区开始”和“缓冲区结束”,并且不需要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))))
受https://lists.gnu.org/archive/html/help-gnu-emacs/2015-12/msg00189.html的启发,但使用“ defadvice”以获得更多兼容性。