Emacs - Désactiver certains messages du mini-tampon


20

Dans Emacs, il y a des cas où j'aimerais empêcher les messages d'apparaître dans le mini-tampon, concernant principalement "Début / Fin du tampon" et "Le texte est en lecture seule".

Existe-t-il un moyen d'empêcher ces messages d'apparaître dans le mini-tampon?

De plus, y a-t-il une raison importante pour laquelle je ne voudrais pas les désactiver? À première vue, je peux tout aussi facilement regarder le numéro de ligne et l'état d'écriture du tampon sur la modélisation.


2
Il n'y a aucune raison pour que vous ayez besoin de ces messages, non. La raison pour laquelle ces messages existent est d'essayer de vous assurer que chaque commande a un effet visible: lorsque l'effet visible attendu de la commande ne peut pas être exécuté, nous émettons plutôt un message, vous pouvez donc dire que la commande a bien été exécutée.
Stefan

Réponses:


21

Dans Emacs 25, vous pouvez supprimer les messages du mini-tampon en établissant une liaison inhibit-messageavec une valeur non nulle:

(let ((inhibit-message t))
  (message "Listen to me, you!"))

Est-ce que cela fonctionne aussi sur les primitives appelées depuis C?
Aaron Miller

1
Il devrait, comme la fonction C l' message1appelle message3, respecter cette variable.
Jackson

Utile pour supprimer le message ennuyeux mu4e "Retreiving mail ...":(let ((inhibit-message t)) (message make-progress-reporter))
manandearth

1
Cela ne fonctionne pas pour moi sur Emacs 26.1, curieusement. Une idée pourquoi?
Christian Hudon

1
@ChristianHudon Je viens de tester dans Emacs 26.1 et master sans fichier init, et cela fonctionne pour moi dans les deux endroits. Notez que messagerenvoie la chaîne de message, donc peut-être que vous voyez la chaîne renvoyée lors de l'évaluation du code. Si vous évaluez ce code dans une liaison de touches, aucun message ne sera imprimé (sauf dans le tampon Messages ).
Jackson

9

Vous pouvez en quelque sorte le faire à partir du code Lisp. Pourquoi "en quelque sorte"? Parce que MESSAGE est une primitive, définie en C, au lieu d'une fonction Lisp, et, selon le manuel de référence Emacs Lisp , les appels aux primitives du code C ignorent les conseils.

Par conséquent, afin de vraiment faire un bon travail d'implémentation de la fonctionnalité que vous désirez, vous devrez redéfinir la primitive MESSAGE en tant que fonction Lisp; une fois que vous l'avez fait, vous pouvez ensuite le conseiller avec du code qui obtient la chaîne que MESSAGE ferait écho au mini-tampon, le compare avec une liste de messages que vous ne voulez pas voir, puis appelle ou n'appelle pas MESSAGE selon sur le résultat. En théorie, cela pourrait être accompli par exemple (defvar *message-prim* (symbol-function 'message)), puis (defun message (format &rest args) ... (funcall *message-prim* format args))- mais SYMBOL-FUNCTION avec un argument primitif renvoie quelque chose qui n'est pas réellement appelable, donc FUNCALL signale une condition VOID-FUNCTION.

Cependant, même si cela fonctionnait, cela ne ferait toujours pas vraiment l'affaire, car la redéfinition d'une primitive garantit uniquement que la redéfinition sera utilisée lorsque la fonction sera appelée à partir du code Lisp; les appels en code C peuvent toujours utiliser la définition primitive . (Il est possible que le code C appelle dans Emacs Lisp, et de tels cas verront la redéfinition; il est également possible, bien sûr, que le code C appelle le code C, et ces cas verront la définition d'origine.)

J'envisage vaguement de patcher le code C et de recompiler Emacs pour fournir une fonctionnalité de suppression des messages appropriée; Je n'ai pas vraiment besoin de cette fonctionnalité, mais cela pourrait s'avérer un exercice intéressant, d'autant plus que je ne suis pas un hacker C. En attendant, voici quelque chose que j'ai concocté qui, lorsqu'il est déposé dans un fichier, inclus dans l'un de vos fichiers init et personnalisé à votre goût, supprimera les messages provenant du code Lisp qui correspondent exactement aux chaînes que vous répertoriez pour la suppression. Tant que la suppression est activée, ces messages n'apparaîtront jamais dans le mini-tampon; vous avez la possibilité de les supprimer également du *Messages*tampon.

;; 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)

