Skip to content

Commit

Permalink
Viewer API: support setting :nextjournal/width
Browse files Browse the repository at this point in the history
For both functional and metadata api.
  • Loading branch information
mk committed Jan 27, 2022
1 parent 571bf11 commit 20afc21
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 43 deletions.
3 changes: 3 additions & 0 deletions notebooks/viewer_api.clj
Expand Up @@ -21,6 +21,9 @@
;; Alternatively you can pass it an HTML string.
(clerk/html "Never <strong>forget</strong>.")

;; ### 🔢 Tables
;; The table viewer api take a number of formats. Each viewer also takes an optional map as a first argument for customization.
(clerk/table {::clerk/width :full} (into (sorted-map) (map (fn [c] [(keyword (str c)) (shuffle (range 5))])) "abcdefghiklmno"))

;; ### 📑 Markdown
;; The Markdown viewer is useful for programmatically generated markdown.
Expand Down
58 changes: 33 additions & 25 deletions src/nextjournal/clerk.clj
Expand Up @@ -116,6 +116,10 @@
result)]
(wrapped-with-metadata result visibility blob-id))))

(defn maybe-resolve-viewer [{:as opts :nextjournal/keys [viewer]}]
(cond-> opts
(symbol? viewer)
(update :nextjournal/viewer resolve)))

(defn read+eval-cached [results-last-run ->hash doc-visibility codeblock]
(let [{:keys [ns-effect? form var]} codeblock
Expand All @@ -129,8 +133,10 @@
cached-result? (and (not no-cache?)
cas-hash
(-> cas-hash ->cache-file fs/exists?))
viewer-on-form-meta (let [v (-> form meta ::viewer)]
(cond-> v (symbol? v) resolve))]
opts-from-form-meta (-> (meta form)
(select-keys [::viewer ::width])
v/normalize-viewer-opts
maybe-resolve-viewer)]
#_(prn :cached? (cond no-cache? :no-cache
cached-result? true
cas-hash :no-cas-file
Expand All @@ -140,19 +146,19 @@
(cond-> (or (when cached-result?
(lookup-cached-result results-last-run var hash cas-hash visibility))
(eval+cache! form hash digest-file var no-cache? visibility))
viewer-on-form-meta (assoc :nextjournal/viewer viewer-on-form-meta))))
(seq opts-from-form-meta)
(merge opts-from-form-meta))))

#_(eval-file "notebooks/test123.clj")
#_(eval-file "notebooks/how_clerk_works.clj")
#_(read+eval-cached {} {} #{:show} "(subs (slurp \"/usr/share/dict/words\") 0 1000)")

(defn clear-cache!
([]
(if (fs/exists? config/cache-dir)
(do
(fs/delete-tree config/cache-dir)
(prn :cache-dir/deleted config/cache-dir))
(prn :cache-dir/does-not-exist config/cache-dir))))
(defn clear-cache! []
(if (fs/exists? config/cache-dir)
(do
(fs/delete-tree config/cache-dir)
(prn :cache-dir/deleted config/cache-dir))
(prn :cache-dir/does-not-exist config/cache-dir)))


(defn blob->result [blocks]
Expand All @@ -162,14 +168,14 @@
#_(blob->result @nextjournal.clerk.webserver/!doc)

(defn +eval-results [results-last-run parsed-doc]
(let [{:as info :keys [doc]} (hashing/build-graph parsed-doc) ;; TODO: clarify that this returns an analyzed doc
->hash (hashing/hash info)
{:keys [blocks visibility]} doc
blocks (into [] (map (fn [{:as cell :keys [type]}]
(cond-> cell
(= :code type)
(assoc :result (read+eval-cached results-last-run ->hash visibility cell))))) blocks)]
(assoc parsed-doc :blocks blocks :blob->result (blob->result blocks) :ns *ns*)))
(let [{:as info :keys [doc]} (hashing/build-graph parsed-doc) ;; TODO: clarify that this returns an analyzed doc
->hash (hashing/hash info)
{:keys [blocks visibility]} doc
blocks (into [] (map (fn [{:as cell :keys [type]}]
(cond-> cell
(= :code type)
(assoc :result (read+eval-cached results-last-run ->hash visibility cell))))) blocks)]
(assoc parsed-doc :blocks blocks :blob->result (blob->result blocks) :ns *ns*)))

(defn parse-file [file]
(hashing/parse-file {:doc? true} file))
Expand Down Expand Up @@ -245,13 +251,15 @@

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; public viewer api
(def md v/md)
(def plotly v/plotly)
(def vl v/vl)
(def tex v/tex)
(def notebook v/notebook)
(def html v/html)
(def code v/code)

