如何让Emacs shell命令输出缓冲区始终跟随底部?

10

我正在编写一个 Emacs 次要模式,其中包含一些调用 shell 命令的 Emacs 命令。 我正在使用以下代码:

    (let ((output (get-buffer-create "*Foo Output*")))
      (start-process "Foo Process" output argv0)
      (display-buffer output))

我希望那些包含shell命令的缓冲区能够在输出被插入时自动滚动到底部,或者至少在命令执行完成时滚动到底部。我该怎么做?

1个回答

9
您可以使用 进程过滤函数 来实现。

进程过滤函数是一种接收关联进程标准输出的函数。如果进程有过滤器,则所有来自该进程的输出都会传递给该过滤器。只有在没有过滤器时,进程缓冲区才直接用于进程输出。

[...]

许多过滤函数有时(或始终)将输出插入到进程的缓冲区中,模拟没有过滤器时 Emacs 的操作。

start-process 返回一个代表新子进程的过程对象,在 Lisp 中您可以将其存储在变量中,例如 proc。您可以编写一个简单的过滤函数,仅将进程输出插入到关联的输出缓冲区中,从而将 point 移动到缓冲区的末尾。

(defun my-insertion-filter (proc string)
  (when (buffer-live-p (process-buffer proc))
    (with-current-buffer (process-buffer proc)
      ;; Insert the text, advancing the process marker.
      (goto-char (process-mark proc))
      (insert string)
      (set-marker (process-mark proc) (point)))))

使用 set-process-filter 将该过滤函数分配给您的进程。
(set-process-filter proc 'my-insertion-filter)

如果只需要在进程终止时跳转到缓冲区末尾,则可以使用sentinel

进程哨兵是一个函数,每当相关进程由于任何原因(包括由Emacs发送的信号或进程自身操作引起的)发生状态更改时都会被调用。如果进程退出,也会调用进程哨兵。

(defun my-sentinel (proc event)
  (when (buffer-live-p (process-buffer proc))
    (with-current-buffer (process-buffer proc)
      (end-of-buffer))))

(注意,每次调用此函数时,它会滚动到进程缓冲区的末尾,这可能不仅发生在进程结束时。如果你真的只想在进程终止时执行此操作,请检查event是否为字符串"finished\n"。)
使用set-process-sentinel将该哨兵分配给您的进程。
(set-process-sentinel proc 'my-sentinel)

我有一个类似的问题。我在我的.emacs文件中使用global-set-key来使某个按键组合运行一个shell命令(通过shell-command函数)。我和OP一样遇到了同样的问题;我只能看到Shell Command Output的顶部,而看不到底部。我盲目地将上面的process-filter内容输入到我的.emacs文件中,然后我收到了一个警告:“Symbol's value as variable is void: proc”,这是来自set-process-filter命令的。我认为proc应该是与shell缓冲区相关联的进程名称,但我对lisp一窍不通。我是否应该通过M-x运行cmd? - Kevin Buzzard
@KevinBuzzard,你的问题太复杂了,无法在评论中回答,请考虑提出一个正式的问题,以便得到更详细的答案。 - Thomas

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