22 emacs
在 Emacs 中,在某些情况下,我希望防止消息出现在迷你缓冲区中,主要与“缓冲区的开始/结束”和“文本是只读的”有关。
有什么办法可以防止这些消息出现在小缓冲区中吗?
另外,是否有一些重要的原因我可能不想禁用这些?从表面上看,我可以很容易地查看模式行上的行号和缓冲区写入状态。
Jac*_*son 22
在 Emacs 25 中,您可以通过绑定inhibit-message到非 nil 值来抑制 minibuffer 消息:
(let ((inhibit-message t))
(message "Listen to me, you!"))
Run Code Online (Sandbox Code Playgroud)
在 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))))
Run Code Online (Sandbox Code Playgroud)
然后,如果您想抑制some-function您产生的所有消息,请执行以下操作:
(advice-add 'some-function :around #'suppress-messages)
Run Code Online (Sandbox Code Playgroud)
例如,我通过编写以下命令来抑制由函数ispell-kill-ispell(in ispell.el.gz)产生的消息“Ispell 进程被杀死” :
(advice-add 'ispell-kill-ispell :around #'suppress-messages)
Run Code Online (Sandbox Code Playgroud)
如果您需要重新启用消息,请运行:
(advice-remove 'some-function #'suppress-messages)
Run Code Online (Sandbox Code Playgroud)
需要注意的几点:
1) 产生的所有消息some-function都将被抑制,函数调用的任何 lisp 函数产生的所有消息也将被抑制。
2) C 代码生成的消息不会被抑制,但这可能是最好的。
3)您需要确保-*- lexical-binding: t -*-包含在.el文件的第一行中。
但是你如何找出调用了哪个函数message呢?您可以按照其他人的建议对代码进行 grep,但让 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))))
Run Code Online (Sandbox Code Playgroud)
然后做:
(advice-add 'message :around #'who-called-me?)
Run Code Online (Sandbox Code Playgroud)
您将在消息中添加一个回溯。从中您可以轻松看到消息的生成位置。
您可以通过以下方式扭转这一点:
(advice-remove 'message #'who-called-me?)
Run Code Online (Sandbox Code Playgroud)
另一种方法是建议message函数并测试是否要打印消息。如果所讨论的消息是固定字符串,这很简单。例如,要抑制“Ispell 进程被杀死”,您可以定义:
(defun suppress-ispell-message (old-fun format &rest args)
(if (string= format "Ispell process killed")
(ignore)
(apply old-fun format args)))
Run Code Online (Sandbox Code Playgroud)
然后做:
(advice-add 'message :around #'suppress-ispell-message)
Run Code Online (Sandbox Code Playgroud)
如果消息很复杂,这种方法很快就会变得非常混乱。
你可以从 Lisp 代码中做到这一点。为什么是“某种”?因为 MESSAGE 是一个原语,在 C 中定义,而不是 Lisp 函数,并且根据 Emacs Lisp 参考手册,从 C 代码调用原语会忽略建议。
因此,为了真正正确地实现您想要的功能,您需要将 MESSAGE 原语重新定义为 Lisp 函数;完成此操作后,您可以使用获取字符串 MESSAGE 的代码通知它会回显到迷你缓冲区,将其与您不想看到的消息列表进行比较,然后调用或不调用 MESSAGE 取决于结果上。理论上,这可以通过 eg 来完成(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)
Run Code Online (Sandbox Code Playgroud)
我已经测试过它可以处理实际从 Lisp 代码生成的消息,例如,当你给它一个空字符串参数时,DESCRIBE-FUNCTION 回应的“你没有指定函数”抱怨。不幸的是,您提到要抑制的消息,例如“缓冲区开始”、“缓冲区结束”和“文本是只读的”,似乎都源自 C 代码,这意味着您将无法用这种方法压制它们。
如果我真的解决了源补丁,它(可能)会针对Emacs 24.3,我将使用有关如何使用它的信息更新此答案。
| 归档时间: |
|
| 查看次数: |
4263 次 |
| 最近记录: |