unrepl

discussing specification of an edn-based repl and its implementations.
thheller 2017-04-04T11:29:27.076824Z

@cgrand any reason why you used (System/identityHashCode x) and not (hash x) in https://github.com/cgrand/unrepl/blob/master/src/unrepl/print.clj#L103

thheller 2017-04-04T11:31:35.104244Z

ah nvm .. its for Object

cgrand 2017-04-04T11:31:49.107125Z

Yes I wanted identity and a bad hash may never return

cgrand 2017-04-04T11:33:45.130726Z

So I changed my mind on how to plug log libs in: unrepl exposes two functions and the client (repl frontend not user) has to create an appender on top of that

thheller 2017-04-04T11:36:46.166983Z

I started writing the custom object printer that would be equivalent to the thing that makes the js/console work

cgrand 2017-04-04T11:37:22.174076Z

@thheller whatโ€™s missing?

thheller 2017-04-04T11:39:03.194612Z

nothing really, just exploring a different approach

thheller 2017-04-04T11:40:02.206693Z

I hate *print-length* .. that is pretty much it

thheller 2017-04-04T11:40:49.216610Z

but what I want expects a rich GUI, so the output is not strictly human-readable edn-ish

thheller 2017-04-04T11:41:02.219215Z

ie. printing {:foo ["hello" 1 'two (list 1 2 3) #{1 2 3}]} produces

thheller 2017-04-04T11:41:16.221945Z

[:collection
 {:type :map}
 [:entry
  {}
  [:named {:type :keyword} nil "foo"]
  [:ref
   {:id -994784545}
   [:span {:type :list} "clojure.lang.PersistentVector [count: 5]"]]]]

thheller 2017-04-04T11:41:42.227503Z

so its hiccup-like markup

thheller 2017-04-04T11:42:25.236232Z

you can then use the :ref id to get the "body" of the ref -994784545

thheller 2017-04-04T11:42:35.238243Z

which would be

thheller 2017-04-04T11:42:37.238657Z

[:collection
 {:type :vector}
 [:entry {} [:number 0] [:string "hello"]]
 [:entry {} [:number 1] [:number 1]]
 [:entry {} [:number 2] [:named {:type :symbol} nil "two"]]
 [:entry
  {}
  [:number 3]
  [:ref
   {:id 736442005}
   [:span {:type :list} "clojure.lang.PersistentList [count: 3]"]]]
 [:entry
  {}
  [:number 4]
  [:ref
   {:id 439094965}
   [:span {:type :list} "clojure.lang.PersistentHashSet [count: 3]"]]]]

thheller 2017-04-04T11:42:44.240197Z

and so on

thheller 2017-04-04T11:43:09.245295Z

so it always only prints one value and leaves references for you to get later

thheller 2017-04-04T11:43:52.254318Z

[:collection props entry-1 entry-2 ...]

thheller 2017-04-04T11:44:05.256968Z

[:entry props key value]

thheller 2017-04-04T11:44:31.262061Z

keywords, symbols are [:named props namespace name]

thheller 2017-04-04T11:45:09.269904Z

it is basically what the js/console custom formatters do

cgrand 2017-04-04T11:45:41.276669Z

A link to these custom formatters?

cgrand 2017-04-04T11:46:59.292613Z

meanwhile in a repl:

user=> (unrepl.repl/start)
[:unrepl/hello {:session :session474, :actions {:exit (unrepl.repl/exit! :session474), :log-eval (clojure.core/some-&gt; :session474 unrepl.repl/session :log-eval), :log-all (clojure.core/some-&gt; :session474 unrepl.repl/session :log-all), :set-source (unrepl.repl/set-file-line-col :session474 <#C4C63FWP5|unrepl>/param :unrepl/sourcename <#C4C63FWP5|unrepl>/param :unrepl/line <#C4C63FWP5|unrepl>/param :unrepl/column)}}]
[:prompt {:file "unrepl-session", :line 1, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user, clojure.core/*warn-on-reflection* false}]
[:prompt {:file "unrepl-session", :line 2, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user, clojure.core/*warn-on-reflection* false}]
(def log (let [w (clojure.core/some-&gt; :session474 unrepl.repl/session :log-eval)] (fn [&amp; args] (into [:trace (-&gt; *ns* ns-name name) (java.util.Date.)] args))))
[:echo {:from [2 1], :to [3 1]} 1]
[:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session474 1), :background (unrepl.repl/background! :session474 1)}} 1]
[:eval <#C4C63FWP5|unrepl>/object [#unrepl.java/class clojure.lang.Var "0x27b6fd39" {:unrepl.ref/status :ready, :unrepl.ref/val <#C4C63FWP5|unrepl>/object [#unrepl.java/class user$fn__477$fn__479 "0x628a2e2d" "user$fn__477$fn__479@628a2e2d"]}] 1]
[:prompt {:file "unrepl-session", :line 3, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user, clojure.core/*warn-on-reflection* false}]
So we defined user/log and we are going to use it:
(log "hello" :thheller {:foo 42} (range))
[:echo {:from [4 1], :to [5 1]} 3]
[:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session474 3), :background (unrepl.repl/background! :session474 3)}} 3]
[:eval [:trace "user" <#C4C63FWP5|unrepl>/object [#unrepl.java/class java.util.Date "0x7ae3e597" "Tue Apr 04 13:44:08 CEST 2017"] "hello" :thheller {:foo 42} (0 1 2 3 4 5 6 7 8 9 <#C4C63FWP5|unrepl>/... {:get (unrepl.repl/fetch :G__486)})] 3]
[:prompt {:file "unrepl-session", :line 5, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user, clojure.core/*warn-on-reflection* false}]

cgrand 2017-04-04T11:47:47.302771Z

hmm oops a bug

thheller 2017-04-04T11:48:02.305774Z

so the custom formatters have the concept of a header and a body

thheller 2017-04-04T11:48:12.307596Z

header is basically the "short" version

thheller 2017-04-04T11:48:40.313458Z

[:span {:type :list} "clojure.lang.PersistentList [count: 3]"]

thheller 2017-04-04T11:48:42.313932Z

this is the header

thheller 2017-04-04T11:49:01.317851Z

ooops should not be :span ๐Ÿ˜‰

thheller 2017-04-04T11:49:07.318747Z

anyways

thheller 2017-04-04T11:49:39.325649Z

but the body is the [:collection ...]

cgrand 2017-04-04T11:50:05.331166Z

ok, without forgetting the call to the logger:

(def log (let [w (clojure.core/some-&gt; :session474 unrepl.repl/session :log-eval)] (fn [&amp; args] (w (into [:trace (-&gt; *ns* ns-name name) (java.util.Date.)] args)))))
[:echo {:from [5 1], :to [6 1]} 4]
[:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session474 4), :background (unrepl.repl/background! :session474 4)}} 4]
[:eval <#C4C63FWP5|unrepl>/object [#unrepl.java/class clojure.lang.Var "0x27b6fd39" {:unrepl.ref/status :ready, :unrepl.ref/val <#C4C63FWP5|unrepl>/object [#unrepl.java/class user$fn__487$fn__489 "0x7b3d57bf" "user$fn__487$fn__489@7b3d57bf"]}] 4]
[:prompt {:file "unrepl-session", :line 6, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user, clojure.core/*warn-on-reflection* false}]
user/log ise defined
(log "hello" :thheller {:foo 42} (range))
[:echo {:from [6 1], :to [7 1]} 5]
[:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session474 5), :background (unrepl.repl/background! :session474 5)}} 5]
[:log [:trace "user" <#C4C63FWP5|unrepl>/object [#unrepl.java/class java.util.Date "0x1f892f92" "Tue Apr 04 13:48:42 CEST 2017"] "hello" :thheller {:foo 42} (0 1 2 3 4 5 6 7 8 9 <#C4C63FWP5|unrepl>/... {:get (unrepl.repl/fetch :G__494)})] 5]
[:eval nil 5]

cgrand 2017-04-04T11:50:52.341416Z

thanks for the link

thheller 2017-04-04T11:51:59.355771Z

the problem I have with the normal print is that it still can get too long

thheller 2017-04-04T11:52:11.358033Z

even with *print-length* 10 or so

thheller 2017-04-04T11:52:25.360928Z

case in point: the cljs.anaylzer AST ๐Ÿ˜›

cgrand 2017-04-04T11:52:38.363728Z

set everything to 1 (length & depth)

cgrand 2017-04-04T11:53:10.370382Z

itโ€™s not because you get too much that you have to display it

thheller 2017-04-04T11:57:22.423251Z

hmm yeah dunno .. your print is probably better since it is still somewhat readable without a tool

cgrand 2017-04-04T15:10:23.394781Z

I documented how to hook up unrepl browseable log to timbre: https://github.com/cgrand/unrepl#log-eval-and-log-all

dominicm 2017-04-04T23:52:36.253712Z

Finally think I get this repl vs tooling thing now. So it would be acceptable to have a mimic/similar protocol that was used for other needs.

๐Ÿ™ 1