在Emacs中,我能否设置*Messages*缓冲区以便它跟踪最新消息?

20

基本上我想让*Messages*缓冲区在有新消息到来时始终滚动到底部。

我可以这样做吗?

我找到了auto-revert-tail-mode,但它仅适用于正在访问文件的缓冲区。 当我在Messages缓冲区中尝试使用它时,它弹出了一个错误:
auto-revert-tail-mode:该缓冲区没有访问文件


3
当光标位于该缓冲区的末尾时,即使有新消息到达,光标也会停留在那里。 我猜这对你来说还不够? - JB.
6
至少在Emacs 23.2.1中,*Messages*默认情况下是尾随的,除非您手动将点从EOF移动(将其移回将恢复尾随行为)。 auto-revert-tail-mode似乎没有明显不同的作用。 - phils
6个回答

10

对于多个框架,您可能需要:

(defadvice message (after message-tail activate)
  "goto point max after a message"
  (with-current-buffer "*Messages*"
    (goto-char (point-max))
    (walk-windows (lambda (window)
                    (if (string-equal (buffer-name (window-buffer window)) "*Messages*")
                        (set-window-point window (point-max))))
                  nil
                  t)))

不错,但你最好使用get-buffer-window-list而不是walk-windows加过滤器。 - Clément

5
只需在缓冲区末尾放置光标M->。如果您不手动移动它,它将保持在那里 - 也就是说,您将始终看到尾部。

5
我很确定这不是真的……在我周围的任何Emacs上都没有起作用。 - nic ferrier
1
@nicferrier 是的,它是有效的。请查看问题下面的其他评论以获取有关所指内容的更多详细信息。确保您使用 M-> 而不仅仅是其他光标移动来将点放在 point-max 上。 - Drew
确实,光标停留在缓冲区的末尾。但是在版本27.0.50中,光标不可见。我认为保持可见是这个问题中“tail”行为的一部分。 - 5fec
@ded7:点始终可见 - 它是光标的缓冲区位置,永远不会超出缓冲区/窗口的可见部分。 - Drew
2
@Drew,我们在这里讨论的是当活动窗口显示的缓冲区不是“Messages”缓冲区时会发生什么情况,但“Messages”缓冲区在另一个窗口中可见。在这种情况下,“Messages”缓冲区的最大缓冲位置可能不可见,即使您在“Messages”中留下了指针,指向当时的最大缓冲位置。 - 5fec
1
我明白了。所以您在谈论window-point。在这种情况下,@Peter的回答或类似的回答是相关的。我刚刚提交了Emacs错误(增强请求)# 36343 ,建议用户可以选择自动执行此操作。 (Bug#36343本身实际上是关于C-h e的。) - Drew

2

这段代码看起来有点复杂,但是简单的(goto-char (point-max)) 对我来说并不能正常工作:

(defadvice message (after message-tail activate)
  "goto point max after a message"
  (with-current-buffer "*Messages*"
    (goto-char (point-max))
    (let ((windows (get-buffer-window-list (current-buffer) nil t)))
      (while windows
        (set-window-point (car windows) (point-max))
        (setq windows (cdr windows))))))

1
你非常有成就,杰克逊先生。 - Cheeso
在我看来,上面的表格使用漫步窗口更加优美。 - Nordlöw
@Nordlöw:至少在这里,(while windows ...) 最好像 walk-windows 版本一样写成 (mapc (lambda (w) (set-window-point w (point-max))) windows) - ntc2

2
这里是一个使用新的建议风格实现的示例。最初的回答。
(defun message-buffer-goto-end-of-buffer (&rest args)
  (let* ((win (get-buffer-window "*Messages*"))
         (buf (and win (window-buffer win))))
    (and win (not (equal (current-buffer) buf))
         (set-window-point
          win (with-current-buffer buf (point-max))))))

(advice-add 'message :after 'message-buffer-goto-end-of-buffer)

