No Emacs 25, você pode suprimir mensagens de minibuffer ligando inhibit-message
a um valor não-nulo:
(let ((inhibit-message t))
(message "Listen to me, you!"))
No Emacs, há alguns casos em que eu gostaria de evitar que mensagens aparecessem no minibuffer, principalmente pertencentes a "Beginning / End of buffer" e "Text is read-only".
Existe alguma maneira de evitar que essas mensagens apareçam no minibuffer?
Além disso, há alguma razão significativa que eu não queira desabilitar? Pelo seu valor de face, posso facilmente ver o número da linha e o status de gravação do buffer no modeline.
Você pode classificar para fazer isso a partir do código Lisp. Por que "tipo de"? Porque MESSAGE é um primitivo, definido em C, em vez de uma função Lisp, e, de acordo com o manual de referência do Emacs Lisp , as chamadas para primitivos do código C ignoram o aviso.
Portanto, para realmente fazer um trabalho adequado de implementar a funcionalidade que você deseja, você precisaria redefinir a primitiva MESSAGE como uma função Lisp; uma vez que você tenha feito isso, você pode avisar com o código que obtém a string MESSAGE echo para o minibuffer, compara com uma lista de mensagens que você não quer ver, e então chama ou não chama MESSAGE dependendo no resultado. Em teoria, isto poderia ser realizado por, e. (defvar *message-prim* (symbol-function 'message))
, e depois (defun message (format &rest args) ... (funcall *message-prim* format args))
- mas SYMBOL-FUNCTION dado um argumento primitivo retorna algo que não é realmente chamado, então a FUNCALL sinaliza uma condição de VOID-FUNCTION.
No entanto, mesmo que isso funcionasse, ainda assim não funcionaria, porque redefinir um primitivo só garante que a redefinição será usada quando a função for chamada do código Lisp; chamadas no código C ainda podem usar a definição primitiva . (É possível para o código C chamar o Emacs Lisp, e tais casos verão a redefinição; também é possível, é claro, que o código C chame o código C, e tais casos verão a definição original.)
Estou vagamente pensando em corrigir o código C e recompilar o Emacs para fornecer a funcionalidade adequada de supressão de mensagens; Eu realmente não preciso dessa funcionalidade, mas pode ser um exercício interessante, especialmente porque eu não sou um hacker C. Enquanto isso, aqui está algo que eu criei e que, quando colocado em um arquivo, incluído em um de seus arquivos init, e personalizado ao seu gosto, suprimirá mensagens originadas do código Lisp que correspondem exatamente às strings listadas para a supressão. Enquanto a supressão estiver ativada, essas mensagens nunca aparecerão no minibuffer; você tem a opção de suprimi-los do buffer *Messages*
também.
;; 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)
Eu testei isso para trabalhar com mensagens que são realmente geradas a partir do código Lisp, por exemplo a queixa "Você não especificou uma função" ecoado por DESCRIBE-FUNCTION quando você dá a ele um argumento de seqüência de caracteres vazia. Infelizmente, as mensagens que você mencionou querendo suprimir, como "Início do buffer", "Fim do buffer" e "O texto é somente leitura", aparecem todas originadas do código C, o que significa que você não conseguirá suprimi-los por este método.
Se eu chegar ao patch de origem, ele (provavelmente) será contra Emacs 24.3 , e atualizarei esta resposta com informações sobre como usá-la.
No Emacs 25 e provavelmente em algumas versões anteriores, a maneira mais limpa de fazer isso é a seguinte:
Primeiro defina:
(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))))
Então, se você quiser suprimir todas as mensagens produzidas por some-function
, faça:
(advice-add 'some-function :around #'suppress-messages)
Por exemplo, eu suprimo a mensagem "Ispell process killed" produzida pela função ispell-kill-ispell
(em ispell.el.gz
) escrevendo:
(advice-add 'ispell-kill-ispell :around #'suppress-messages)
Se você precisar reativar as mensagens, execute:
(advice-remove 'some-function #'suppress-messages)
Algumas das coisas a serem observadas:
1) Todas as mensagens produzidas por some-function
serão suprimidas, assim como todas as mensagens produzidas por qualquer função lisp que a função chamar.
2) As mensagens produzidas pelo código C não serão suprimidas, mas isso provavelmente é tudo para o melhor.
3) Você precisa ter certeza de que -*- lexical-binding: t -*-
está contido na primeira linha do seu arquivo .el
.
Mas como você descobre qual função chamada message
? Você pode usar o código como outra pessoa sugeriu, mas é mais fácil deixar o Emacs fazer o trabalho para você.
Se você definir:
(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))))
e faça:
(advice-add 'message :around #'who-called-me?)
você receberá um backtrace adicionado à mensagem. Com isso, você pode ver facilmente onde a mensagem foi gerada.
Você pode reverter isso com:
(advice-remove 'message #'who-called-me?)
Uma abordagem alternativa seria aconselhar a função message
e testar para ver se você deseja imprimir a mensagem ou não. Isso é simples se a mensagem em questão for uma string fixa. Por exemplo. para suprimir "processo ispell morto" você poderia definir:
(defun suppress-ispell-message (old-fun format &rest args)
(if (string= format "Ispell process killed")
(ignore)
(apply old-fun format args)))
e faça:
(advice-add 'message :around #'suppress-ispell-message)
Essa abordagem logo fica muito confusa se a mensagem for complicada.
Você está aparentemente pedindo uma maneira de seletivamente inibir determinadas mensagens. A resposta para isso é que você precisaria redefinir ou aconselhar o código que emite aquelas mensagens específicas.
Para evitar todas mensagens, por exemplo, para a duração de algum código, você pode usar flet
ou cl-flet
para redefinir a função message
localmente para (função) ignore
. Ou use a técnica usada em edt-electric-helpify
: salve a definição original de message
, fset
to ignore
, re fset
de volta ao def original (embora seja melhor usar unwind-protect
se você faça isso.
Isso funciona para suprimir "Beginning of buffer" e "End of buffer" e não requer o 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))))
Inspirado pelo link , mas usa "defadvice" para mais compatibilidade.
Tags emacs