请注意,这不仅对 clojure.java.shell 和 clojure.java.browse 很重要,对于在 xdg-open 上使用的平台上,这还使得 ClojureScript 浏览器 REPL 能够正确地启动浏览器。目前,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} 做了本地复制,添加了一个名为 (launch) 的函数到 clojure.java.shell,忽略 I/O 流但返回退出码,并将/browse-url 修改为使用 launch。非常好!浏览器和 REPL 和承诺的那样,就像快速入门指南所承诺的那样。
个人笔记:虽然我刚刚开始对 ClojureScript 进行实验,但我已经使用 Clojure 几年了。
由:Alex Miller