Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clerk in Babashka #232

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions bb-runtime.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{:min-bb-version "1.0.164"
:paths ["bb/stubs" "src" "notebooks" "resources"]
:deps {;; hash replacement?
io.replikativ/hasch {:mvn/version "0.3.7"}
weavejester/dependency {:mvn/version "0.2.1"}
;; shiiiiet!
;; io.github.nextjournal/markdown {:mvn/version "0.4.126"}
hiccup/hiccup {:mvn/version "2.0.0-alpha2"}
}
:tasks
{clerk
{:requires ([babashka.fs :as fs]
[babashka.nrepl.server :as srv]
[nextjournal.clerk :as clerk])
:task (do (srv/start-server! {:host "localhost" :port 1339})
(spit ".nrepl-port" "1339")
(clerk/serve! {:port 9999})
(-> (Runtime/getRuntime)
(.addShutdownHook (Thread. (fn []
(clerk/halt!)
(fs/delete ".nrepl-port")))))
(deref (promise)))}}}
3 changes: 3 additions & 0 deletions bb/stubs/multihash/core.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns multihash.core)

(defn base58 [h] "base58")
3 changes: 3 additions & 0 deletions bb/stubs/multihash/digest.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns multihash.digest)

(defn sha2-512 [o] "sha2")
4 changes: 4 additions & 0 deletions bb/stubs/nextjournal/beholder.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(ns nextjournal.beholder)

(defn watch [cb & args] nil)
(defn stop [w] nil)
41 changes: 41 additions & 0 deletions bb/stubs/nextjournal/clerk/analyzer.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
(ns nextjournal.clerk.analyzer
(:require [nextjournal.clerk.config :as config]
[edamame.core :as edamame]))

(defn valuehash [value] "hash")
(defn hash-codeblock [_ {:keys [hash]}] hash)
(defn ->hash-str [value] "hash-str")
(defn deref? [form] false)
(defn hash [doc] doc)
(defn hash-deref-deps [doc _cell] doc)

