Emacs - Desabilita algumas mensagens do Minibuffer

17

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.

    
por mellowmaroon 05.11.2013 / 07:01

5 respostas

18

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!"))
    
por 14.06.2015 / 19:23
8

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.

    
por 12.11.2013 / 23:00
6

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.

    
por 13.01.2016 / 16:07
3

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.

    
por 05.11.2013 / 16:51
2

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.

    
por 16.05.2016 / 22:50

Tags