Fork me on GitHub
#clerk
<
2023-08-02
>
joshcho01:08:09

Hi all, exploring clerk. How can you customize the rendering of the source code block? I want to play with having interactive controls in the source code. Also, if interactive extensions already exist, I would love to know them. (Trying to get some ideas from something like https://github.com/fonsp/Pluto.jl)

mkvlr02:08:16

nextjournal.clerk.render.code does have an editable view, see https://github.com/nextjournal/clerk/blob/main/notebooks/viewers/code.clj for usage. Also @U9EQP1K0X has done some experiments along those lines, can you share them here?

👍 2
Andrea09:08:50

Hi @U6D1FU8F2 👋 > How can you customize the rendering of the source code block? You can override the code block rendering by redefining its render-fn by calling

(nextjournal.clerk/add-viewers!
 [(assoc nextjournal.clerk.viewer/code-block-viewer
         :render-fn '(fn [text opts] your own render logic ))])
in the notebook ns. Check the book for more context on writing viewers https://book.clerk.vision. > interactive controls in the source code I don’t fully get what you main with in the source code, but the following notebooks might also be of interest in the space of interactive controls • https://github.com/nextjournal/clerk/blob/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/notebooks/editor.cljhttps://github.com/nextjournal/clerk/blob/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/notebooks/viewers/in_text_eval.cljhttps://github.com/nextjournal/clerk/blob/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/notebooks/viewers/control_lab.clj I’m not sure which experiments in particular Martin is referring to?

👍 2
joshcho14:08:21

I am imagining something like 1) being able to hover over expressions and see what that is rendering to and 2) being able to click on variable declarations and interactively change them using sliders or selectors.

joshcho14:08:21

Oh, I actually meant the source, not rendering of the code block. So if you have a rendering of a vega lite block, I am interested in customizing the source code that is shown above the vega lite block.

Andrea14:08:33

yeah, the example I pasted above refer to that

Andrea14:08:20

For 1 I could imagine some codemirror extension for tooltips https://codemirror.net/examples/tooltip/ in combination of some sci-context machinery we used in the editor above

👍 2
Andrea14:08:59

I could be wrong, but I kind of remember something posted to #C035GRLJEP8 pretty like your point 2, but I can’t find it now 😞

joshcho14:08:18

Gotcha. I can't quite get this to work:

(nextjournal.clerk/add-viewers!
  [(assoc nextjournal.clerk.viewer/code-block-viewer
          :render-fn '(fn [text opts]
                        [:div "sample"]))])
Should I be resetting the viewers so that there are no two code-block-viewers in viewers atom? I am trying reset-viewers! but finangling it a bit.

Andrea14:08:01

that should work, as long as it’s evaluated in the namespace you’re showing. I tested with this and worked

(nextjournal.clerk/add-viewers!
    [(assoc nextjournal.clerk.viewer/code-block-viewer :render-fn '(fn [text _] [:div [:b text]]))])

Andrea14:08:28

> so that there are no two code-block-viewers in viewers atom that’s no problem, we do a linear search by name (in this case) and add-viewers! prepends the new to the default ones

👍 2
joshcho14:08:26

Oh, I had line {:nextjournal.clerk/visibility {:code :hide :result :hide}} at the very top (above ns decl), and that was messing with it. I was trying to hide the ns decl. Works now!

joshcho16:08:24

How do I define a renderer in a separate file, and then reference it? For instance, right now I have in render.cljs:

(ns app.render
  (:require
   [hyperfiddle.electric :as e]
   [hyperfiddle.electric-dom2 :as dom]))

(defn custom-render [text opts]
  [:div "HELLO"]
  ;; attempt at electric
  ;; (hyperfiddle.electric/boot
  ;;  (binding [hyperfiddle.electric-dom2/node js/document.body]
  ;;    (dom/div
  ;;      (dom/text
  ;;       "hello"))))
  )
and I have:
(clerk/with-viewer
  '(fn [code-string {:as opts :keys [id]}]
     [:div.viewer.code-viewer.w-full.max-w-wide {:data-block-id id}
      ;; [nextjournal.clerk.render.code/render-code
      ;;  code-string
      ;;  (assoc opts :language "clojure")]
      [app.render/custom-render
       code-string
       (assoc opts :language "clojure")]
      ])
  "(def fib
  (lazy-cat [0 1]
            (map + fib (rest fib))))")
I am getting the error
error in render-fn: Could not resolve symbol: app.render/custom-render
How do I let with-viewer recognize my cljs namespaces?

Andrea17:08:39

you may, either provide your own compiled js bundle or (probably easier) use clerk/eval-cljs as in https://snapshots.nextjournal.com/clerk/build/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/index.html#/notebooks/eval_cljs

mkvlr17:08:34

yes, eval-cljs or eval-cljs-str (with e.g. slurp)

joshcho17:08:21

Perfect, thank you both!

joshcho02:08:47

Tried the clerk/eval-cljs approach, but it doesn't recognize the electric namespaces. How do I provide my own compiled js bundle? Tried searching the source/book. Thank you for answering my questions, trying to build cool things on top of clerk.

mkvlr02:08:15

yeah eval-cljs doesn’t resolve dependent namespaces

joshcho02:08:18

I will give that a shot. Thank you!

joshcho01:08:07

Also, is it possible to have a predicate that runs on the results to determine which code/result pair shows vs. not? For instance, I don't want any functions to show up. If this requires some hacking, where would I need to look?

Andrea09:08:05

We have a concept of visibility https://book.clerk.vision/#visibility in Clerk, but at the moment that cannot be interacted with via the viewer API e.g. controlled on specific result types. What you could do, is override the notebook-viewer’s :transform-fn itself (similar to what I posted in the previous thread) and skip the blocks which match a your predicate. See https://github.com/nextjournal/clerk/blob/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/src/nextjournal/clerk/viewer.cljc#L1214-L1220 and https://github.com/nextjournal/clerk/blob/90ec95dadc48a6d53e1156fc7e4fb2b6959f1c9b/src/nextjournal/clerk/viewer.cljc#L621-L633

👍 2
joshcho14:08:58

Thanks, I will take a closer look.

joshcho16:08:24

How do I define a renderer in a separate file, and then reference it? For instance, right now I have in render.cljs:

(ns app.render
  (:require
   [hyperfiddle.electric :as e]
   [hyperfiddle.electric-dom2 :as dom]))

(defn custom-render [text opts]
  [:div "HELLO"]
  ;; attempt at electric
  ;; (hyperfiddle.electric/boot
  ;;  (binding [hyperfiddle.electric-dom2/node js/document.body]
  ;;    (dom/div
  ;;      (dom/text
  ;;       "hello"))))
  )
and I have:
(clerk/with-viewer
  '(fn [code-string {:as opts :keys [id]}]
     [:div.viewer.code-viewer.w-full.max-w-wide {:data-block-id id}
      ;; [nextjournal.clerk.render.code/render-code
      ;;  code-string
      ;;  (assoc opts :language "clojure")]
      [app.render/custom-render
       code-string
       (assoc opts :language "clojure")]
      ])
  "(def fib
  (lazy-cat [0 1]
            (map + fib (rest fib))))")
I am getting the error
error in render-fn: Could not resolve symbol: app.render/custom-render
How do I let with-viewer recognize my cljs namespaces?