Emacs - Bazı Minibuffer Mesajlarını Devre Dışı Bırak


20

Emacs'ta, mesajların minibuffer'da görünmesini önlemek istediğim, çoğunlukla "Arabellek Başlangıcı / Sonu" ve "Metin salt okunur" ile ilgili bazı durumlar vardır.

Bu mesajların minibuffer'da görünmesini engelleyebilmemin bir yolu var mı?

Ayrıca, bunları devre dışı bırakmak istemememin önemli bir nedeni var mı? Yüz değerinde, modelde satır numarasına ve arabellek yazma durumuna kolayca bakabilirim.


2
Bu mesajlara ihtiyaç duymanız için hiçbir neden yok, hayır. Bu iletilerin var olmasının nedeni, her komutun görünür bir etkiye sahip olduğundan emin olmaktır: komutun beklenen görünür etkisi gerçekleştirilemediğinde, bunun yerine bir mesaj göndeririz, böylece komutun gerçekten çalıştırıldığını söyleyebilirsiniz.
Stefan

Yanıtlar:


21

Emacs 25'te, inhibit-messagenil olmayan bir değere bağlanarak minibuffer mesajlarını engelleyebilirsiniz :

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

Bu C denilen ilkel öğeler üzerinde de çalışıyor mu?
Aaron Miller

1
C işlevinin message1çağırdığı gibi message3, bu değişkene saygı duymalıdır .
Jackson

Can sıkıcı mu4e "Posta alınıyor ..." mesajını bastırmak için yararlı:(let ((inhibit-message t)) (message make-progress-reporter))
manandearth

1
Bu benim için Emacs 26.1'de işe yaramaz, garip bir şekilde. Neden olduğu hakkında bir fikrin var mı?
Christian Hudon

1
@ChristianHudon Emacs 26.1'de test ettim ve init dosyası olmadan master yaptım ve her iki yerde de benim için çalışıyor. messageİleti dizesini döndürdüğünü unutmayın , bu nedenle kodu değerlendirirken döndürülen dizeyi görüyor olabilirsiniz. Bu kodu bir tuş bağlamada değerlendirirseniz, hiçbir ileti yazdırılmaz ( Mesajlar arabelleği hariç ).
Jackson

9

Sen edebilirsiniz çeşit Lisp koddan bunu. Neden "bir çeşit"? MESSAGE, Lisp işlevi yerine C'de tanımlanan bir ilkel olduğundan ve Emacs Lisp başvuru kılavuzuna göre , C kodundan gelen ilkel çağrıları önerileri yok sayar.

Bu nedenle, arzu ettiğiniz işlevselliği uygulamak için gerçekten uygun bir iş yapmak için MESSAGE ilkelini Lisp işlevi olarak yeniden tanımlamanız gerekir; bunu yaptıktan sonra, MESSAGE dizisinin yankılanmasını, görmek istemediğiniz mesajların bir listesini karşılaştırmasını sağlar ve ardından MESSAGE'yi arar veya çağırmaz. sonuç. Teorik olarak, bu, örneğin (defvar *message-prim* (symbol-function 'message)), ve sonra (defun message (format &rest args) ... (funcall *message-prim* format args))- ile gerçekleştirilebilir , ancak ilkel bir argüman verildiğinde SYMBOL-FUNCTION, aslında çağrılabilir olmayan bir şey döndürür, bu nedenle FUNCALL bir VOID-FUNCTION durumunu işaret eder.

