Factor out :repl-options handling into its own function.

This commit is contained in:
Phil Hagelberg 2011-02-28 20:18:20 -08:00
parent b5002a23c2
commit 4b994497ee

View file

@ -10,62 +10,69 @@
(def *retry-limit* 100)
(defn repl-server [project host port & repl-options]
(let [init-form [:init `#(let [is# ~(:repl-init-script project)
in# ~(:repl-init project)
mn# '~(:main project)]
(when (and is# (.exists (File. (str is#))))
(println (str "Warning: :repl-init-script is "
"deprecated; use :repl-init."))
(load-file is#))
(when in#
(doto in# require in-ns))
(if mn#
(doto mn# require in-ns)
(in-ns '~'user)))]
repl-options (concat init-form repl-options)]
`(do (try ;; transitive requires don't work for stuff on bootclasspath
(require '~'clojure.java.shell)
(require '~'clojure.java.browse)
;; these are new in clojure 1.2, so swallow exceptions for 1.1
(catch Exception _#))
(let [server# (ServerSocket. ~port 0 (InetAddress/getByName ~host))
acc# (fn [s#]
(let [ins# (.getInputStream s#)
outs# (.getOutputStream s#)
skip-whitespace# @(ns-resolve '~'clojure.main
'~'skip-whitespace)
;; Suppress socket closed exceptions since
;; they are part of normal operation
caught# (fn [t#]
(when-not (instance? SocketException t#)
(throw t#)))]
(doto (Thread.
#(binding [*in* (-> ins# InputStreamReader.
LineNumberingPushbackReader.)
*out* (OutputStreamWriter. outs#)
*err* *err*
;; TODO: bugger; can't rebind in 1.3
;; clojure.main/repl has no way
;; to exit without signalling EOF,
;; which we can't do with a socket.
clojure.main/skip-whitespace
(fn [s#]
(try (skip-whitespace# s#)
(catch java.io.IOException _#
:stream-end)))]
(clojure.main/repl :caught caught#
~@repl-options)))
.start)))]
(doto (Thread. #(when-not (.isClosed server#)
(try
(acc# (.accept server#))
(catch SocketException e#
(.printStackTrace e#)))
(recur)))
.start)
(symbol (format "REPL started; server listening on %s:%s."
~host ~port))))))
;; TODO: test custom options, repl in interactive
(defn repl-options [project options]
(let [options (apply hash-map options)
init `#(let [is# ~(:repl-init-script project)
in# ~(:repl-init project)
mn# '~(:main project)]
~(:init options)
(when (and is# (.exists (File. (str is#))))
(println (str "Warning: :repl-init-script is "
"deprecated; use :repl-init."))
(load-file is#))
(when in#
(doto in# require in-ns))
(if mn#
(doto mn# require in-ns)
(in-ns '~'user)))
;; Suppress socket closed since it's part of normal operation
caught `(fn [t#]
(when-not (instance? SocketException t#)
(~(:caught options 'clojure.main/repl-caught) t#)))
;; clojure.main/repl has no way to exit without signalling EOF,
;; which we can't do with a socket. We can't rebind skip-whitespace
;; in Clojure 1.3, so we have to duplicate the function
read `(fn [request-prompt# request-exit#]
(or ({:line-start request-prompt# :stream-end request-exit#}
(try (clojure.main/skip-whitespace *in*)
(catch java.io.IOException _#
:stream-end)))
(let [input# (read)]
(clojure.main/skip-if-eol *in*)
input#)))]
(concat [:init init :caught caught :read read]
(flatten (seq (dissoc options :caught :init :read))))))
(defn repl-server [project host port & options]
`(do (try ;; transitive requires don't work for stuff on bootclasspath
(require '~'clojure.java.shell)
(require '~'clojure.java.browse)
;; these are new in clojure 1.2, so swallow exceptions for 1.1
(catch Exception _#))
(let [server# (ServerSocket. ~port 0 (InetAddress/getByName ~host))
acc# (fn [s#]
(let [ins# (.getInputStream s#)
outs# (.getOutputStream s#)
skip-whitespace# @(ns-resolve '~'clojure.main
'~'skip-whitespace)]
(doto (Thread.
#(binding [*in* (-> ins# InputStreamReader.
LineNumberingPushbackReader.)
*out* (OutputStreamWriter. outs#)
*err* *err*]
(clojure.main/repl
~@(repl-options project options))))
.start)))]
(doto (Thread. #(when-not (.isClosed server#)
(try
(acc# (.accept server#))
(catch SocketException e#
(.printStackTrace e#)))
(recur)))
.start)
(symbol (format "REPL started; server listening on %s:%s."
~host ~port)))))
(defn copy-out-loop [reader]
(let [buffer (make-array Character/TYPE 1000)]
@ -126,5 +133,4 @@ Running outside a project directory will start a standalone repl session."
(clojure.main/with-bindings (println (eval server-form)))
(eval-in-project project server-form)))
(poll-repl-connection port retries repl-client)
(exit))))
0)))