chlorine-clover

About Chlorine for Atom and Clover for VS Code: https://atom.io/packages/chlorine and https://marketplace.visualstudio.com/items?itemName=mauricioszabo.clover
mauricio.szabo 2020-05-03T00:22:46.333300Z

Yes, the thing is that with the current "interactive results" plug-in customizations can be first-class

mauricio.szabo 2020-05-03T00:23:26.333500Z

It means that you can evaluate anything, and when you get the result the user can decide how to render that result - even if it involves further interactions with the REPL

mauricio.szabo 2020-05-03T00:23:59.333700Z

So, if there's a better way to make it easier for the user to write these interactions... maybe we can see some interesting developments

seancorfield 2020-05-03T03:44:29.336Z

Will there be a way to trigger additional evaluates from the Reagent component? And just so I understand the machinery: the text block passed to the evaluate_interactive API is passed to the REPL and evaluated and then passed back to Chlorine and rendered -- it's a one-way valve: evaluate in the REPL, if it produces :html etc, create an inline renderer?

seancorfield 2020-05-03T03:45:35.337200Z

I think it would be very interesting to be able to trigger additional evaluate/render cycles from the renderer: that would allow something close to REBL's functionality where you can render, then navigate and render, then navigate and render, etc.

💯 1
mauricio.szabo 2020-05-03T13:30:03.337900Z

Yes, it is possible today - every "callback" function that you add on :fns is evaluated on the REPL

mauricio.szabo 2020-05-03T13:31:38.338700Z

For example, on the code below:

'{:html [:div.rows
          [:div [:input {:type "text" :on-change (?hello "Hello") :value (:in ?state)}]]
          [:div (:msg ?state)]]
   :state {:in "" :msg "Type Something..."}
   :fns {:hello (fn [e s prefix] (assoc s
                                        :in (:value e)
                                        :msg (str prefix ", " (:value e))))}}

mauricio.szabo 2020-05-03T13:35:17.341Z

This :hello handler is evaluated on the REPL side. The way it currently works is that, on Chlorine's side, the "event handler" (the e on the function) is converted to EDN and sent to REPL. The REPL then will evaluate something like:

((fn [e s prefix] (assoc s
                         :in (:value e)
                         :msg (str prefix ", " (:value e))))
 {:value "World"} 
 {:in "" :msg "Type Something..."} 
 "Hello")

mauricio.szabo 2020-05-03T13:36:40.342200Z

Of course, not every attribute from the "event" on React / Reagent's side is serialized (mostly because React adds infinite cycles and other strange things on its side...)

mauricio.szabo 2020-05-03T13:46:17.343700Z

The idea for the "interactive renderer" is to allow people to customize the plug-in as far as they want, even to the point of hooking new libraries, without the need to recompile it.

seancorfield 2020-05-03T18:23:07.345Z

@mauricio.szabo Oh wow, I didn't realize that's how it works! That's awesome. So a datafy/`nav` UI would be possible to build. I'll have to give that some thought!

seancorfield 2020-05-03T18:26:16.346200Z

Since the callbacks work on event, state, and data and they return new state, I sort of assumed they were executing on the client side (and I was wondering how, since they are Clojure/Script) 🙂 That's really nice.

mauricio.szabo 2020-05-03T19:03:01.348200Z

@seancorfield well, the way that everything fit together is quite tricky, so if you find any strange thing, please ask here! This "Clojure/ClojureScript dance" is quite interesting, but it can become confusing really fast...

mauricio.szabo 2020-05-03T19:05:04.350400Z

For a considerably more complex example of what the renderer can do, look at this file: https://github.com/mauricioszabo/repl-tooling/blob/master/resources/orchard-cmds.clj#L2

👀 1
seancorfield 2020-05-03T19:05:14.350800Z

Thanks.

seancorfield 2020-05-03T21:55:43.352200Z

I have a very clunky, bare bones inline mini-REBL starting to come together -- The new renderer stuff is amazing @mauricio.szabo !

👀 1
🦜 1
mauricio.szabo 2020-05-03T22:08:53.353400Z

Thanks! Let me know if you can thing on ways to improve it 🙂

seancorfield 2020-05-03T22:39:21.354200Z

I just ran across a repl-tooling.editor-helpers.Browseable which seems to be a wrapper for a value?

mauricio.szabo 2020-05-03T22:39:35.354500Z

Yes, it's a wrapper

mauricio.szabo 2020-05-03T22:40:03.355300Z