(defn build-graph [doc]
(-> doc
(assoc :->analysis-info (fn [x] {:form x}))
;; TODO: read first form, create sci.lang.Namespace
(assoc :ns *ns*)
(update :blocks
(partial into [] (map (fn [{:as b :keys [type text]}]
(cond-> b
(= :code type)
(assoc :form
(edamame/parse-string text
{:all true
:readers *data-readers*
:read-cond :allow
:regex #(list `re-pattern %)
:features #{:clj}
;; TODO:
#_#_:auto-resolve (auto-resolves (or *ns* (find-ns 'user)))})))))))))

(defn exceeds-bounded-count-limit? [x]
(reduce (fn [_ xs]
(try
(let [limit config/*bounded-count-limit*]
(if (and (seqable? xs) (<= limit (bounded-count limit xs)))
(reduced true)
false))
(catch Exception _e
(reduced true))))
false
(tree-seq seqable? seq x)))
3 changes: 3 additions & 0 deletions bb/stubs/nextjournal/markdown.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns nextjournal.markdown)

(defn parse [md] {:type :doc :content md})
3 changes: 3 additions & 0 deletions bb/stubs/nextjournal/markdown/parser.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(ns nextjournal.markdown.parser)

(defn add-title+toc [doc] doc)
4 changes: 4 additions & 0 deletions bb/stubs/nextjournal/markdown/transform.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(ns nextjournal.markdown.transform)

(defn ->text [node] "text")
(defn table-alignment [attrs] {})
5 changes: 5 additions & 0 deletions bb/stubs/taoensso/nippy.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(ns taoensso.nippy)

(defn freezable? [x] false)
(defn freeze [x] x)
(defn thaw-from-file [file] "thawed")
2 changes: 1 addition & 1 deletion resources/viewer-js-hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
46k5SeDmWgR6seZFSVzwdiCJ7BEi
3E4A2XqsHVVWy5QvM6RCuu7ScjWw
3 changes: 2 additions & 1 deletion src/nextjournal/clerk.clj → src/nextjournal/clerk.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
(throw (ex-info (str "`nextjournal.clerk/show!` cannot show `nil`.")
{:file-or-ns file-or-ns}))

(or (symbol? file-or-ns) (instance? clojure.lang.Namespace file-or-ns))
;; TODO: sci.lang.Namespace
(or (symbol? file-or-ns) (instance? #?(:bb (type *ns*) :clj clojure.lang.Namespace) file-or-ns))
(or (some (fn [ext]
(io/resource (str (str/replace (namespace-munge file-or-ns) "." "/") ext)))
[".clj" ".cljc"])
Expand Down
23 changes: 15 additions & 8 deletions src/nextjournal/clerk/eval.clj → src/nextjournal/clerk/eval.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@
[nextjournal.clerk.parser :as parser]
[nextjournal.clerk.viewer :as v]
[taoensso.nippy :as nippy])
(:import (java.awt.image BufferedImage)
(javax.imageio ImageIO)))
#?(:bb (:import)
:clj (:import (java.awt.image BufferedImage)
(javax.imageio ImageIO))))

(comment
(alter-var-root #'nippy/*freeze-serializable-allowlist* (fn [_] "allow-and-record"))
(alter-var-root #'nippy/*thaw-serializable-allowlist* (fn [_] "allow-and-record"))
(nippy/get-recorded-serializable-classes))

;; nippy tweaks
(alter-var-root #'nippy/*thaw-serializable-allowlist* (fn [_] (conj nippy/default-thaw-serializable-allowlist "java.io.File" "clojure.lang.Var" "clojure.lang.Namespace")))
(nippy/extend-freeze BufferedImage :java.awt.image.BufferedImage [x out] (ImageIO/write x "png" (ImageIO/createImageOutputStream out)))
(nippy/extend-thaw :java.awt.image.BufferedImage [in] (ImageIO/read in))
#?(:bb nil
:clj (do
(alter-var-root #'nippy/*thaw-serializable-allowlist* (fn [_] (conj nippy/default-thaw-serializable-allowlist "java.io.File" "clojure.lang.Var" "clojure.lang.Namespace")))
(nippy/extend-freeze BufferedImage :java.awt.image.BufferedImage [x out] (ImageIO/write x "png" (ImageIO/createImageOutputStream out)))
(nippy/extend-thaw :java.awt.image.BufferedImage [in] (ImageIO/read in))))

#_(-> [(clojure.java.io/file "notebooks") (find-ns 'user)] nippy/freeze nippy/thaw)

Expand Down Expand Up @@ -107,6 +110,10 @@
#_(prn :freeze-error e)
nil)))

;; NOTE: cannot add clojure.main to bb stubs
(defn ex-triage [m] #?(:bb m :clj (main/ex-triage m)))
(defn ex-str [m] #?(:bb (str m) :clj (main/ex-str m)))

(defn ^:private eval+cache! [{:keys [form var ns-effect? no-cache? freezable?] :as form-info} hash digest-file]
(try
(let [{:keys [result]} (time-ms (binding [config/*in-clerk* true]
Expand All @@ -128,8 +135,8 @@
result)]
(wrapped-with-metadata result blob-id)))
(catch Throwable t
(let [triaged (main/ex-triage (Throwable->map t))]
(throw (ex-info (main/ex-str triaged) triaged))))))
(let [triaged (ex-triage (Throwable->map t))]
(throw (ex-info (ex-str triaged) triaged))))))

(defn maybe-eval-viewers [{:as opts :nextjournal/keys [viewer viewers]}]
(cond-> opts
Expand Down Expand Up @@ -196,7 +203,7 @@
"Evaluates the given `parsed-doc` using the `in-memory-cache` and augments it with the results."
[in-memory-cache parsed-doc]
(let [{:as analyzed-doc :keys [ns]} (analyzer/build-graph parsed-doc)]
(binding [*ns* ns]
(binding [*ns* (or ns *ns*)]
(-> analyzed-doc
analyzer/hash
(assoc :blob->result in-memory-cache)
Expand Down
2 changes: 2 additions & 0 deletions src/nextjournal/clerk/sci_viewer.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
[goog.string :as gstring]
[nextjournal.clerk.viewer :as viewer :refer [code md plotly tex table vl row col with-viewer with-viewers]]
[nextjournal.clerk.parser :as clerk.parser]
[nextjournal.markdown :as markdown]
[nextjournal.markdown.transform :as md.transform]
[nextjournal.ui.components.icon :as icon]
[nextjournal.ui.components.localstorage :as ls]
Expand Down Expand Up @@ -752,6 +753,7 @@
'col col
'html html-render
'md md
'md->hiccup markdown/->hiccup
'plotly plotly
'row row
'table table
Expand Down
4 changes: 2 additions & 2 deletions src/nextjournal/clerk/view.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
(-> (merge doc opts) v/notebook v/present))))


#_(doc->viewer (nextjournal.clerk/eval-file "notebooks/hello.clj"))
#_(doc->viewer (nextjournal.clerk.eval/eval-file "notebooks/hello.clj"))
#_(nextjournal.clerk/show! "notebooks/test.clj")
#_(nextjournal.clerk/show! "notebooks/visibility.clj")

Expand Down Expand Up @@ -56,7 +56,7 @@ window.ws_send = msg => ws.send(msg)")]]))
[:head
[:title (or (and current-path (-> state :path->doc (get current-path) v/->value :title)) "Clerk")]
[:meta {:charset "UTF-8"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
(include-css+js)]
[:body
[:div#clerk-static-app]
Expand Down
48 changes: 29 additions & 19 deletions src/nextjournal/clerk/viewer.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
[applied-science.js-interop :as j]])
[nextjournal.markdown :as md]
[nextjournal.markdown.transform :as md.transform])
#?(:clj (:import (com.pngencoder PngEncoder)
#?(:bb (:import (java.nio.file Files StandardOpenOption)
(java.util Base64)
(java.lang Throwable))
:clj (:import (com.pngencoder PngEncoder)
(clojure.lang IDeref)
(java.lang Throwable)
(java.awt.image BufferedImage)
Expand Down Expand Up @@ -466,7 +469,8 @@
#?(:clj
(defn datafy-scope [scope]
(cond
(instance? clojure.lang.Namespace scope) {:namespace (-> scope str keyword)}
(instance? #?(:bb (type *ns*) :clj clojure.lang.Namespace) scope)
{:namespace (-> scope str keyword)}
(keyword? scope) scope
:else (throw (ex-info (str "Unsupported scope " scope) {:scope scope})))))

Expand Down Expand Up @@ -605,7 +609,8 @@
{:pred (fn [e] (instance? #?(:clj Throwable :cljs js/Error) e))
:name :error :render-fn 'v/throwable-viewer :transform-fn (comp mark-presented (update-val (comp demunge-ex-data datafy/datafy)))})

(def buffered-image-viewer #?(:clj {:pred #(instance? BufferedImage %)
(def buffered-image-viewer #?(:bb {}
:clj {:pred #(instance? BufferedImage %)
:transform-fn (fn [{image :nextjournal/value}]
(let [w (.getWidth image)
h (.getHeight image)
Expand All @@ -620,15 +625,16 @@
:render-fn '(fn [blob] (v/html [:figure.flex.flex-col.items-center.not-prose [:img {:src (v/url-for blob)}]]))}))

(def ideref-viewer
{:pred #(instance? IDeref %)
:transform-fn (update-val (fn [ideref]
(with-viewer :tagged-value
{:tag "object"
:value (vector (symbol (pr-str (type ideref)))
#?(:clj (with-viewer :number-hex (System/identityHashCode ideref)))
(if-let [deref-as-map (resolve 'clojure.core/deref-as-map)]
(deref-as-map ideref)
ideref))})))})
#?(:bb {} :clj
{:pred #(instance? IDeref %)
:transform-fn (update-val (fn [ideref]
(with-viewer :tagged-value
{:tag "object"
:value (vector (symbol (pr-str (type ideref)))
#?(:clj (with-viewer :number-hex (System/identityHashCode ideref)))
(if-let [deref-as-map (resolve 'clojure.core/deref-as-map)]
(deref-as-map ideref)
ideref))})))}))

(def regex-viewer
{:pred #?(:clj (partial instance? java.util.regex.Pattern) :cljs regexp?)
Expand Down Expand Up @@ -660,12 +666,16 @@
{:name :vega-lite :render-fn (quote v/vega-lite-viewer) :transform-fn mark-presented})

(def markdown-viewer
{:name :markdown :transform-fn (fn [wrapped-value]
(-> wrapped-value
mark-presented
(update :nextjournal/value #(cond->> % (string? %) md/parse))
(update :nextjournal/viewers add-viewers markdown-viewers)
(with-md-viewer)))})
(-> {:name :markdown}
#?(:bb (assoc :transform-fn (comp mark-presented (update-val :content)))
:clj (assoc :transform-fn
(fn [wrapped-value]
(-> wrapped-value
mark-presented
(update :nextjournal/value #(cond->> % (string? %) md/parse))
(update :nextjournal/viewers add-viewers markdown-viewers)
(with-md-viewer)))))
#?(:bb (assoc :render-fn '(fn [str] (js/console.log :str str) (v/html (v/md->hiccup str)))))))

(def code-viewer
{:name :code :render-fn (quote v/code-viewer) :transform-fn (comp mark-presented (update-val (fn [v] (if (string? v) v (str/trim (with-out-str (pprint/pprint v)))))))})
Expand Down Expand Up @@ -1275,7 +1285,7 @@
([viewers] (reset-viewers! *ns* viewers))
([scope viewers]
(assert (or (#{:default} scope)
#?(:clj (instance? clojure.lang.Namespace scope))))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work now in the newest bb

#?(:bb :default :clj (instance? clojure.lang.Namespace scope))))
(swap! !viewers assoc scope viewers)))

(defn add-viewers! [viewers]
Expand Down
4 changes: 2 additions & 2 deletions src/nextjournal/clerk/webserver.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
[clojure.edn :as edn]
[clojure.pprint :as pprint]
[clojure.string :as str]
[lambdaisland.uri :as uri]
[nextjournal.clerk.view :as view]
[nextjournal.clerk.viewer :as v]
[nextjournal.markdown :as md]
[org.httpkit.server :as httpkit]))

(def help-doc
{:blocks [{:type :markdown :doc (md/parse "Use `nextjournal.clerk/show!` to make your notebook appear…")}]})
{:ns *ns*
:blocks [{:type :markdown :doc (md/parse "Use `nextjournal.clerk/show!` to make your notebook appear…")}]})

(defonce !clients (atom #{}))
(defonce !doc (atom help-doc))
Expand Down