Emacs-いくつかのミニバッファーメッセージを無効にする


20

Emacsでは、主に「バッファの開始/終了」と「テキストは読み取り専用」に関連するメッセージがミニバッファに表示されないようにしたい場合があります。

これらのメッセージがミニバッファーに表示されないようにする方法はありますか?

また、これらを無効にしたくないかもしれない重要な理由がありますか?額面通りに、モードラインで行番号とバッファー書き込みステータスを簡単に確認できます。


2
これらのメッセージが必要になる理由はありません。これらのメッセージが存在する理由は、すべてのコマンドに何らかの可視効果があることを確認するためです:コマンドの予想される可視効果が実行できない場合、代わりにメッセージを出力するため、コマンドが実際に実行されたことを確認できます。
ステファン

回答:


21

Emacs 25ではinhibit-message、非nil値にバインドすることでミニバッファーメッセージを抑制することができます。

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

これは、Cから呼び出されるプリミティブでも機能しますか?
アーロンミラー

1
C関数message1message3この変数を尊重するを呼び出すため、これは必要です。
ジャクソン

迷惑なmu4e「メールを取得しています...」メッセージを(let ((inhibit-message t)) (message make-progress-reporter))
抑制するのに役立ち

1
これは、Emacs 26.1では動作しませんが、奇妙なことです。理由は何ですか?
クリスチャンハドン

1
@ChristianHudon Emacs 26.1でテストしたところ、initファイルなしでmasterが動作し、両方の場所で動作します。messageはメッセージ文字列を返すことに注意してください。したがって、コードを評価するときに、返された文字列が表示されている可能性があります。キーバインディングでこのコードを評価すると、メッセージは出力されません(メッセージバッファーを除く)。
ジャクソン

9

Lispコードからこれを並べ替えることができます。なぜ「並べ替え」なのですか?MESSAGEはLisp関数の代わりにCで定義されたプリミティブであり、Emacs Lispリファレンスマニュアルに従って、 Cコードからのプリミティブへの呼び出しはアドバイスを無視します。

したがって、希望する機能を実際に適切に実装するには、MESSAGEプリミティブをLisp関数として再定義する必要があります。完了したら、文字列MESSAGEを取得してミニバッファーにエコーするコードを使用してアドバイスし、表示したくないメッセージのリストと比較してから、MESSAGEを呼び出したり呼び出したりしません結果に。理論的には、これは例えば(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ファイルの1つからインクルードされ、好みに合わせてカスタマイズされると、抑制用にリストした文字列に完全に一致する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)

実際にLispコードから生成されたメッセージで動作するようにこれをテストしました。たとえば、空の文字列引数を与えるとDESCRIBE-FUNCTIONによってエコーされる「関数を指定しませんでした」という苦情です。残念ながら、「バッファの始まり」、「バッファの終わり」、「テキストは読み取り専用です」など、抑制したいというメッセージはすべてCコードから発信されているように見えるため、次のことができません。この方法でそれらを抑制します。

ソースパッチにたどり着いた場合、それは(おそらく)Emacs 24.3に反するものであり、使用方法についての情報でこの回答を更新します。


8

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

次に、作成したすべてのメッセージを抑制したい場合some-function

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

たとえば、次のように記述することにより、関数ispell-kill-ispell(in ispell.el.gz)によって生成される「Ispell process killed」というメッセージを抑制します。

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

メッセージを再度有効にする必要がある場合は、次を実行します。

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

注意すべき点がいくつかあります。

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

してから:

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

メッセージにバックトレースが追加されます。これから、メッセージが生成された場所を簡単に確認できます。

これを逆にすることができます:

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

別の方法としては、message機能をアドバイスし、メッセージを印刷するかどうかを確認するテストを行います。問題のメッセージが固定文字列の場合、これは簡単です。たとえば、「Ispell process killed」を抑制するには、次のように定義できます。

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

してから:

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

メッセージが複雑な場合、このアプローチはすぐに非常に面倒になります。


3

特定のメッセージを選択的に禁止する方法を求めているようです。その答えは、それらの特定のメッセージを発行するコードを再定義またはアドバイスする必要があるということです。

たとえば一部のコードの期間中にすべてのメッセージを防ぐには、fletまたはcl-fletを使用して、messageローカルで関数を(関数)に再定義できますignore。またはで使用される技術を使用するedt-electric-helpify:の元の定義保存messagefsetignore、再fset(使用することをお勧めですが、元のDEFにそれをunwind-protectあなたがそれを行う場合)。


申し訳ありませんが、これらのエラーメッセージを検索する方法を教えていただけますか?この時点で、メッセージを保持するよりも、メッセージを無効にするのが難しいように感じます。
ビットフリップ

1
「これらのエラーメッセージ」、使用を検索するgrepAのdiredで。Emacs Lispソースファイルでエラーメッセージテキストを検索します(利用可能な場合はEmacs Cファイルでも検索できます)。HTH。
ドリュー

2

これは、「バッファーの開始」と「バッファーの終了」を抑制するために機能し、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))))

https://lists.gnu.org/archive/html/help-gnu-emacs/2015-12/msg00189.htmlから着想を得ていますが、互換性を高めるために「defadvice」を使用しています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.