Emacs - Deaktivieren Sie einige Minibuffer-Meldungen

20

In Emacs gibt es einige Fälle, in denen ich verhindern möchte, dass Nachrichten im Minipuffer angezeigt werden, hauptsächlich in Bezug auf "Anfang / Ende des Puffers" und "Text ist schreibgeschützt".

Kann ich auf irgendeine Weise verhindern, dass diese Meldungen im Minipuffer angezeigt werden?

Gibt es auch einen wichtigen Grund, warum ich diese möglicherweise nicht deaktivieren möchte? Beim Nennwert kann ich genauso gut die Zeilennummer und den Pufferschreibstatus auf der Modeline anzeigen.

Bitflips
quelle
2
Es gibt keinen Grund, warum Sie diese Nachrichten brauchen würden, nein. Der Grund, warum diese Meldungen vorhanden sind, besteht darin, sicherzustellen, dass jeder Befehl einen sichtbaren Effekt aufweist: Wenn der erwartete sichtbare Effekt des Befehls nicht ausgeführt werden kann, wird stattdessen eine Meldung ausgegeben, damit Sie erkennen können, dass der Befehl tatsächlich ausgeführt wurde.
Stefan

Antworten:

21

In Emacs 25 können Sie Minibuffer-Meldungen unterdrücken, indem Sie inhibit-messagean einen Wert ohne Null binden :

(let ((inhibit-message t))
  (message "Listen to me, you!"))
Jackson
quelle
Funktioniert dies auch mit Primitiven, die von C aufgerufen werden?
Aaron Miller
1
Es sollte, wie die C-Funktion message1aufruft message3, diese Variable berücksichtigen.
Jackson
Nützlich zum Unterdrücken der lästigen mu4e-Nachricht "Retreiving mail ...":(let ((inhibit-message t)) (message make-progress-reporter))
manandearth
1
Auf Emacs 26.1 funktioniert das seltsamerweise nicht. Irgendeine Idee warum?
Christian Hudon
1
@ChristianHudon Ich habe gerade in Emacs 26.1 und Master ohne Init-Datei getestet, und es funktioniert für mich an beiden Orten. Beachten Sie, dass messagedie Nachrichtenzeichenfolge zurückgegeben wird. Möglicherweise wird die zurückgegebene Zeichenfolge bei der Auswertung des Codes angezeigt. Wenn Sie diesen Code in einer Tastenkombination auswerten, wird keine Nachricht gedruckt (außer im Nachrichtenpuffer ).
Jackson
9

Sie können eine Art dieser Code von Lisp tun. Warum "irgendwie"? Da MESSAGE ein Primitiv ist, das in C anstelle einer Lisp-Funktion definiert ist und gemäß dem Emacs Lisp-Referenzhandbuch Aufrufe von Primitiven aus C-Code ignoriert.

Um die von Ihnen gewünschte Funktionalität wirklich zu implementieren, müssen Sie daher das MESSAGE-Grundelement als Lisp-Funktion neu definieren. Sobald Sie dies getan haben, können Sie es mit Code beraten, der die Zeichenfolge MESSAGE erhält, die an den Minipuffer zurückgemeldet wird, es mit einer Liste von Nachrichten vergleicht, die Sie nicht sehen möchten, und dann MESSAGE abhängig aufruft oder nicht aufruft auf das Ergebnis. Theoretisch könnte dies z. B. (defvar *message-prim* (symbol-function 'message))durch und dann erreicht werden (defun message (format &rest args) ... (funcall *message-prim* format args))- aber SYMBOL-FUNCTION gibt bei einem primitiven Argument etwas zurück, das eigentlich nicht aufrufbar ist, sodass der FUNCALL eine VOID-FUNCTION-Bedingung signalisiert.

Aber selbst wenn das funktioniert hätte, würde es den Trick nicht wirklich machen, da das Neudefinieren eines Primitivs nur garantiert, dass die Neudefinition verwendet wird, wenn die Funktion aus Lisp-Code aufgerufen wird. Aufrufe in C-Code können weiterhin die primitive Definition verwenden . (Es ist möglich, dass C-Code in Emacs Lisp aufgerufen wird, und in solchen Fällen wird die Neudefinition angezeigt. Natürlich kann C-Code auch C-Code aufrufen, und in solchen Fällen wird die ursprüngliche Definition angezeigt.)

Ich denke vage darüber nach, den C-Code zu patchen und Emacs neu zu kompilieren, um eine ordnungsgemäße Funktion zur Unterdrückung von Nachrichten bereitzustellen. Ich brauche diese Funktionalität nicht wirklich, aber sie könnte sich als interessante Übung erweisen, zumal ich kein C-Hacker bin. In der Zwischenzeit habe ich Folgendes hinzugefügt, das beim Ablegen in eine Datei, die aus einer Ihrer Init-Dateien stammt und auf Ihren Geschmack zugeschnitten ist, Meldungen aus dem Lisp-Code unterdrückt, die genau mit den Zeichenfolgen übereinstimmen, die Sie zur Unterdrückung auflisten. Solange die Unterdrückung aktiviert ist, werden diese Meldungen niemals im Minipuffer angezeigt. Sie haben die Möglichkeit, sie auch aus dem *Messages*Puffer zu unterdrücken .

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

Ich habe dies getestet, um mit Nachrichten zu arbeiten, die tatsächlich aus Lisp-Code generiert wurden, z. B. der Beschwerde "Sie haben keine Funktion angegeben", die von DESCRIBE-FUNCTION wiederholt wird, wenn Sie ein leeres Zeichenfolgenargument angeben. Leider scheinen alle Nachrichten, die Sie unterdrücken möchten, wie "Beginn des Puffers", "Ende des Puffers" und "Text ist schreibgeschützt", vom C-Code zu stammen, was bedeutet, dass Sie dies nicht können unterdrücken sie durch diese Methode.

Wenn ich jemals zum Quell-Patch komme, wird es (wahrscheinlich) gegen Emacs 24.3 sein , und ich werde diese Antwort mit Informationen darüber aktualisieren, wie man damit umgeht.

Aaron Miller
quelle
8

In Emacs 25 und wahrscheinlich in früheren Versionen ist dies am saubersten wie folgt:

Zuerst definieren Sie:

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

Wenn Sie dann alle von some-functionIhnen erstellten Nachrichten unterdrücken möchten, gehen Sie wie folgt vor:

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

Zum Beispiel unterdrücke ich die Nachricht "Ispell process killed", die von der Funktion ispell-kill-ispell(in ispell.el.gz) erzeugt wurde, indem ich schreibe:

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

Wenn Sie die Nachrichten jemals wieder aktivieren müssen, führen Sie Folgendes aus:

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

Ein paar Dinge zu beachten:

1) Alle von erzeugten Nachrichten some-functionwerden unterdrückt, ebenso wie alle Nachrichten, die von einer von der Funktion aufgerufenen lisp-Funktion erzeugt werden.

2) Mit C-Code erzeugte Nachrichten werden nicht unterdrückt, aber das ist wahrscheinlich das Beste.

