reveal icon indicating copy to clipboard operation
reveal copied to clipboard

Chlorine: Submit function similar to REBL?

Open sparkofreason opened this issue 5 years ago • 6 comments

I'm trying to figure out how to use reveal with atom/chlorine. I currently use REBL in this setup. REBL is started via -m, and then chlorine can be configured to send to REBL as shown here: https://github.com/seancorfield/atom-chlorine-setup/blob/master/init.coffee#L50

As far as I can tell, that won't quite work with reveal as it stands, since the instance of the function required to submit things for evaluation requires have the result of calling make. I'll keep digging around, but if you have any thoughts on how to wire this up that would be fantastic.

sparkofreason avatar Feb 23 '20 21:02 sparkofreason

Hi! Isn't chlorine just using a normal socket REPL to work? I don't have an Atom installed, but you can try this:

clj \
-J-Dclojure.server.repl='{:port 5555 :accept vlaaad.reveal.prepl/-main}' \
-Sdeps '{:deps {vlaaad/reveal {:mvn/version "0.1.0-ea4"}}}' 

This is similar to the usage instructions I found for chlorine.

I then tried opening simple socket server and it worked:

$ nc localhost 5555
Clojure 1.10.1
clojure.core=> {:fn inc}
{:fn #object[clojure.core$inc 0x73eb5891 "clojure.core$inc@73eb5891"]}
user=>

Reveal window opened and it mirrored the output.

vlaaad avatar Feb 24 '20 09:02 vlaaad

The first problem I had was typing vlaad instead of vlaaad. I was also a little confused because I expected the Reveal window to open when the REPL started, now realize it happens on first eval. When I connected via Chlorine. a whole bunch of errors came out, and nothing would eval subsequently. But I am guessing this is something to do with how Chlorine initializes the REPL connection, seems to be attempting to evaluate some code that Reveal doesn't like. The errors look like

Clojure 1.10.1
Syntax error reading source at (REPL:1:3).
Conditional read not allowed

(:cljs :using-cljs-repl :clj :using-clj-repl :cljr :using-cljr-repl :joker :using-joker-repl :clje :using-clje-repl :bb :using-bb-repl)
Execution error (IllegalArgumentException) at user/eval3943 (REPL:1).
Wrong number of args passed to keyword: :cljs

:using-unknown-repl
=> :using-unknown-repl
Syntax error reading source at (REPL:3:74).
Conditional read not allowed

and go on for a couple of pages. I'll check in on the #chlorine slack channel and see if there are any suggestions.

sparkofreason avatar Feb 24 '20 13:02 sparkofreason

Oh. There is an open issue on Clojure JIRA: CLJ-2453. I'll think about possible workarounds. Probably I'll be able to make Reveal start a normal REPL that can handle reader conditionals.

vlaaad avatar Feb 24 '20 13:02 vlaaad

Hmm, so I added vlaaad.reveal.repl namespace (0.1.0-ea5) that uses normal repl, and Chlorine starts 2 connections (which results in 2 windows opening), and their output is not very useful: Screenshot from 2020-02-25 21-55-35

I think it's better to use submit functionality you posted earlier on Slack:

Add this alias:

  :reveal {:extra-deps {vlaaad/reveal {:mvn/version "0.1.0-ea4"}}
           :extra-paths ["/Users/dave.dixon/.clojure"]
           :jvm-opts ["-Dclojure.server.repl={:port,50505,:accept,my.repl/start}"]}

pointing to your .clojure folder (or wherever you want to run startup scripts). In that folder add this clj file in the appropriate hierarchy:

(ns my.repl
  (:require [vlaaad.reveal.ui :as ui]))
(def reveal (ui/make))
(defn start
  []
  (clojure.core.server/repl))

Then modify the wrap_in_rebl_submit from @seancorfield's init.coffee as:

wrap_in_rebl_submit = (code) ->
  "(let [value " + code + "] " +
  "  (try" +
  "    ((requiring-resolve 'cognitect.rebl/submit) '" + code + " value)" +
  "    (catch Throwable _))" +
  "  (try" +
  "    ((requiring-resolve 'my.repl/reveal) value)" +
  "    (catch Throwable _))" +
  "  value)" 

vlaaad avatar Feb 25 '20 21:02 vlaaad

Here's the link where @seancorfield has the init.coffee file:

https://github.com/seancorfield/atom-chlorine-setup

sparkofreason avatar Feb 25 '20 21:02 sparkofreason

FWIW, what I'm doing at work is starting my REPL from a dev.repl namespace like this:


(defn -main
  "Pass an optional port number to start the REPL server on.

  The port can be provided as a command line argument or we'll try to use
  the last known value (from .socket-repl-port)."
  [& args]
  (let [cl (.getContextClassLoader (Thread/currentThread))]
    (.setContextClassLoader (Thread/currentThread) (clojure.lang.DynamicClassLoader. cl)))
  (let [port   (try (Long/parseLong (first args)) (catch Exception _))
        s-port (or port (file->port ".socket-repl-port") 50505)]
    (println "Starting Socket REPL on port" s-port "...")
    (spit ".socket-repl-port" (str s-port))
    ((requiring-resolve 'clojure.core.server/start-server)
     {:port s-port :name (str "REPL-" s-port)
      :accept 'clojure.core.server/repl})
    (if-let [rebl-main (try (requiring-resolve 'cognitect.rebl/-main)
                         (catch Exception _))]
      (do
        (println "Starting REBL browser...")
        (try
          (require 'jedi-time.core)
          (println "Java Time is Datafiable...")
          (catch Throwable _))
        (rebl-main))
      (if-let [reveal-main (try (requiring-resolve 'vlaaad.reveal/repl)
                             (catch Exception _))]
        (do
          (println "Starting Reveal REPL/browser...")
          (try
            (require 'jedi-time.core)
            (println "Java Time is Datafiable...")
            (catch Throwable _))
          (reveal-main))
        (do
          (println "Unable to find REBL or Reveal")
          (System/exit 1))))))

and then in my Chlorine config I have this code:

(defn- wrap-in-tap [code]
  (str "(let [value " code
       "      rr      (try (resolve 'requiring-resolve) (catch Throwable _))]"
       "  (if-let [rs (try (rr 'cognitect.rebl/submit) (catch Throwable _))]"
       "    (rs '" code " value)"
       "    (tap> value))"
       "  value)"))

So, if REBL is on my classpath, dev.repl/-main starts that up and Chlorine will use submit to send the form and the value to REBL, otherwise dev.repl/-main starts Reveal (if it is on the classpath) and Chlorine just tap>'s all the values.

I've also been experimenting with Portal -- which you can run alongside Reveal since it also uses add-tap to drive its web UI.

Oh, and here's file->port:


(defn- file->port
  "Attempt to read a port number from the specified file. If the file
  doesn't exist or doesn't contain a valid number, return nil."
  [filename]
  (try
    (-> filename (slurp) (Long/parseLong))
    (catch Throwable _)))

seancorfield avatar Aug 04 '20 21:08 seancorfield

Given that Atom/Chlorine has gone away, is there any value in keeping this issue open now?

seancorfield avatar May 20 '23 00:05 seancorfield

No.

sparkofreason avatar May 20 '23 15:05 sparkofreason