nrepl/piggieback

Trying to start ClojureScript nREPL with CLI Tools

sbondaryev opened this issue · 4 comments

Hello
I am trying to start ClojureScript nREPL with CLI Tools
When I try to send ClojureScript expression to ClojureScropt nREPL it is treaded as Clojure

deps.edn

{:deps {
  org.clojure/clojure {:mvn/version "1.9.0"}
  org.clojure/clojurescript {:mvn/version "1.10.339"}
  nrepl {:mvn/version "0.3.1"}
  cider/piggieback {:mvn/version "0.3.6"}
}}

Start nREPL

user=> (require '[clojure.tools.nrepl.server :as server])
nil
user=> (require '[cider.piggieback :as pback])
nil
user=> (server/start-server :handler (server/default-handler #'pback/wrap-cljs-repl) :port 7888)
#clojure.tools.nrepl.server.Server{:server-socket #object[java.net.ServerSocket 0x70c205bf "ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=7888]"], :port 7888, :open-transports #object[clojure.lang.Atom 0x46894dc5 {:status :ready, :val #{}}], :transport #object[clojure.tools.nrepl.transport$bencode 0x596afb2f "clojure.tools.nrepl.transport$bencode@596afb2f"], :greeting nil, :handler #object[clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__877 0x79ba0285 "clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__877@79ba0285"], :ss #object[java.net.ServerSocket 0x70c205bf "ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=7888]"]}

Define a function to send message to nREPL

user=> (require '[clojure.tools.nrepl])
nil
user=> (defn msg [port code]
  (with-open [conn (clojure.tools.nrepl/connect :port port)]
    (-> (clojure.tools.nrepl/client conn 20000)
        (clojure.tools.nrepl/message {:op :eval :code code})
        doall
        pprint)))
#'user/msg

Try to switch to ClojureScript nREPL

user=> (msg 7888 "(require 'cljs.repl.nashorn)")
({:id "77d64088-aa65-4936-a14d-f10c4dff2244",
  :ns "user",
  :session "f0184538-0508-4850-9dca-37aea3773ade",
  :value "nil"}
 {:id "77d64088-aa65-4936-a14d-f10c4dff2244",
  :session "f0184538-0508-4850-9dca-37aea3773ade",
  :status ["done"]})
nil

user=> (msg 7888 "(cider.piggieback/cljs-repl (cljs.repl.nashorn/repl-env))")
({:id "21b36257-3d36-4b6a-a9c5-cfb8543dabb2",
  :out "To quit, type: :cljs/quit\n",                                 <<- It seems to be OK
  :session "10bfc16d-44d9-44f7-a6f9-94a870661e74"}
 {:id "21b36257-3d36-4b6a-a9c5-cfb8543dabb2",
  :ns "cljs.user",
  :session "10bfc16d-44d9-44f7-a6f9-94a870661e74",
  :value "nil"}
 {:id "21b36257-3d36-4b6a-a9c5-cfb8543dabb2",
  :session "10bfc16d-44d9-44f7-a6f9-94a870661e74",
  :status ["done"]})
nil

Check if ClojureScript nREPL works

user=> (msg 7888 "(clj->js {})")
({:ex "class clojure.lang.Compiler$CompilerException",
  :id "86184aa4-b1a1-4e01-86f7-57fc458dbdee",
  :root-ex "class clojure.lang.Compiler$CompilerException",
  :session "fa1628e3-ff34-4190-96f4-df600f8a36db",
  :status ["eval-error"]}
 {:err
  "CompilerException java.lang.RuntimeException: Unable to resolve symbol: clj->js in this context, compiling:(null:1:1) \n",
  :id "86184aa4-b1a1-4e01-86f7-57fc458dbdee",
  :session "fa1628e3-ff34-4190-96f4-df600f8a36db"}
 {:id "86184aa4-b1a1-4e01-86f7-57fc458dbdee",
  :session "fa1628e3-ff34-4190-96f4-df600f8a36db",
  :status ["done"]})

So if you look at the responses and take note of the :session key value. Notice how they are all different. In this case you can think of this as sending operations to different REPLs.

If you want to talk to the cljs repl you will have to talk to that session.

This easiest way to get a stable session is to take the client and make a session client out of it.
Then when you send your messages to that client they are all going "to the same repl" (actually
you are speaking to different threads with isolated bindings).

(def conn (nrepl/connect :port 7888))
(def client (nrepl/client conn 1000))
(def sess1 (nrepl/client-session client))
(def sess2 (nrepl/client-session client))

;; now you will send things to the different sessions and you will notice the session id stays stable

(nrepl/message sess1 {:op :eval :code "(list 1 2 3)"})
(nrepl/message sess2 {:op :eval :code "(list 1 2 3)"})

And you will need to make a cljs-session for your cljs-repl. But what you have done above should work for vscode calva as you have separate sessions and one is a cljs session.

Great! Thanks @bhauman
Just to make the things done - here are modified steps

Define a function to send message to nREPL

user=> (require '[clojure.tools.nrepl])
nil
user=> (defn create-messenger [port]
  (let [session (-> (clojure.tools.nrepl/connect :port port)
                    (clojure.tools.nrepl/client 20000)
                    (clojure.tools.nrepl/client-session))]
    #(-> (clojure.tools.nrepl/message session {:op :eval :code %})
          doall
          pprint)))
#'user/create-messenger
user=> (def msg (create-messenger 7888))
#'user/msg

Switch to ClojureScript nREPL

user=> (msg "(require 'cljs.repl.nashorn)")
({:id "5d92a255-9e2b-42f9-b0c8-6e8232850a61",
  :ns "user",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :value "nil"}
 {:id "5d92a255-9e2b-42f9-b0c8-6e8232850a61",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :status ["done"]})
nil

user=> (msg "(cider.piggieback/cljs-repl (cljs.repl.nashorn/repl-env))")
({:id "cd73345e-7078-4249-ae37-1fe2cba61be0",
  :out "To quit, type: :cljs/quit\n",                                      <<- It is OK
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4"}
 {:id "cd73345e-7078-4249-ae37-1fe2cba61be0",
  :ns "cljs.user",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :value "nil"}
 {:id "cd73345e-7078-4249-ae37-1fe2cba61be0",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :status ["done"]})
nil

Evaluate ClojureScript

user=> (msg "(clj->js {})")
({:id "561211b9-ae5f-4674-86ce-f2e1a7141bc0",
  :ns "cljs.user",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :value "#js {}"}                                                        <<- It works now 
 {:id "561211b9-ae5f-4674-86ce-f2e1a7141bc0",
  :session "3f732512-7af4-4f56-b43f-054b1eb246b4",
  :status ["done"]})
nil

Indeed the session ID remains the same 3f732512-7af4-4f56-b43f-054b1eb246b4

Let's close this as it seems answered.