3) Sie müssen sicherstellen, dass -*- lexical-binding: t -*-in der ersten Zeile Ihrer .elDatei enthalten ist.

Aber wie findet man heraus, welche Funktion aufgerufen wird message? Sie könnten den Code durchgehen, wie jemand anderes vorgeschlagen hat, aber es ist einfacher, Emacs die Arbeit für Sie erledigen zu lassen.

Wenn Sie definieren:

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

und dann mache:

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

Sie erhalten eine Rückverfolgung zur Nachricht hinzugefügt. Daran können Sie leicht erkennen, wo die Nachricht generiert wurde.

Sie können dies umkehren mit:

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

Ein alternativer Ansatz wäre, die messageFunktion zu beraten und zu testen, ob Sie die Nachricht drucken möchten oder nicht. Dies ist einfach, wenn die betreffende Nachricht eine feste Zeichenfolge ist. Um beispielsweise "Ispell-Prozess beendet" zu unterdrücken, können Sie Folgendes definieren:

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

und dann mache:

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

Dieser Ansatz wird bald sehr unübersichtlich, wenn die Nachricht etwas Kompliziertes ist.

Bernard Hurley
quelle
3

Sie fragen anscheinend nach einer Möglichkeit, bestimmte Nachrichten selektiv zu sperren . Die Antwort darauf ist, dass Sie den Code, der diese bestimmten Nachrichten ausgibt, neu definieren oder empfehlen müssen .

Um alle Meldungen, beispielsweise für die Dauer eines Codes, zu verhindern , können Sie mit fletoder cl-fletdie Funktion messagelokal auf (Funktion) umdefinieren ignore. Oder die Technik in verwendet verwenden edt-electric-helpify: Speichern Sie die ursprüngliche Definition von message, fsetzu ignore, re- fsetes wieder auf den ursprünglichen def (obwohl es besser ist , zu verwenden , unwind-protectwenn Sie das tun).

Drew
quelle
Entschuldigung, aber können Sie mir helfen, wie ich nach diesen Fehlermeldungen suchen kann? An diesem Punkt hat man fast das Gefühl, dass es schwieriger ist, die Nachrichten zu deaktivieren, als sie zu behalten.
Bitflips
1
Verwenden Sie grepoder Ain Dired, um nach "diesen Fehlermeldungen" zu suchen . Suchen Sie nach dem Text der Fehlermeldung in den Emacs Lisp-Quelldateien (und möglicherweise auch in den Emacs C-Dateien, falls verfügbar). HTH.
Drew
2

Dies funktioniert zum Unterdrücken von "Beginn des Puffers" und "Ende des Puffers" und erfordert keinen 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))))

Inspiriert von https://lists.gnu.org/archive/html/help-gnu-emacs/2015-12/msg00189.html , verwendet jedoch "defadvice" für mehr Kompatibilität.

Trogdoro
quelle