请注意,这不仅对 clojure.java.shell 很重要,对 clojure.java.browse 也有影响;此外,这还将使 ClojureScript 浏览器 REPL 能够在 xdg-open 被用于的平台正确地启动浏览器。目前,ClojureScript 快速入门指南在许多系统上基本上是损坏的。大多数 ClojureScript 的初学者都不会享受调试此类问题(也许我只是比大多数人更固执:))。
在某些平台上,clojure.java.browse/browse-url 会调用 clojure.java.shell/sh 来执行命令行,使用 xdg-open 启动网页浏览器。作为合适的 **Nix 工具,xdg-open 会将它的开放文件描述符传递给新的进程。(我不知道这是否在某处对 xdg-open 有记录,但很容易演示。)
clojure.java.shell/sh 一直读取执行进程的 STDOUT 和 STDERR 流。当目的是收集子进程的输出时,当然是件好事。然而,当使用 xdg-open 启动浏览器时,直到浏览器退出这些流才会关闭。对于 clojure.java.browse/browse-url 的调用者来说,该函数看起来似乎“永远不会”返回。
我们需要一个 clojure.java.shell/sh 的变体(或 sh 的一个选项)来忽略输出流,并且只返回退出代码。我们严格使用子进程的副作用。与使用 doseq 而不是 map 有点类似,只是我们还需要子进程的退出代码。
为了使 ClojureScript 浏览器 REPL 工作正常,我对 clojure.java.{browse,shell} 做了本地副本,向 clojure.java.shell 添加了一个(launch)函数,该函数忽略 I/O 流但返回退出代码,并将 browse-url 修改为使用 launch。非常好!浏览器和 REPL 都是,正如快速入门指南所承诺的那样。
个人笔记:虽然我才刚开始尝试 ClojureScript,但我已经使用 Clojure 几年了。
由以下人员预审: Alex Miller