portal 2023-05-31

update: thanks to @djblue we are close to supporting all of the emmy viewers in portal, like this: this one should be dragging the plot around, and it will, soon! EDIT: it works great:

๐Ÿ’ฏ 3
โค๏ธ 4

it should look like this:

Can't get the inequality bit working, probably have the wrong version of the code, but the atoms are working for this example if you wrap the code in an fn

Also default viewers can be specified at all levels so this viewer will compose will all the other viewers in portal clojure-spin

For example:

(->
 [:<>
  [:portal.viewer/code "(+ 1 2 3)"]
  [:portal-present.viewer/mafs
   '(fn []
      (reagent.core/with-let
        [G__68160 (reagent.core/atom [0 0])]
        [:<>
         [:pre (clojure.core/pr-str @G__68160)]
         [mafs.core/Mafs
          [mafs.coordinates/Cartesian {}]
          (reagent.core/with-let
            [G__68161
             (js/Function.
              "[y0001]"
              "[p0002]"
              "  const _0006 = - p0002;\n  const _0008 = _0006 + y0001;\n  const _0013 = Math.sinh(_0008);\n  const _0014 = Math.cosh(_0008);\n  const _0015 = Math.pow(_0014, 4.0);\n  return (- 6.0 * Math.pow(_0013, 4.0) + 8.0 * Math.pow(_0013, 2.0) * Math.pow(_0014, 2.0) - 2.0 * _0015) / _0015;")]
            [mafs.plot/OfX
             {:y
              (let [G__68162 (mapv @G__68160 [0])] (fn [x] (G__68161 [x] G__68162)))}])
          (reagent.core/with-let
            [G__68163
             (js/Function.
              "[y0001]"
              "[p0002]"
              "  const _0006 = - p0002;\n  const _0008 = _0006 + y0001;\n  const _0013 = Math.sinh(_0008);\n  const _0014 = Math.cosh(_0008);\n  const _0015 = Math.pow(_0014, 4.0);\n  return (- 6.0 * Math.pow(_0013, 4.0) + 8.0 * Math.pow(_0013, 2.0) * Math.pow(_0014, 2.0) - 2.0 * _0015) / _0015;")
             G__68165
             (js/Function. "y0001" "  return Math.cos(y0001);")]
            #_[mafs.plot/Inequality
               {:y
                {:<=
                 (let [G__68164 (mapv @G__68160 [0])] (fn [x] (G__68163 [x] G__68164))),
                 :> G__68165},
                :color :blue}])
          [mafs.core/MovablePoint {:atom G__68160, :constrain "horizontal"}]]]))]]
 (with-meta {:portal.viewer/default :portal.viewer/hiccup}))

In terms of downstream users resolving npm deps, not sure how you envisioned it, but the following might be a start:

In jvm land
(try
  (portal.api/eval-str "(js/require \"mafs\")")
  (catch Exception e <install deps for user or ask them to do so>))

If you wanted to vendor your npm deps, portal can resolve js files from the classpath ๐Ÿ‘

@djblue I do specify deps.cljs , could we pull them from there?

@djblue in clerk I have been building a custom JS bundle that includes everything, but this approach seems obviously easier to extend