;; these are refercing vars for convience when working at the REPL
(def md #'v/md)
(def plotly #'v/plotly)
(def vl #'v/vl)
(def tex #'v/tex)
(def notebook #'v/notebook)
(def html #'v/html)
(def code #'v/code)
(def table #'v/table)
(def use-headers #'v/use-headers)
(def hide-result #'v/hide-result)
Expand Down
11 changes: 6 additions & 5 deletions src/nextjournal/clerk/view.clj
Expand Up @@ -106,8 +106,9 @@
base64-encode-value)
described-result))

(defn ->result [ns {:nextjournal/keys [value blob-id]} lazy-load?]
(let [described-result (extract-blobs lazy-load? blob-id (v/describe value {:viewers (v/get-viewers ns (v/viewers value))}))]
(defn ->result [ns {:as result :nextjournal/keys [value blob-id]} lazy-load?]
(let [described-result (extract-blobs lazy-load? blob-id (v/describe value {:viewers (v/get-viewers ns (v/viewers value))}))
opts-from-form-meta (select-keys result [:nextjournal/width])]
(merge {:nextjournal/viewer :clerk/result
:nextjournal/value (cond-> (try {:nextjournal/edn (->edn described-result)}
(catch Throwable _e
Expand All @@ -118,8 +119,8 @@
lazy-load?
(assoc :nextjournal/fetch-opts {:blob-id blob-id}
:nextjournal/hash (->hash-str [blob-id (selected-viewers described-result)])))}

(dissoc described-result :nextjournal/value :nextjournal/viewer))))
(dissoc described-result :nextjournal/value :nextjournal/viewer)
opts-from-form-meta)))

#_(nextjournal.clerk/show! "notebooks/hello.clj")
#_(nextjournal.clerk/show! "notebooks/viewers/image.clj")
Expand Down Expand Up @@ -173,7 +174,7 @@
v/notebook
(cond-> ns (assoc :scope (v/datafy-scope ns))))))

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

Expand Down
26 changes: 14 additions & 12 deletions src/nextjournal/clerk/viewer.cljc
Expand Up @@ -2,6 +2,7 @@
(:require [clojure.string :as str]
[clojure.pprint :as pprint]
[clojure.datafy :as datafy]
[clojure.set :as set]
[clojure.walk :as w]
#?@(:clj [[clojure.repl :refer [demunge]]
[nextjournal.clerk.config :as config]]
Expand Down Expand Up @@ -205,8 +206,8 @@
{:name :plotly :render-fn (quote v/plotly-viewer) :fetch-fn fetch-all}
{:name :vega-lite :render-fn (quote v/vega-lite-viewer) :fetch-fn fetch-all}
{:name :markdown :render-fn (quote v/markdown-viewer) :fetch-fn fetch-all}
{:name :code :render-fn (quote v/code-viewer) :fetch-fn fetch-all}
{:name :code-folded :render-fn (quote v/foldable-code-viewer) :fetch-fn fetch-all}
{:name :code :render-fn (quote v/code-viewer) :fetch-fn fetch-all :transform-fn #(let [v (value %)] (if (string? v) v (with-out-str (pprint/pprint v))))}
{:name :code-folded :render-fn (quote v/foldable-code-viewer) :fetch-fn fetch-all :transform-fn #(let [v (value %)] (if (string? v) v (with-out-str (pprint/pprint v))))}
{:name :reagent :render-fn (quote v/reagent-viewer) :fetch-fn fetch-all}
{:name :eval! :render-fn (constantly 'nextjournal.clerk.viewer/set-viewers!)}
{:name :table :render-fn (quote v/table-viewer) :fetch-opts {:n 5}
Expand Down Expand Up @@ -538,18 +539,23 @@
#_(registration? (set-viewers! []))
#_(nextjournal.clerk/show! "notebooks/viewers/vega.clj")

(defn normalize-viewer-opts [opts]
(set/rename-keys opts {:nextjournal.clerk/viewer :nextjournal/viewer
:nextjournal.clerk/width :nextjournal/width}))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; public api

(defn with-viewer
"Wraps given "
([viewer x] (with-viewer viewer {} x))
([viewer opts x]
(merge opts (-> x
wrap-value
(assoc :nextjournal/viewer (cond-> viewer
(or (list? viewer) (symbol? viewer))
->viewer-fn))))))
(merge (normalize-viewer-opts opts)
(-> x
wrap-value
(assoc :nextjournal/viewer (cond-> viewer
(or (list? viewer) (symbol? viewer))
->viewer-fn))))))

#_(with-viewer :latex "x^2")
#_(with-viewer '#(v/html [:h3 "Hello " % "!"]) "x^2")
Expand All @@ -576,8 +582,4 @@
(def notebook (partial with-viewer :clerk/notebook))
(defn doc-url [path]
(->viewer-eval (list 'v/doc-url path)))

(defn code [x]
(with-viewer :code (if (string? x) x (with-out-str (pprint/pprint x)))))

#_(code '(+ 1 2))
(def code (partial with-viewer :code))
21 changes: 20 additions & 1 deletion test/nextjournal/clerk_test.clj
Expand Up @@ -5,7 +5,8 @@
[clojure.test :refer :all]
[matcher-combinators.test :refer [match?]]
[nextjournal.clerk :as clerk]
[nextjournal.clerk.hashing :as hashing])
[nextjournal.clerk.hashing :as hashing]
[nextjournal.clerk.view :as view])
(:import (java.io File)))

(deftest url-canonicalize
Expand Down Expand Up @@ -81,3 +82,21 @@
(clerk/eval-string "^{:nextjournal.clerk/viewer nextjournal.clerk/table} (def markup [:h1 \"hi\"])")))
(is (match? {:blocks [{:result {:nextjournal/viewer :html}}]}
(clerk/eval-string "^{:nextjournal.clerk/viewer :html} (def markup [:h1 \"hi\"])")))))

(deftest eval-string+doc->viewer
(testing "assigns the correct width from form meta"
(is (match? [{:nextjournal/width :full}
{:nextjournal/width :wide}]
(-> "^{:nextjournal.clerk/visibility :hide} (ns clerk-test-width)
^{:nextjournal.clerk/viewer :table :nextjournal.clerk/width :full}
(def dataset
[[1 2] [3 4]])
^{:nextjournal.clerk/viewer :html :nextjournal.clerk/width :wide}
[:div.bg-red-200 [:h1 \"Wide Hiccup\"]]
"
clerk/eval-string
view/doc->viewer
:nextjournal/value
:blocks)))))

0 comments on commit 20afc21

Please sign in to comment.