@djblue I'm curious what your thoughts are on the extensibility of Portal. Should it be easy (or possible) for people to add their own viewers? or to extend the serialization/rendering for custom types?
My current version of (user/portal)
(def portal-instance (atom nil))
(defn portal
"Open a Portal window and register a tap handler for it. The result can be
treated like an atom."
[]
;; Portal is both an IPersistentMap and an IDeref, which confuses pprint.
(prefer-method @(jit clojure.pprint/simple-dispatch) clojure.lang.IPersistentMap clojure.lang.IDeref)
;; Portal doesn't recognize records as maps, make them at least datafiable
(extend-protocol clojure.core.protocols/Datafiable
clojure.lang.IRecord
(datafy [r] (into {} r)))
(let [p ((jit portal.api/open) @portal-instance)]
(reset! portal-instance p)
(add-tap (jit portal.api/submit))
p))
Together with Emacs shortcuts for invoking (user/portal)
or (cljs.user/portal)
this is getting really nice!
Apologies if this has been asked and answered before: is it possible to have one JVM instance hosting your portal instance, and have other JVM instances point to that same server? I have a REPL running and I have a test runner in a separate process, and I would like to be able to get tap>
to push messages over to my REPL portal process.
I'd love to understand the architecture better to see if something like that is possible. I had a bit of a look around to see how hard it would be to graft Portal onto Funnel. Tools like Portal are one of the use cases I had in mind when creating Funnel, and it would make it trivial to have multiple processes connected to a single UI (or vice versa) https://github.com/lambdaisland/funnel
This would have been easier on Transit-based portal, but I guess you can still wrap CSON in Transit if necessary
I've been thinking about it but haven't put anything together yet. I've been waiting for use-cases before deciding on anything concrete. Did you have a specific use-case in mind?
The main issues I see with client extensibility is that it's going to be more involved, so my general preference would be focus on the user's runtime first.
I've been thinking about having a viewer that takes a value and a function from your runtime and applies that f to the value. For for a custom viewer, you could implement a fn that takes a value and returns hiccup :thinking_face:
Sorry, there isn't direct support for this, however I would be open to adding support for it. As an alternative, you could include your test code in your repl process and invoke tap>
from there.
I would describe the protocol semantics as similar to json-rpc over ws
Also, the server can make rpc requests to the client, but it's all sync request/response