J'ai testé cela pour travailler avec des messages qui sont réellement générés à partir du code Lisp, par exemple la plainte "Vous n'avez pas spécifié de fonction" renvoyée par DESCRIBE-FUNCTION lorsque vous lui donnez un argument de chaîne vide. Malheureusement, les messages que vous mentionnez vouloir supprimer, tels que "Début du tampon", "Fin du tampon" et "Le texte est en lecture seule", semblent tous provenir du code C, ce qui signifie que vous ne pourrez pas les supprimer par cette méthode.

Si jamais je passe au patch source, ce sera (probablement) contre Emacs 24.3 , et je mettrai à jour cette réponse avec des informations sur la façon de l'utiliser.


8

Dans Emacs 25 et probablement dans certaines versions antérieures, la façon la plus simple de procéder est la suivante:

Définissez d'abord:

(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))))

Ensuite, si vous souhaitez supprimer tous les messages produits par some-functionvous, procédez comme suit:

(advice-add 'some-function :around #'suppress-messages)

Par exemple, je supprime le message "Processus Ispell tué" produit par la fonction ispell-kill-ispell(in ispell.el.gz) en écrivant:

(advice-add 'ispell-kill-ispell :around #'suppress-messages)

Si vous devez réactiver les messages, exécutez:

(advice-remove 'some-function #'suppress-messages)

Quelques points à noter:

1) Tous les messages produits par some-functionseront supprimés, tout comme tous les messages produits par toute fonction lisp appelée par la fonction.

2) Les messages produits par le code C ne seront pas supprimés mais c'est probablement tout pour le mieux.

3) Vous devez vous assurer qu'il -*- lexical-binding: t -*-est contenu dans la première ligne de votre .elfichier.

Mais comment savoir quelle fonction s'appelle message? Vous pouvez parcourir le code comme quelqu'un d'autre l'a suggéré, mais il est plus facile de laisser Emacs faire le travail pour vous.

Si vous définissez:

(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))))

puis faites:

(advice-add 'message :around #'who-called-me?)

vous obtiendrez une trace ajoutée au message. De là, vous pouvez facilement voir où le message a été généré.

Vous pouvez inverser cela avec:

(advice-remove 'message #'who-called-me?)

Une autre approche serait de conseiller la messagefonction et de tester pour voir si vous souhaitez imprimer le message ou non. C'est simple si le message en question est une chaîne fixe. Par exemple, pour supprimer le "processus Ispell tué", vous pouvez définir:

(defun suppress-ispell-message (old-fun format &rest args)
  (if (string= format "Ispell process killed")
         (ignore)
    (apply old-fun format args)))

puis faites:

(advice-add 'message :around #'suppress-ispell-message)

Cette approche devient rapidement très compliquée si le message est compliqué.


3

Vous demandez apparemment un moyen d' inhiber sélectivement certains messages. La réponse à cela est que vous devrez redéfinir ou conseiller le code qui émet ces messages particuliers .

Pour empêcher tous les messages, par exemple pendant la durée d'un code, vous pouvez utiliser fletou cl-fletpour redéfinir la fonction messagelocalement en (fonction) ignore. Ou utilisez la technique utilisée dans edt-electric-helpify: enregistrez la définition d'origine de message, fsetpour ignore, fsetrevenir à la définition d' origine (bien qu'il soit préférable de l'utiliser unwind-protectsi vous le faites).


Désolé, mais pourriez-vous m'aider sur la façon dont je peux rechercher ces messages d'erreur? À ce stade, on a presque l'impression qu'il est plus difficile de désactiver les messages que de les conserver.
bitflips

1
Pour rechercher «ces messages d'erreur», utilisez grepou Adans Dired. Recherchez le texte du message d'erreur dans les fichiers source Emacs Lisp (et peut-être aussi dans les fichiers Emacs C, si vous les avez disponibles). HTH.
Tiré

2

Cela fonctionne pour supprimer "Début du tampon" et "Fin du tampon" et ne nécessite pas 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))))

Inspiré par https://lists.gnu.org/archive/html/help-gnu-emacs/2015-12/msg00189.html mais utilise "defadvice" pour plus de compatibilité.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.