在Emacs中异步运行命令,但是逐步显示输出 [英] Run commands in Emacs asynchronously, but display output incrementally

查看:175
本文介绍了在Emacs中异步运行命令,但是逐步显示输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实用功能:

(defun execute-in-buffer (command-with-args buffer)
  "Execute a string COMMAND-WITH-ARGS representing a shell command with arguments,
inserting the results in BUFFER."
  (switch-to-buffer buffer)
  (insert (format ">>> %s\n" command-with-args))
  (let* ((command-args-list (s-split " " command-with-args))
         (command (car command-args-list))
         (args (cdr command-args-list)))
    (apply 'call-process command nil buffer t args)))

这允许我做一些事情,如(execute-in-bufferls /(get- buffer-create* my-output *)然而,它并不适用于慢速命令,如果我调用了一系列缓慢的命令,直到最后都没有得到任何输出:

This allows me to do things like (execute-in-buffer "ls /" (get-buffer-create "*my-output*"). However, it's not well suited for slow commands. If I call a series of slow commands, I don't get any output until the very end:

(let ((buf (get-buffer-create "*my-output")))
  (execute-in-buffer "sleep 10" buf)
  (execute-in-buffer "ls /" buf))

我想能够同步调用,所以下一个命令只在前一个命令完成后运行。但是,我想在我们的命令运行时看到输出。我如何做到这一点?

I want to be able to call synchronously, so the next command only runs after the previous one finishes. However, I want to see the output from my commands as they run. How would I do this?

(示例代码只是为了显示,我很乐意放弃赞成别的东西。)

(Example code is just for show, I'm happy to drop it in favour of something else.)

推荐答案

使用同步进程

如果你想坚持同步处理(例如使用 call-process ),每次调用$ $ c $后,您需要调用(重新显示) c>执行缓冲区显示要更新,输出可见(另见这个问题了解更多细节)。但是,在进程终止之前,每个命令的输出将不可见,并且外部进程运行时emacs将挂起。

If you want to stick with synchronous processes (e.g. using call-process), you need to call (redisplay) after each call to execute-in-buffer for the display to be updated and the output to be visible (also see this question for more details). However, the output of each command will not be visible until the process terminates, and emacs will hang while the external processes are running.

使用异步进程strong>

Using asynchronous processes

使用异步进程有点复杂,但是避免在命令运行时挂起Emacs,这也解决了重新显示问题。这里的棘手部分是顺序链接所有命令。这里有一些elisp应该做的窍门:

Using asynchronous processes is a bit more complicated, but avoids hanging Emacs while the commands are running, which also solves the redisplay issue. The tricky part here is to sequentially chain all commands. Here is a bit of elisp which should do the trick:

(defun execute-commands (buffer &rest commands)
  "Execute a list of shell commands sequentially"
  (with-current-buffer buffer
    (set (make-local-variable 'commands-list) commands)
    (start-next-command)))

(defun start-next-command ()
  "Run the first command in the list"
  (if (null commands-list)
      (insert "\nDone.")
    (let ((command  (car commands-list)))
      (setq commands-list (cdr commands-list))
      (insert (format ">>> %s\n" command))
      (let ((process (start-process-shell-command command (current-buffer) command)))
        (set-process-sentinel process 'sentinel)))))

(defun sentinel (p e)
  "After a process exited, call `start-next-command' again"
  (let ((buffer (process-buffer p)))
    (when (not (null buffer))
      (with-current-buffer buffer
        ;(insert (format "Command `%s' %s" p e) )
        (start-next-command)))))

;; Example use
(with-current-buffer (get-buffer-create "*output*") (erase-buffer))
(execute-commands "*output*"
                  "echo 1"
                  "sleep 1"
                  "echo 2; sleep 1; echo 3"
                  "ls /")

这篇关于在Emacs中异步运行命令,但是逐步显示输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