This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-23
Channels
- # announcements (3)
- # architecture (10)
- # babashka (37)
- # beginners (69)
- # calva (2)
- # cider (10)
- # clerk (22)
- # clj-kondo (33)
- # cljdoc (44)
- # clojure (45)
- # clojure-conj (4)
- # clojure-denmark (7)
- # clojure-europe (14)
- # clojure-nl (1)
- # clojure-norway (5)
- # clojure-uk (4)
- # clojurescript (10)
- # clr (19)
- # conjure (1)
- # emacs (28)
- # events (1)
- # fulcro (1)
- # jobs (1)
- # joyride (1)
- # lsp (18)
- # malli (30)
- # membrane (3)
- # off-topic (23)
- # pathom (45)
- # portal (29)
- # proletarian (7)
- # rdf (15)
- # re-frame (21)
- # reagent (2)
- # releases (6)
- # remote-jobs (1)
- # reveal (6)
- # shadow-cljs (36)
- # slack-help (7)
- # sql (5)
- # tools-deps (3)
I made a proof-of-concept to combine the cider-inspector
and Clerk
and quite like it.
The idea is that while in the cider-inspector
I can press a key, and the current value gets then send to Clerk and is rendered in browser via Clerks tap inspector.
So I can still navigate complex data structures with the cider-inspector
as usual, and at any given point in time render the current value with Clerk.
As I have little clue on Cider and EmacsLisp I just hacked the existing
cider-inspector-def-current-val
and added a "tapping" of the value to it.
(just to see f it works)
(defun cider-inspector-def-current-val (var-name ns)
"Defines a var with VAR-NAME in current namespace.
Doesn't modify current page. When called interactively NS defaults to
current-namespace."
(interactive (let ((ns (cider-current-ns)))
(list (read-from-minibuffer (concat "Var name: " ns "/"))
ns)))
(setq cider-inspector--current-repl (cider-current-repl))
(when-let* ((value (cider-sync-request:inspect-def-current-val ns var-name)))
(cider-interactive-eval (concat "(tap> " ns "/" var-name ")"))
(cider-inspector--render-value value)
(message "%s#'%s/%s = %s" cider-eval-result-prefix ns var-name value)
))
Then I can setup the Clerk tap inspector:
(nextjournal.clerk/show! 'nextjournal.clerk.tap)
Now I can call cider-inspector-def-current-value
while in cider-inspector and it will render the current value in Clerk.So I think it would be cool, if the cider inspector could gain a new function to tap the current value. cider-inspector-tap-current-value
To have a "full integration" of Cider and Clerk, one piece is still missing: When "render" a value like above in clerk, we need to have a way to "choose a Clerk viewer". In Clerk itself this goes via code, using specific functions. I made an other proof of concept, in which Emacs asks the user to select a viewer from a list and wrap the value with the needed metadata before tapping, and then Clerk would use the selected viewer in the tap inspector:
(setq clerk-viewer-list '("default"
":html"
":latex"
":table"
"nextjournal.clerk.viewer/html-viewer"
"nextjournal.clerk.viewer/vega-lite-viewer"
"nextjournal.clerk.viewer/map-viewer"
"nextjournal.clerk.viewer/markdown-viewer"
"nextjournal.clerk.viewer/katex-viewer"
"nextjournal.clerk.viewer/fallback-viewer"
"nextjournal.clerk.viewer/string-viewer"))
(defun clerk-tap-last-sexp-with-viewer (viewer)
(interactive
(list (completing-read "Choose viewer: " clerk-viewer-list nil t)))
(let ((tapped-form (concat "(clojure.core/->> "
(cider-last-sexp)
(if (equal "default" viewer)
(concat " (nextjournal.clerk/with-viewer {:transform-fn identity})")
(if (string-prefix-p ":" viewer)
(concat " (nextjournal.clerk/with-viewer " "(keyword \"" (substring viewer 1) "\")" ")")
(concat " (nextjournal.clerk/with-viewer " "(symbol \"" viewer "\")" ")"))
)
" (clojure.core/tap>))")))
(cider-interactive-eval tapped-form
nil
nil
(cider--nrepl-pr-request-map))))
This code is Clerk specific, so should probably not be in Cider. But Cider would need to "call back" as part of the cider-inspector to ask the user to select the viewer, to get this nicely working....
But maybe we could start by adding a function cider-inspector-tap-current-value
to Cider ?
Then we could make a basic integration with Clerk's tap inspector (without viewer selection) outside cider
If somebody want to play with it, the following emacs lisp function can be used while in cider-inspector
without changing any cider code:
(defun cider-inspector-tap-current-val ()
(interactive)
(setq cider-inspector--current-repl (cider-current-repl))
(when-let* ((ns "user")
(var-name "cider-inspector-temp-hdhsad")
(value (cider-sync-request:inspect-def-current-val ns var-name)))
(cider-interactive-eval (concat "(tap> " ns "/" var-name ")"))
(cider-inspector--render-value value)
(message "%s#'%s/%s = %s" cider-eval-result-prefix ns var-name value)
))
It will def
the current value of the cider-inspector (using a fixed var name) and then tap>
it.
If the Clerk tap inspector is open, it will then render it.
Other Clojure value inspectors, like Portal and Reveal can as well be setup as tap> targets.
So it would work the same way for those, not only Clerk.The following add the interactive viewer selection to it:
(setq clerk-viewer-list '("default"
":html"
":latex"
":table"
"nextjournal.clerk.viewer/html-viewer"
"nextjournal.clerk.viewer/vega-lite-viewer"
"nextjournal.clerk.viewer/map-viewer"
"nextjournal.clerk.viewer/markdown-viewer"
"nextjournal.clerk.viewer/katex-viewer"
"nextjournal.clerk.viewer/fallback-viewer"
"nextjournal.clerk.viewer/string-viewer"))
(defun cider-inspector-tap-current-val-with-viewer (viewer)
(interactive
(list (completing-read "Choose viewer: " clerk-viewer-list nil t)))
(setq cider-inspector--current-repl (cider-current-repl))
(when-let* ((ns "user")
(var-name "cider-inspector-temp-hdhsad")
(value (cider-sync-request:inspect-def-current-val ns var-name)))
(let ((tapped-form (concat "(clojure.core/->> "
(concat ns "/" var-name)
(if (equal "default" viewer)
(concat " (nextjournal.clerk/with-viewer {:transform-fn identity})")
(if (string-prefix-p ":" viewer)
(concat " (nextjournal.clerk/with-viewer " "(keyword \"" (substring viewer 1) "\")" ")")
(concat " (nextjournal.clerk/with-viewer " "(symbol \"" viewer "\")" ")"))
)
" (clojure.core/tap>))")))
(cider-interactive-eval tapped-form
nil
nil
(cider--nrepl-pr-request-map)))
(cider-inspector--render-value value)
(message "%s#'%s/%s = %s" cider-eval-result-prefix ns var-name value)
))
Calling cider-inspector-tap-current-val-with-viewer
while in cider-inspector
will first ask for a viewer to pick (:table for table viewer) and then it tap>
the current inspector value wrapped in Clerk metadata which chooses the viewer .
Clerk tap inspector will then show it as table (or in any other viewer selected before)The Portal docu assumes as well that the "correct viewer" can be selected automatically by "looking at the value". In my view this does not work "in general", for all cases. To detect that a "map" is "vega lite" is not easy and will not work for "all graphic formats". So the "user" need to be "asked" about the "viewer to use". (or we assume "code")
But maybe we could start by adding a function cider-inspector-tap-current-value
to Cider ?
Then we could make a basic integration with Clerk's tap inspector (without viewer selection) outside cider