(ev/with-let [!phase [0 0]]
  (let [shifted (ev/with-params {:atom !phase :params [0]}
                  (fn [shift]
                    (((cube D) tanh) (- identity shift))))]
    [:<>
     [:pre `(pr-str @~!phase)]
     (mafs/mafs
      (mafs/cartesian)
      (mafs/of-x shifted)
      (mafs/inequality
       {:y {:<= shifted :> cos} :color :blue})
      (mafs/movable-point
       {:atom !phase :constrain "horizontal"}))]))

the fn trick worked great:

(p/register-viewer!
 {:name      ::mafs
  :predicate (constantly true)
  :component (fn [form]
               (eval (list 'fn [] form)))})

๐Ÿ’ฏ 1

Currently Portal doesn't look for deps.cljs, it could but I'm not sure how that would play with how shadow treats it

If you already have the code vendor'd:

;; in cljs land
(def mafs
  (try
    (js/require "./vendor.js")
    (catch :default e (js/reauire "mafs"))))

Or perhaps fallback to the vendor if the npm version isn't available

What are your expectations for the deps.cljs file?

my expectation was that any consumer of mafs.cljs will build a bundle with shadow, and that this file would trigger shadow into running npm install mafs with the correct version; https://github.com/mentat-collective/Mafs.cljs/blob/main/src/deps.cljs

๐Ÿค” 1

and save the user from having to do it manually

same with mathbox.cljs, leva.cljs etc

Interesting, so with Portal you get the convenience of no bundles but the inconvenience of resolving npm deps ๐Ÿ˜†

(clicking to interact seems to also โ€œbegin filteringโ€ always, not sure if that matters enough to figure out a way around! doesnโ€™t seem to impact the animation at all)

Interesting, might need to stop some events from propagating ๐Ÿค”

๐ŸŽ‰ 7

Not sure if you are interested, but you have access to portal.ui.theme, which will automatically work with editor based themes

Also, would getting this working in calva notebooks be something you want? https://cljdoc.org/d/djblue/portal/0.40.0/doc/editors/vs-code/clojure-notebooks

yes, absolutely

that looks very powerful, and absolutely fits in with my goals here, of having these viewers come to the user wherever they are

It looks like it should be able to work as long as people have the portal.nrepl/wrap-notebook nrepl middleware setup ๐Ÿ”ฅ

1
1

And some slight tweaks that I'm about to merge ๐Ÿ˜†

https://github.com/djblue/portal/releases/tag/0.41.0 has all the changes so far to get things working ๐ŸŽ‰

Also, not sure if this is important to you but Portal also works for the #clr and it looks like emmy is a lot of cljc ๐Ÿค”

Tell me about this portal.nrepl/wrap-notebook middleware?!?

By default, calva notebooks pass along edn from nrepl to the portal viewer so all the rich runtime data is gone (no datafy/nav, etc...). With this middleware, portal can detect if you are in a notebook, intercept the runtime value and pass along an id, then in the notebook viewer it can hookup portal to your runtime and everything works as a normal runtime connected portal.

๐Ÿ’ฏ 1
๐Ÿคฏ 1

The following bits are enabled with the middleware: โ€ข https://cljdoc.org/d/djblue/portal/0.40.0/doc/datafy-nav โ€ข First class object support โ€ข Runtime registered commands โ€ข Larger values which are harder for edn to serialize and parse โ€ข Better error rendering

I think once calva notebooks support clojure-lsp, they are gonna be a top tier development environment

I may have done a thing ๐Ÿ˜†

(def ^:private theme-mapping
  {:fg         ::c/text
   :bg         ::background
   :line-color ::c/border
   :red        ::c/exception
   :orange     ::c/uri
   :green      ::c/string
   :blue       ::c/namespace
   :indigo     ::c/boolean
   :violet     ::c/package
   :pink       ::c/number
   :yellow     ::c/tag})

(defn- ->style [theme]
  (str
   ".MafsView {"
   (str/join
    ";"
    (reduce-kv
     (fn [out mafs portal]
       (conj out (str "--mafs-" (name mafs) ": " (get theme portal))))
     []
     theme-mapping))
   "}"))

๐ŸŽ‰ 1

I really love this

Added the wrap-notebook middleware and I'm trying out the Clojure Notebook thing... very cool! Seems it selects Portal rendering by default? (good) One downside seems to be that if you have RCFs -- (comment ...) blocks -- in your file and you tell the Notebook to "Run All", it evaluates the contents of those RCFs as well as all the top-level forms... which is kinda dangerous (given some of the code I have in RCFs!). It doesn't look like there's even a way to visually distinguish regular top-level forms from the contents of RCFs?

Is the Notebook format just fundamentally incompatible with the RCF-based approach?

(and is there a better channel to ask about this?)

The Calva integration was mostly handled by @domagala.lukas so he probably knows more about the details / limitations

I think the #calva channel might be a good place to have this convo but I'm also cool if we continue it here ๐Ÿ‘Œ

Cool, thanks. I remember seeing some discussions about it but couldn't remember where...

I think when the parser splits apart the comment form into multiple cells, it might be able to mark them as special to filter them out in this for loop. Then, the only method of evaluation would be eval'ing the cell alone.

1

I'm not at home right now so I can't link to it but there should be a github discussion on this in the calva repo

The parser already marks comment forms as special, so we can do the filtering. Iโ€™ll go ahead and do it, @domagala.lukas. Holler if you see a reason not to do this.

1

Having refreshed my memory -- since I participated quite a bit in that thread -- it seems that the restrictions with RCFs are known about but unsolved, which certainly makes it dangerous for me to use at present ๐Ÿ™‚ Issue 2210 needs to also skip RCFs in the run cells above and run cell & below commands. I'll add that note to the issue.

This VSIX should fix it https://output.circle-artifacts.com/output/job/7f57b12b-206f-444d-bbea-b622700cd2b4/artifacts/0/tmp/artifacts/calva-2.0.365-2210-rich-comment-notebook-run-all-9710d2c3.vsix Do you have time to test it, @seancorfield? Otherwise, Iโ€™ll just release it and we can fix any remaining issues later. The run cells above and below cases should be covered the way I did the filtering.

Sure, I can try it...

@djblue found a bug. ๐Ÿ˜ƒ New VSIX building.

The bug was that evaluation of cells below a comment cell would not happen either. Now they do (unless they are comment cells).

I installed that but there still seems to be a bug in Cell and Below...

Can you describe? It seems to work when I try it.

Trying to repro...

Ah, my bad, I had a defn- inside a long RCF and couldn't tell in notebook view -- and it wasn't getting evaluated, but when I scrolled down I found real top-level forms were evaluated! So it does seem correct. Thank you!

I wish there was a way to visually tell that a cell is part of an RCF ๐Ÿ˜

Yeah, that would be nice. Dunno how possible.

And ;; line comments don't appear in notebook cells (which would have clued me into this being in an RCF).

It's got a ways to go... but it's certainly a lot safer to use now! ๐Ÿ™‚

Calvaโ€™s feature for creating an RCF tucks an :rcf at the closing bracket. Thatโ€™s retained as a cell in the notebook.

Hmm, I don't see that:

I wonder if comment cells can be styled with a border or something ๐Ÿค”

Oh, @pez You mean some specific feature in Calva that inserts an RCF actually inserts this?

(comment
  
  :rcf)
I have never used that (since it's so easy to just type (comm and tab-complete to accept the RCF suggestion)!

Yeah, itโ€™s a bit of a silly feature. More for people to discover RCFs as such. But it does work well if youโ€™re inside some function and want to create (or jump to) an RCF below it.

Yeah Iโ€™d love to style them somehow. The best Iโ€™ve come up with is to show the (comment and ) as cells but that seems weird as well ๐Ÿ˜ž

And thanks @pez for quickly implementing this. At some point, we might want to make run-all for RCF optional but off by default seems like a good safety feature.