Emacs - вимкнення деяких повідомлень про мінібуфер


20

У Emacs є деякі випадки, коли я хотів би запобігти появі повідомлень у мінібуфері, в основному стосуючись «Початок / Кінець буфера» та «Текст лише для читання».

Чи я можу запобігти появі цих повідомлень у minibuffer?

Крім того, чи є якась вагома причина, через яку я не можу не хочу відключити їх? За номіналом я можу так само легко переглядати номер рядка та стан запису в буфер на моделі.


2
Немає причини, чому б вам знадобилися ці повідомлення, ні. Причина цих повідомлень полягає в тому, щоб спробувати переконатися, що кожна команда має якийсь видимий ефект: коли очікуваний видимий ефект команди не може бути виконаний, ми замість цього висилаємо повідомлення, тож ви можете сказати, що команда справді виконувалася.
Стефан

Відповіді:


21

У програмі Emacs 25 ви можете придушити повідомлення про мінібуфер, прив’язавши inhibit-messageдо ненульового значення:

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

Чи працює це і на примітивах, викликаних з C?
Аарон Міллер

1
Вона повинна, як message1закликає функція C message3, яка поважає цю змінну.
Джексон

Корисно для придушення набридливого mu4e повідомлення "Відновлення пошти ...":(let ((inhibit-message t)) (message make-progress-reporter))
manandearth

1
Це не працює для мене на Emacs 26.1, як не дивно. Будь-яка ідея чому?
Крістіан Гудон

1
@ChristianHudon Я щойно перевірив Emacs 26.1 і майстер без файлу init, і він працює для мене в обох місцях. Зверніть увагу, що messageповертає рядок повідомлення, тому, можливо, ви бачите повернуту рядок під час оцінки коду. Якщо ви оцінюєте цей код у палітурці, то жодне повідомлення не надрукується (за винятком буфера повідомлень ).
Джексон

9

Ви можете роду це зробити з коду Lisp. Чому "свого роду"? Оскільки ПОВІДОМЛЕННЯ - це примітив, визначений у C, а не функція Lisp і, відповідно до посібника Emacs Lisp , звертається до примітивів із коду C, ігноруючи поради.

Тому, щоб реально виконати належну роботу по впровадженню потрібної вам функції, вам потрібно було б визначити примітив MESSAGE як функцію Lisp; як тільки ви це зробите, ви можете порадити його з кодом, який отримує рядок MESSAGE, що буде відповідати мінібуферу, порівняти його зі списком повідомлень, які ви не хочете бачити, а потім дзвонить або не дзвонить ПОВІДОМЛЕННЯ залежно за результатом. Теоретично це може бути досягнуто, наприклад (defvar *message-prim* (symbol-function 'message)), і тоді (defun message (format &rest args) ... (funcall *message-prim* format args))- але SYMBOL-FUNCTION, наданий примітивний аргумент, повертає щось, що насправді не можна викликати, тому FUNCALL сигналізує про умову FOUNCTION VOID.

Однак, навіть якщо це спрацювало, воно все-таки не справді зробить трюк, оскільки переозначення примітиву гарантує лише те, що перевизначення буде використано, коли функція викликається з коду Lisp; виклики в коді C все ще можуть використовувати примітивне визначення . (Можливо, що код C зателефонує в Emacs Lisp, і такі випадки побачать переопределення; також, звичайно, можна за кодом C викликати код C, і такі випадки побачать оригінальне визначення.)

Я нечітко розмірковую про виправлення коду С та перекомпіляцію Emacs для забезпечення належної функції придушення повідомлень; Мені не дуже потрібна ця функціональність, але це може виявитися цікавим вправою, тим більше, що я не хакер C. Тим часом, я ось що-небудь зіштовхнув, що після потрапляння у файл, що входить до одного з ваших файлів init та налаштований на ваш смак, придушить повідомлення, що походять з коду 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", вироблене функцією ispell-kill-ispell(in ispell.el.gz), написавши:

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

Якщо вам потрібно буде знову ввімкнути повідомлення, виконайте такі дії:

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

Деякі речі, які слід зазначити:

1) Усі повідомлення, що виробляються, some-functionбудуть придушені, як і всі повідомлення, створені будь-якою функцією lisp, яка викликає функцію.

2) Повідомлення, створені за допомогою коду С, не будуть придушені, але це, мабуть, все найкраще.

3) Вам потрібно переконатися, що -*- lexical-binding: t -*-він міститься в першому рядку вашого .elфайлу.

Але як дізнатися, яку функцію викликали message? Ви можете проглядати код так, як запропонував хтось інший, але простіше дозволити 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 убито" ви можете визначити:

(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: зберегти початкове визначення message, fsetщоб ignore, повторно fsetйого назад до первісного Опру (хоча краще використовувати , unwind-protectякщо ви зробите це).


Вибачте, але чи зможете ви допомогти мені, як я можу шукати ці повідомлення про помилки? На даний момент майже не виникає відчуття, що більше проблем із відключенням повідомлень, ніж збереження їх.
bitflips

1
Для пошуку "цих повідомлень про помилки" використовуйте grepабо Aв 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" для більшої сумісності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.