이맥스-일부 미니 버퍼 메시지 비활성화


20

Emacs에는 주로 "버퍼 시작 / 종료"및 "텍스트가 읽기 전용"인 미니 버퍼에 메시지가 표시되지 않도록하는 경우가 있습니다.

이러한 메시지가 미니 버퍼에 나타나지 않도록 할 수있는 방법이 있습니까?

또한 이러한 기능을 사용하지 않으려는 중요한 이유가 있습니까? 액면가에서 모델 번호의 행 번호와 버퍼 쓰기 상태를 쉽게 볼 수 있습니다.


2
그 메시지가 필요한 이유는 없습니다. 이러한 메시지가 존재하는 이유는 모든 명령에 가시적 인 효과가 있는지 확인하기위한 것입니다. 명령의 예상되는 가시 효과를 수행 할 수없는 경우 대신 메시지가 표시되므로 명령이 실제로 실행되었음을 알 수 있습니다.
Stefan

답변:


21

Emacs 25에서는 넌 inhibit-message이 아닌 값 에 바인딩 하여 미니 버퍼 메시지를 억제 할 수 있습니다 .

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

이것은 C에서 호출 된 프리미티브에서도 작동합니까?
Aaron Miller

1
C 함수가 message1호출 message3할 때이 변수를 존중해야합니다.
Jackson

성가신 mu4e "메일 수신 중 ..."메시지를 억제하는 데 유용 :(let ((inhibit-message t)) (message make-progress-reporter))
manandearth

1
Emacs 26.1에서는 이상하게 작동하지 않습니다. 왜 그런지 알아?
Christian Hudon

1
@ChristianHudon 방금 Emacs 26.1에서 테스트했고 init 파일없이 마스터했으며 두 곳에서 모두 작동합니다. message메시지 문자열 을 반환하므로 코드를 평가할 때 반환 된 문자열이 표시 될 수 있습니다. 키 바인딩에서이 코드를 평가하면 메시지가 인쇄되지 않습니다 ( 메시지 버퍼 제외 ).
잭슨

9

당신은 할 수 종류의 리스프 코드에서이 작업을 수행. 왜 "정렬"입니까? 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 파일 중 하나에서 포함되고 취향에 맞게 사용자 정의하면 억제를 위해 나열된 문자열과 정확히 일치하는 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에서 생성 된 "Ispell process killed"메시지 ispell.el.gz를 다음과 같이 작성하여 표시하지 않습니다.

(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있습니까? 다른 사람이 제안한대로 코드를 살펴볼 수는 있지만 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로컬로 (function)으로 사용 하거나 재정의 할 수 있습니다 ignore. 또는에서 사용되는 기술을 사용 edt-electric-helpify:의 원래 정의 저장 message, fset위해 ignore, 재 fset(그것을 사용하는 것이 좋습니다하지만 원래의 수비력을 unwind-protect당신이 그렇게 할 경우).


죄송합니다. 이러한 오류 메시지를 검색하는 방법에 대해 알려주세요. 이 시점에서 메시지를 유지하는 것보다 메시지를 비활성화하는 것이 더 어려운 것처럼 느껴집니다.
bitflips

1
"이러한 오류 메시지"를 검색하려면 grep또는 ADired를 사용하십시오. Emacs Lisp 소스 파일 (및 가능하면 Emacs C 파일에서도 가능)에서 오류 메시지 텍스트를 검색하십시오. HTH.
Drew

2

이것은 "버퍼 시작"및 "버퍼 끝"을 억제하는 데 효과적이며 이맥스 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.