Ancak, bu işe yarasa bile, yine de hile yapmaz, çünkü ilkel yeniden tanımlamak, işlev Lisp kodundan çağrıldığında yeniden tanımlamanın kullanılacağını garanti eder; C kodundaki çağrılar ilkel tanımı kullanmaya devam edebilir . (C kodunun Emacs Lisp'i çağırması mümkündür ve bu gibi durumlar yeniden tanımlamayı görür; elbette C kodunun C kodunu çağırması da mümkündür ve bu gibi durumlar orijinal tanımı görecektir.)

Belirsiz C kodu yama ve uygun ileti bastırma işlevselliği sağlamak için Emacs yeniden derleme düşünüyor; Bu işlevselliğe gerçekten ihtiyacım yok, ama özellikle C hacker olmadığım için ilginç bir egzersiz olabilir. Bu arada, bir dosyaya düştüğünüzde, init dosyalarınızdan birisine dahil edilen ve zevkinize göre özelleştirilen, çırptığım bir şey var. Bastırma etkin olduğu sürece, bu mesajlar asla minibuffer'da görünmez; onları *Messages*tampondan da bastırma seçeneğiniz vardır .

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

Ben aslında boş bir dize argümanı verirken DESCRIBE-FUNCTION tarafından yankılanan "Bir işlev belirtmediniz" şikayeti aslında Lisp kodundan oluşturulan mesajlarla çalışmak için test ettim. Ne yazık ki, "Arabelleğin başlangıcı", "Arabellek sonu" ve "Metin salt okunur" gibi bastırmak istediğiniz iletilerin tümü C kodundan kaynaklanıyor gibi görünüyor, yani bunları bu yöntemle bastırın.

Kaynak yamaya geçersem, (muhtemelen) Emacs 24.3'e karşı olacak ve bu cevabı nasıl kullanacağınızla ilgili bilgilerle güncelleyeceğim.


8

Emacs 25 ve muhtemelen bazı önceki sürümlerde, bunu yapmanın en temiz yolu aşağıdaki gibidir:

İlk önce şunları tanımlayın:

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

Sonra, ürettiğiniz tüm mesajları bastırmak some-functionistiyorsanız:

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

Örneğin, işlev tarafından ispell-kill-ispell(içinde ispell.el.gz) üretilen "Ispell işlemi öldürüldü" mesajını yazarak bastırıyorum :

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

Mesajları yeniden etkinleştirmeniz gerekiyorsa, çalıştırın:

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

Unutulmaması gereken birkaç nokta:

1) tarafından üretilen tüm mesajlar some-function Tarafından üretilen tüm mesajlar, herhangi bir lisp tarafından üretilen tüm mesajlar fonksiyonun çağırdığı gibi bastırılır.

2) C kodu tarafından üretilen iletiler bastırılmaz, ancak muhtemelen en iyisi budur.

3) Emin olun gerekir -*- lexical-binding: t -*-ilk satırında bulunan.el Dosyanızın .

Ama hangi fonksiyonun aradığını nasıl bulabilirsin? message ? Başka birinin önerdiği gibi kodu gözden geçirebilirsiniz, ancak Emacs'ın işi sizin için yapmasına izin vermek daha kolaydır.

Tanımlarsanız:

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

ve sonra:

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

mesaja bir geri izleme eklenir. Buradan mesajın nerede oluşturulduğunu kolayca görebilirsiniz.

Bunu şununla tersine çevirebilirsiniz:

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

Alternatif bir yaklaşım, messagefonksiyona tavsiyede bulunmak ve mesajı yazdırmak isteyip istemediğinizi test etmek olacaktır. Söz konusu mesaj sabit bir dize ise bu basittir. Örneğin, "Ispell süreci öldürüldü" yi bastırmak için şunları tanımlayabilirsiniz:

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

ve sonra:

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

Mesaj karmaşık bir şeyse bu yaklaşım çok dağınık hale gelir.


3

Görünüşe göre belirli mesajları seçici olarak engellemenin bir yolunu istiyorsun . Bunun cevabı, bu belirli mesajları veren kodu yeniden tanımlamanız veya tavsiye etmeniz gerektiğidir .

Önlemek için tüm mesajlar, bazı kodlar süresince örneğin, kullanabilir fletveya cl-fletişlevini yeniden tanımlamak için message(fonksiyon) yerel olarak ignore. Veya kullanılan tekniği kullanmak edt-electric-helpify: orijinal tanımı kaydetme message, fsetiçin ignore, yeniden fset(o kullanmak daha iyidir olsa tekrar orijinal def bunu unwind-protectbunu varsa).


Maalesef, bu hata mesajlarını nasıl arayabileceğim konusunda bana yardımcı olabilir misiniz? Bu noktada, mesajları devre dışı bırakmaktan daha fazla sorun çıkarıyormuş gibi geliyor.
bitflips

1
"Bu hata mesajlarını" aramak için Dired grepveya ADired öğelerini kullanın . Hata iletisi metnini Emacs Lisp kaynak dosyalarında (ve eğer varsa, Emacs C dosyalarında da) arayın. HTH.
Drew

2

Bu "Tamponun başlangıcı" ve "Tampon sonu" nun baskılanması için çalışır ve emacs 25 gerektirmez.

; 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'den esinlenerek daha fazla uyumluluk için "defadvice" kullanılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.