Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Ensure ordering of printed responses (i.e. stop writing :out & :err m…

…essages with an agent)
  • Loading branch information...
commit 3f36e58c9c8c0156fbc0dfbce226013296e52076 1 parent daf0a84
@cemerick cemerick authored
View
50 src/main/clojure/clojure/tools/nrepl.clj
@@ -120,7 +120,8 @@
"Writes the given message to the writer. Returns the :id of the message."
[#^Writer out msg]
(locking out
- (binding [*out* out]
+ (binding [*out* out
+ *print-readably* true]
(prn (count msg))
(doseq [[k v] msg]
(prn (if (string? k) k (name k)))
@@ -159,25 +160,24 @@
(defn- create-repl-out
[stream-key write-response]
- (let [sw (agent (StringBuilder.))
- writer (PrintWriter. (proxy [Writer] []
- (close []
- (.flush this))
- (write [& [x off len]]
- (cond
- (number? x) (send sw #(.append #^StringBuilder % (char x)))
- (not off) (send sw #(.append #^StringBuilder % x))
- off (send sw #(.append #^StringBuilder % x off len))))
- (flush []
- (send-off sw
- #(if (zero? (.length #^StringBuilder %))
- %
- (do
- (write-response stream-key (str %))
- ; would use (.setLength % 0) here, but clojure 1.1 fails that with
- ; => Can't call public method of non-public class: public void java.lang.AbstractStringBuilder.setLength
- (StringBuilder.)))))))]
- [sw writer]))
+ (let [sb (ref (StringBuilder.))]
+ (PrintWriter. (proxy [Writer] []
+ (close []
+ (.flush this))
+ (write [& [x off len]]
+ (dosync
+ (cond
+ (number? x) (alter sb #(.append #^StringBuilder % (char x)))
+ (not off) (alter sb #(.append #^StringBuilder % x))
+ off (alter sb #(.append #^StringBuilder % x off len)))))
+ (flush []
+ ; would use (.setLength % 0) here, but clojure 1.1 fails that with
+ ; => Can't call public method of non-public class: public void java.lang.AbstractStringBuilder.setLength
+ (let [buffer (dosync (let [buffer @sb]
+ (ref-set sb (StringBuilder.))
+ buffer))]
+ (when (pos? (.length #^StringBuilder buffer))
+ (write-response stream-key (str buffer)))))))))
(defn- create-response
[current-session & options]
@@ -198,7 +198,6 @@
(str (java.util.UUID/randomUUID)))]
(swap! client-state-atom assoc :session-id session-id)
(swap! retained-sessions assoc session-id client-state-atom)
- (println "Retained session" (select-keys @client-state-atom [:session-id :value-1 :value-2 :value-3 :last-exception]))
session-id))
(defn release-session!
@@ -233,8 +232,8 @@
(defn- handle-request
[client-state-atom write-response {:keys [code in interrupt-atom ns] :or {in ""} :as msg}]
(let [code-reader (LineNumberingPushbackReader. (StringReader. code))
- [out-agent out] (create-repl-out :out write-response)
- [err-agent err] (create-repl-out :err write-response)]
+ out (create-repl-out :out write-response)
+ err (create-repl-out :err write-response)]
(binding [*in* (LineNumberingPushbackReader. (StringReader. in))
*out* out
*err* err
@@ -273,9 +272,7 @@
(if (pretty-print?)
(pprint value)
(prn value))))))
- (finally (.flush *out*) (.flush *err*))))
-
- (await out-agent err-agent)))
+ (finally (.flush *out*) (.flush *err*))))))
(def #^{:private true
:doc "Currently one minute; this can't just be Long/MAX_VALUE, or we'll inevitably
@@ -565,6 +562,7 @@
;; - tools
;; - add ClojureQL-style quasiquoting to send-with
;; - streams
+;; - multiplex new *out*'s to System/out (or things like clojure.test/*test-out* will just disappear into the ether)
;; - optionally multiplex System/out and System/err
;; - optionally join multiplexed S/out and S/err, receive :stdout, :stderr msgs
;; - protocols and transport
View
16 src/test/clojure/clojure/tools/nrepl_test.clj
@@ -244,7 +244,7 @@
(deftest repl-out-writer
(let [responses (atom [])
- [w-agent w] (#'repl/create-repl-out :out #(swap! responses conj %&))]
+ w (#'repl/create-repl-out :out #(swap! responses conj %&))]
(doto w
.flush
(.write "abcd")
@@ -262,7 +262,6 @@
(prn #{})
(flush)))
- (await w-agent)
(is (= [[:out "abcdefghij "]
[:out "no writes\nkeyed on linebreaks"]
[:out "\n#{}\n"]]
@@ -327,4 +326,15 @@
(ns baz))
full-response
:ns))
- (= 5 (repl-value "bar" :ns "user")))
+ (= 5 (repl-value "bar" :ns "user")))
+
+(def-repl-test proper-response-ordering
+ (is (= [[nil "100\n"] ; printed number
+ ["nil\n" nil] ; return val from println
+ ["42\n" nil] ; return val from `42`
+ [nil nil]] ; :done message
+ (->> (repl/send-with connection
+ (println 100)
+ 42)
+ repl/response-seq
+ (map (juxt :value :out))))))
Please sign in to comment.
Something went wrong with that request. Please try again.