如何从 Clojure 中 运行 交互式 CLI 程序?

How to run an interactive CLI program from within Clojure?

我想要 运行 Clojure 中的交互式 CLI 程序(例如,vim)并能够与之交互。

在 bash 和其他编程语言中,我可以用

vim > `tty`

我尝试在 Clojure 中做同样的事情:

(require '[clojure.java.shell :as shell])
(shell/sh "vim > `tty`")

但它只是打开 vim 而没有给我 tty。


背景:我正在开发一个 Clojure CLI 工具,它可以解析电子邮件并让用户在将解析的数据保存到磁盘之前对其进行编辑。它的工作方式如下:

  1. 读取包含电子邮件内容的文件并解析它。每封电子邮件都存储为一个单独的文件。
  2. 向用户显示已解析的数据并让用户编辑 vim 中的数据。我在内部用解析后的数据创建了一个临时文件,但我不介意用另一种方式来解决我的问题。
  3. 在用户完成对解析数据的编辑后(他们可能决定保持原样)将数据附加到磁盘上的文件中。所以所有解析的数据都保存到同一个文件中。
  4. 如果有任何包含电子邮件的文件,请转到第一步。

此代码依赖于 Clojure Java 互操作来利用 Java 的 ProcessBuilder class.

(defn -main
[]
;use doseq instead of for because for is lazily evaluated
(doseq [i [1 2 3]]
;extract current directory from system variable
(let [file-name (str "test" i ".txt")
      working-directory (trim-newline (:out (sh "printenv" "PWD")))]
  (spit file-name "")

  ;this is where fun begins. We use ProcessBuilder to forward commands to terminal
  ;we pass a list of commands and their arguments to its constructor
  (let [process-builder (java.lang.ProcessBuilder. (list "vim" (str working-directory "/" file-name)))
  ;inherit is a configuration constant
        inherit (java.lang.ProcessBuilder$Redirect/INHERIT)]
  ;we configure input, output and error redirection
  (.redirectOutput process-builder inherit)
  (.redirectError process-builder inherit)
  (.redirectInput process-builder inherit)

  ;waitFor used to block execution until vim is closed
  (.waitFor (.start process-builder))
  )
  ;additional processing here
)
)
;not necessary but script tends to hang for around 30 seconds at end of its execution
;so this command is used to terminate it instantly
(System/exit 0)
)