1

我运行23.3版本,但是仍然有太多情况下内置的"解决方案"和消息函数的原始defadvice无法满足需求,所以我将代码包装在列表/切换/定时器设置中,现在工作得非常好——在调试时不再感到沮丧!

它是通用的,因此可以在任何缓冲区上使用,尽管我只在实际使用中使用它…

(toggle-buffer-tail "*Messages*" "on")

希望对某些人有用。

;alist of 'buffer-name / timer' items
(defvar buffer-tail-alist nil)
(defun buffer-tail (name)
  "follow buffer tails"
  (cond ((or (equal (buffer-name (current-buffer)) name)
         (string-match "^ \\*Minibuf.*?\\*$" (buffer-name (current-buffer)))))
        ((get-buffer name)
      (with-current-buffer (get-buffer name)
        (goto-char (point-max))
        (let ((windows (get-buffer-window-list (current-buffer) nil t)))
          (while windows (set-window-point (car windows) (point-max))
         (with-selected-window (car windows) (recenter -3)) (setq windows (cdr windows))))))))

(defun toggle-buffer-tail (name &optional force)
  "toggle tailing of buffer NAME. when called non-interactively, a FORCE arg of 'on' or 'off' can be used to to ensure a given state for buffer NAME"
  (interactive (list (cond ((if name name) (read-from-minibuffer 
      (concat "buffer name to tail" 
        (if buffer-tail-alist (concat " (" (caar buffer-tail-alist) ")") "") ": ")
    (if buffer-tail-alist (caar buffer-tail-alist)) nil nil
           (mapcar '(lambda (x) (car x)) buffer-tail-alist)
        (if buffer-tail-alist (caar buffer-tail-alist)))) nil)))
  (let ((toggle (cond (force force) ((assoc name buffer-tail-alist) "off") (t "on")) ))
    (if (not (or (equal toggle "on") (equal toggle "off"))) 
      (error "invalid 'force' arg. required 'on'/'off'") 
      (progn 
        (while (assoc name buffer-tail-alist) 
           (cancel-timer (cdr (assoc name buffer-tail-alist)))
           (setq buffer-tail-alist (remove* name buffer-tail-alist :key 'car :test 'equal)))
        (if (equal toggle "on")
            (add-to-list 'buffer-tail-alist (cons name (run-at-time t 1 'buffer-tail name))))
        (message "toggled 'tail buffer' for '%s' %s" name toggle)))))

编辑:将功能更改为在窗口底部显示尾行


把以下與程式設計相關的內容從英文翻譯成中文。僅返回翻譯後的文字:為了方便起見,將其放在GitHub上(僅供我個人使用)http://github.com/mbriggs/buffer-tail.el - Matt Briggs

1

这里是对 Peter / Trey 解决方案的修正

(defun modi/messages-auto-tail (&rest _)
  "Make *Messages* buffer auto-scroll to the end after each message."
  (let* ((buf-name "*Messages*")
         ;; Create *Messages* buffer if it does not exist
         (buf (get-buffer-create buf-name)))
    ;; Activate this advice only if the point is _not_ in the *Messages* buffer
    ;; to begin with. This condition is required; otherwise you will not be
    ;; able to use `isearch' and other stuff within the *Messages* buffer as
    ;; the point will keep moving to the end of buffer :P
    (when (not (string= buf-name (buffer-name)))
      ;; Go to the end of buffer in all *Messages* buffer windows that are
      ;; *live* (`get-buffer-window-list' returns a list of only live windows).
      (dolist (win (get-buffer-window-list buf-name nil :all-frames))
        (with-selected-window win
          (goto-char (point-max))))
      ;; Go to the end of the *Messages* buffer even if it is not in one of
      ;; the live windows.
      (with-current-buffer buf
        (goto-char (point-max))))))
(advice-add 'message :after #'modi/messages-auto-tail)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接