进程 过滤器函数(filter function) 是接收关联进程标准输出的函数。该进程的所有输出都会传递给过滤器。默认过滤器仅直接将输出写入进程缓冲区。
默认情况下,进程的错误输出(如有)也会传递给过滤器函数,除非创建进程时已将其标准错误流与标准输出分离。Emacs 仅会在特定函数调用期间调用过滤器函数。See 接收进程输出。注意,如果过滤器调用了这些函数,可能导致过滤器被递归调用。
过滤器函数必须接收两个参数:关联进程,以及刚从进程接收到的输出字符串。函数可自由处理这些输出。
过滤器函数内部通常会禁止退出操作,否则在命令行输入 C-g 或退出用户命令的行为会变得不可预测。如果希望在过滤器函数内允许退出,可将 inhibit-quit 绑定为 nil。大多数情况下,正确的做法是使用宏 with-local-quit。See 退出。
如果过滤器函数执行过程中发生错误,错误会被自动捕获,不会中断触发过滤器的正在运行的程序。但如果 debug-on-error 为非 nil,错误不会被捕获,从而可以使用 Lisp 调试器调试过滤器函数。See Lisp 调试器。如果错误被捕获,Emacs 会暂停 process-error-pause-time 秒,让用户看到错误信息。See 创建异步进程。
很多过滤器函数会(有时或始终)模仿默认过滤器的行为,将输出插入进程缓冲区。这类过滤器需要确保保存当前缓冲区,插入输出前切换到正确的缓冲区(若不同),之后恢复原缓冲区。它们还应检查缓冲区是否存活,更新进程标记,某些情况下还需更新点位置。实现方式如下:
(defun ordinary-insertion-filter (proc string)
(when (buffer-live-p (process-buffer proc))
(with-current-buffer (process-buffer proc)
(let ((moving (= (point) (process-mark proc))))
(save-excursion
;; Insert the text, advancing the process marker.
(goto-char (process-mark proc))
(insert string)
(set-marker (process-mark proc) (point)))
(if moving (goto-char (process-mark proc)))))))
若要让过滤器在新文本到达时强制显示进程缓冲区,可在 with-current-buffer 结构前添加如下代码:
(display-buffer (process-buffer proc))
若要强制将点移至新输出末尾,无论其之前位置如何,可移除示例中的 moving 变量并无条件调用 goto-char。注意这不一定会移动窗口点。默认过滤器实际使用 insert-before-markers,会移动所有标记包括窗口点。这可能移动无关标记,因此通常更好的做法是显式移动窗口点,或将其插入类型设为 t(see 窗口(window)与点(Point))。
注意 Emacs 在执行过滤器函数时会自动保存和恢复匹配数据。See 匹配数据。
传递给过滤器的输出可以是任意大小的数据块。连续两次产生相同输出的程序,可能一次发送 200 字符的一个块,下次分成五个 40 字符的块。如果过滤器需要在子进程输出中查找特定文本,务必处理字符串被拆分到两个或更多输出块中的情况;一种方法是将接收到的文本插入临时缓冲区再进行搜索。
该函数为 process 设置过滤器函数 filter。如果 filter 为 nil,进程将使用默认过滤器,即将输出插入进程缓冲区。如果 filter 为 t,Emacs 会停止接收该进程的输出,除非它是监听连接的网络服务器进程。
该函数返回 process 的过滤器函数。
如果需要将进程输出传递给多个过滤器,可使用 add-function 将现有过滤器与新过滤器组合。See 为 Emacs Lisp 函数添加建议。
以下是过滤器函数的使用示例:
(defun keep-output (process output)
(setq kept (cons output kept)))
⇒ keep-output
(setq kept nil)
⇒ nil
(set-process-filter (get-process "shell") 'keep-output)
⇒ keep-output
(process-send-string "shell" "ls ~/other\n")
⇒ nil
kept
⇒ ("lewis@slug:$ "
"FINAL-W87-SHORT.MSS backup.otl kolstad.mss~ address.txt backup.psf kolstad.psf backup.bib~ david.mss resume-Dec-86.mss~ backup.err david.psf resume-Dec.psf backup.mss dland syllabus.mss " "#backups.mss# backup.mss~ kolstad.mss ")