Skip to content

Instantly share code, notes, and snippets.

@hiredman
Created January 5, 2021 22:57
Show Gist options
  • Save hiredman/a2630ea6153d06840a2723d5b2c9698c to your computer and use it in GitHub Desktop.
Save hiredman/a2630ea6153d06840a2723d5b2c9698c to your computer and use it in GitHub Desktop.
(defn send-repl [& [obj]]
(let [in-in (java.io.PipedInputStream.)
in-out (java.io.PipedOutputStream. in-in)
out-in (java.io.PipedInputStream.)
out-out (java.io.PipedOutputStream. out-in)
err-in (java.io.PipedInputStream.)
err-out (java.io.PipedOutputStream. err-in)]
(tap> {:repl/in (clojure.java.io/writer in-out)
:repl/out (clojure.java.io/reader out-in)
:repl/err (clojure.java.io/reader err-in)})
(with-open [out (java.io.PrintWriter. (clojure.java.io/writer out-out))
err (java.io.PrintWriter. (clojure.java.io/writer err-out))
in (clojure.lang.LineNumberingPushbackReader.
(clojure.java.io/reader in-in))]
(binding [*out* out
*err* err
*in* in
*1 obj]
(clojure.main/repl
:init (fn []
(clojure.core.server/repl-init)
(set! *1 obj))
:read clojure.core.server/repl-read)))))
(defn wait-for-repl []
(let [p (promise)
f (fn [msg]
(when (and (contains? msg :repl/in)
(contains? msg :repl/out)
(contains? msg :repl/err))
(deliver p msg)))]
(try
(add-tap f)
(let [{:repl/keys [in out err]} @p
o (future
(let [buf (char-array 1024)]
(loop []
(let [n (.read out buf)]
(if-not (neg? n)
(do
(.write *out* buf 0 n)
(.flush *out*)
(recur))
nil)))))
e (future
(let [buf (char-array 1024)]
(loop []
(let [n (.read err buf)]
(if-not (neg? n)
(do
(.write *err* buf 0 n)
(.flush *err*)
(recur))
nil)))))
i (future
(let [buf (char-array 1024)]
(loop []
(let [n (.read *in* buf)]
(if-not (neg? n)
(do
(.write in buf 0 n)
(.flush in)
(recur))
(.close in))))))]
@o
@e
@i)
(finally
(remove-tap f)))))
@p-himik
Copy link

p-himik commented Sep 20, 2023

Context by hiredman shared on Slack:

You put a call to send-repl wherever, passing whatever context information

Then in the repl call wait-for-repl, and when execution reaches send-repl, wait-for-repl connects your current repl's in and out and err to the repl created by send-repl, with whatever context bound to *1

Execution at send-repl halts until you exit the repl it sent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment