Fork me on GitHub
#chlorine
<
2020-05-03
>
seancorfield03:05:29

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?

seancorfield03:05:35

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.szabo13:05:03

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

mauricio.szabo13:05:38

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.szabo13:05:17

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.szabo13:05:40

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.szabo13:05:17

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.

seancorfield18:05:07

@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!

seancorfield18:05:16

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.szabo19:05:01

@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.szabo19:05:04

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
seancorfield21:05:43

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

parrot 1
👀 1
mauricio.szabo22:05:53

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

seancorfield22:05:21

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

mauricio.szabo22:05:35

Yes, it's a wrapper

mauricio.szabo22:05:03

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

mauricio.szabo22:05:18

Probably an exception of some kind

seancorfield22:05:57

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

mauricio.szabo22:05:34

Oh... that should not be wrapped 😞

seancorfield22:05:55

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

seancorfield22:05:55

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.szabo22:05:27

Even on devtools, no exception appears?

mauricio.szabo22:05:19

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

seancorfield22:05:36

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

seancorfield22:05:27

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.

seancorfield22:05:43

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.szabo22:05:32

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.szabo22:05:37

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.szabo22:05:51

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

seancorfield22:05:13

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

mauricio.szabo22:05:18

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

mauricio.szabo22:05:51

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

mauricio.szabo22:05:10

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

seancorfield22:05:20

I'm not sure what you're asking.

seancorfield22:05:35

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

seancorfield22:05:57

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

mauricio.szabo23:05:33

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.szabo23:05:48

To see why it's being interpreted as a Browsable

seancorfield23:05:38

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

seancorfield23:05:51

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

seancorfield23:05:35

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

seancorfield23:05:09

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

mauricio.szabo23:05:14

Okay, that can be the issue.

mauricio.szabo23:05:27

(no, probably they won't survive)

seancorfield23:05:42

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.szabo23:05:13

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.szabo23:05:41

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

seancorfield23:05:52

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

seancorfield23:05:52

Initial view...

seancorfield23:05:31

After clicking the a key...

seancorfield23:05:07

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.szabo23:05:49

Wow, interesting! Great 👏

seancorfield23:05:22

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.szabo23:05:17

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

seancorfield23:05:44

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

mauricio.szabo23:05:53

(He's working on Pink Gorilla notebooks)

seancorfield23:05:40

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

mauricio.szabo23:05:14

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