Sometimes, these results are a little crude (that's one of the reasons I want to get rid of UNREPL)

mauricio.szabo 2020-05-03T22:40:18.355500Z

Probably an exception of some kind

seancorfield 2020-05-03T22:40:57.355900Z

No, it's wrapping a hash map that has metadata.

mauricio.szabo 2020-05-03T22:41:34.357Z

Oh... that should not be wrapped 😞

seancorfield 2020-05-03T22:41:55.357800Z

I have my inline REBL working for basic hash maps and vectors so I thought I'd try it on a next.jdbc result set

seancorfield 2020-05-03T22:42:55.358800Z

I can unwrap it for display, but now I can't seem to get my button to fire (and there's no exception being displayed so it's hard to debug).

mauricio.szabo 2020-05-03T22:43:27.359300Z

Even on devtools, no exception appears?

mauricio.szabo 2020-05-03T22:44:19.360400Z

Maybe I can print uncaugh exceptions on code and print then somehow on the inline result, I'll see if I can come up with something

seancorfield 2020-05-03T22:44:36.360700Z

Found it in the console... yeah... Uncaught in promise, :ex #unrepl/browsable

seancorfield 2020-05-03T22:47:27.361400Z

OK, I'm stuck at this point. I can't tell where it's blowing up. It isn't invoking my button callback when I click the button.

seancorfield 2020-05-03T22:50:43.362300Z

Here's more of that exception {:ex #unrepl/browsable [#error {:via [{:type clojure.lang.LispReader$ReaderException, :message "java.lang.ClassNotFoundException: repl-tooling.editor-helpers.Browseable", :data {:clojure.error/line 91, :clojure.error/column 2812}, :at [clojure.lang.LispReader read "LispReader.java" 314]} {:type java.lang.ClassNotFoundException, :message "repl-tooling.editor-helpers.Browseable", :at [unrepl.repl$i9hjMxfOQ2IzbCA5TVia2QQEJNg$classloader$fn__13265 invoke "NO_SOURCE_FILE" 486]}] ...

mauricio.szabo 2020-05-03T22:52:32.364300Z

Ah... okay, that's not good. I didn't anticipate it. The problem is that the REPL is sending to Chlorine a code that it can't undestand.

mauricio.szabo 2020-05-03T22:53:37.365800Z

The REPL will evaluate a code, and Chlorine will answer with a repl-tooling.editor-helpers.Browseable object. When this code is sent to the interactive renderer, it will not undestand that repl-tooling.editor-helpers.Browseable is

mauricio.szabo 2020-05-03T22:53:51.366200Z

So, it can't de-serialize, and the whole thing becomes stuck 😞

seancorfield 2020-05-03T22:54:13.366700Z

I was a bit surprised that was even in the expression... it should just be a vector of hash maps.

mauricio.szabo 2020-05-03T22:56:18.368300Z

UNREPL issues. Sometimes it does wrap "normal Clojure" objects inside a strange format that Chlorine wraps inside this Browsable

mauricio.szabo 2020-05-03T22:56:51.369Z

What (type <your-object>) or (type (first your-object)) prints?

mauricio.szabo 2020-05-03T22:57:10.369300Z

(I had this issue with Datomic Datons, for example)

seancorfield 2020-05-03T22:59:20.369600Z

I'm not sure what you're asking.

seancorfield 2020-05-03T22:59:35.370Z

The result of next.jdbc/execute! is a vector of hash maps.

seancorfield 2020-05-03T22:59:57.370600Z

Is it perhaps because the metadata on the rows includes a function value?

mauricio.szabo 2020-05-03T23:00:33.371300Z

I just want to see what object next.jdbc/execute! returns - what's the exact class name of the vector, or the hash-maps

mauricio.szabo 2020-05-03T23:00:48.371700Z

To see why it's being interpreted as a Browsable

seancorfield 2020-05-03T23:02:38.372200Z

The rows are being interpreted as Browsable. Not the whole result.

seancorfield 2020-05-03T23:03:51.372800Z

It's a clojure.lang.PersistentVector containing clojure.lang.PersistentHashMap objects.

seancorfield 2020-05-03T23:04:35.373600Z

And those PersistentHashMap objects have metadata, which includes the key clojure.datafy/nav (a symbol), whose value is a function object.

seancorfield 2020-05-03T23:05:09.374200Z

I assume those function objects are not going to survive the round-trip...

mauricio.szabo 2020-05-03T23:05:14.374500Z

Okay, that can be the issue.

mauricio.szabo 2020-05-03T23:05:27.375Z

(no, probably they won't survive)

seancorfield 2020-05-03T23:06:42.376900Z

Yeah, that means I can't do this client-side... I hadn't thought too deeply about the protocol metadata stuff breaking if you render it over the wire. Oh well.

mauricio.szabo 2020-05-03T23:08:13.378600Z

Well, I also hadn't thought that Chlorine could send Browsables over the wire, then break everything on the process. Well, one more reason to re-think these wrappers

mauricio.szabo 2020-05-03T23:08:41.379100Z

Probably will be fixed on future versions. Just need some "hammock time" too :hammock:

seancorfield 2020-05-03T23:09:52.379500Z

Sure... It works really well for pure data!

seancorfield 2020-05-03T23:11:52.379600Z

Initial view...

seancorfield 2020-05-03T23:12:31.379900Z

After clicking the a key...

seancorfield 2020-05-03T23:13:07.380700Z

If you click one of the idx values, it drills down into the value. You can click < to go back to the previous view.

mauricio.szabo 2020-05-03T23:15:49.381100Z

Wow, interesting! Great 👏

seancorfield 2020-05-03T23:20:22.382300Z

I added this to my init.coffee so I had a hook into the new interactive renderer stuff

# Hook to test interactive rendering in Chlorine 0.6.0.
  atom.commands.add 'atom-text-editor', 'sean:interactive-block', ->
    result = Cl.ext.get_block()
    if result.text
      cmd = wrap_in_rebl_submit result.text
      Cl.ext.evaluate_interactive cmd, result.range
and then bound that to ctrl-; i (for interactive 🙂 )

mauricio.szabo 2020-05-03T23:22:17.384200Z

Yes, I did the same to be able to test things 🙂 I'm also talking with @hoertlehner to allow plots (using the same structure for the interactive renderer), and probably "custom UIs" so it becomes easier to make these fancy interfaces

seancorfield 2020-05-03T23:22:44.384600Z

I'll think about some of the workflows I use and see what I can come up with for interesting renderers 🙂

mauricio.szabo 2020-05-03T23:22:53.384700Z

(He's working on Pink Gorilla notebooks)

seancorfield 2020-05-03T23:23:40.385400Z

Those "browsable" wrappers definitely complicate things since they have to be unwrapped by the renderer...

mauricio.szabo 2020-05-03T23:28:14.388100Z

Yes, but I think there's a workaround. Probably not too difficult either, just need to think a little bit and then do some experiments.

1