利用 suspend-emacs 在终端中执行 Shell 命令

Emacs 如何运行交换式的 shell 命令 继续讨论:

Emacs 自带终端模拟器 (M-x term),不过对于需要用到终端的命令,比如 man, less, vim 等,我还是习惯用专门的终端程序,对于已经运行在终端中的 Emacs, suspend-emacs 能实现这一点:

(suspend-emacs "man ls ; fg")

这里的参数是一个 Shell 命令。为了方便使用,封装成一个用户命令:

(defun terminal-shell-command (command)
  "Suspend Emacs, run COMMAND in the Terminal."
  (interactive "sShell command: ")
  (suspend-emacs command))

于是乎似乎可以实现跟 Vim 的 ! 类似的效果(?):

M-x terminal-shell-command RET man ls ; fg RET

suspend-emacs 在 Lisp 和 Shell Command 间构造了一个桥梁,因此我们构造一个更高级 Lisp 函数,自动化这一过程:

(defun terminal-shell-command-to-string (command)
  "Suspend Emacs, run COMMAND in the Terminal, then resume Emacs."
  (suspend-emacs (concat command " > /tmp/shell-command.output ; fg"))
  (shell-command-to-string "cat /tmp/shell-command.output"))

一个应用是,实现 peco1 + Emacs 的协作,效果应该和 peco + vim 差不多。

(defun peco-find-file (command)
  "Run `find-file' on the output of 'COMMAND | peco'."
  (interactive "sShell 'Command' | peco: ")
  (let ((files (split-string
                (terminal-shell-command-to-string (concat command " | peco"))
                "\n" t)))
    (mapc #'find-file files)))

1 peco 感觉像是终端版本的 Helm。