vlaaad / reveal

Read Eval Visualize Loop for Clojure

Home Page:https://vlaaad.github.io/reveal/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Chlorine: Submit function similar to REBL?

sparkofreason opened this issue · 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.

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.

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.

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.

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)" 

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

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

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 _)))