Skip to content

Commit 2511b22

Browse files
zampinomkphilippamarkovics
authored
Make following clerk/doc-url links usable in interactive mode (#437)
Support following `clerk/doc-url` links in interactive mode. Previously these links would only be functional in the static build. Update the browser url accordingly and support evaluating a given doc by entering it in the browser's address bar. Also perform an internal refactor to drop the `!error` state atoms in both the webserver and render namespaces and store that state under a key in the `!doc` atom instead. Change `nextjournal.clerk.render/clerk-eval` to not recompute the currently shown document when using the 1-arity version. Added a second arity that takes an opts map with a `:recompute?` key. Co-authored-by: Martin Kavalar <[email protected]> Co-authored-by: Philippa Markovics <[email protected]>
1 parent 86fd28d commit 2511b22

File tree

16 files changed

+311
-131
lines changed

16 files changed

+311
-131
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Changes can be:
44
* 🌟⭐️💫 features
5+
* 🚨 possibly breaking
56
* 🐞🐜 friendly or nasty bugs
67
* 🛠 dev improvements
78

@@ -13,8 +14,14 @@ Changes can be:
1314

1415
* 🍕 `clerk/fragment` for splicing a seq of values into the document as if it were produced by results of individual cells. Useful when programmatically generating content.
1516

17+
* 🔗 Support following `clerk/doc-url` links in interactive mode. Previously these links would only be functional in the static build. Update the browser url accordingly and support evaluating a given doc by entering it in the browser's address bar.
18+
19+
* 🚨 Change `nextjournal.clerk.render/clerk-eval` to not recompute the currently shown document when using the 1-arity version. Added a second arity that takes an opts map with a `:recompute?` key.
20+
1621
* 🔌 Make websocket reconnect automatically on close to avoid having to reload the page
22+
1723
* 💫 Cache expressions that return `nil` in memory
24+
1825
* 🐜 Ensure custom `print-method` supporting unreadable symbols preserves metadata
1926

2027
## 0.13.842 (2023-03-07)

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,3 @@ You can use the following BibTeX citation:
151151
year = 2023
152152
}
153153
```
154-

book.clj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,9 +457,8 @@ v/default-viewers
457457

458458

459459
^{::clerk/visibility {:code :fold :result :hide}}
460-
(do
461-
(set! *print-namespace-maps* false)
462-
(defn show-raw-value [x]
460+
(defn show-raw-value [x]
461+
(binding [*print-namespace-maps* false]
463462
(clerk/code (with-out-str (clojure.pprint/pprint x)))))
464463

465464
;; Let's start with one of the simplest examples. You can see that

deps.edn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
juji/editscript {:mvn/version "0.6.2"}}
2626

27-
:aliases {:nextjournal/clerk {:extra-deps {org.clojure/clojure {:mvn/version "1.11.1"} ;; for `:as-alias` support in static build
27+
:aliases {:nextjournal/clerk {:extra-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha3"} ;; for `:as-alias` support in static build
2828
org.slf4j/slf4j-nop {:mvn/version "1.7.36"}
2929
org.babashka/cli {:mvn/version "0.6.50"}}
3030
:extra-paths ["notebooks"]

notebooks/clerk_eval.clj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22
(ns clerk-eval
33
{:nextjournal.clerk/visibility {:code :fold}}
44
(:require [nextjournal.clerk :as clerk]
5-
[nextjournal.clerk.render.hooks :as-alias hooks]
65
[nextjournal.clerk.viewer :as v]))
76

87
(clerk/with-viewer
98
'(fn [code-str _]
10-
(let [!code (hooks/use-state code-str)
11-
!result (hooks/use-state nil)]
9+
(let [!code (nextjournal.clerk.render.hooks/use-state code-str)
10+
!result (nextjournal.clerk.render.hooks/use-state nil)]
1211
[:div
1312
[:p "Enter a form to be evaluated using " [:code "v/clerk-eval"] ":"]
1413
[:div.flex.mb-4
1514
[:div.shadow-inner.border.rounded.bg-slate-100.px-2.py-1.flex-auto
1615
[nextjournal.clerk.render.code/editor !code]]
1716
[:button.rounded.px-3.py-1.bg-indigo-600.text-white.font-sans.font-bold.ml-2
18-
{:on-click #(reset! !result (v/clerk-eval (read-string @!code)))}
17+
{:on-click #(reset! !result (nextjournal.clerk.render/clerk-eval (read-string @!code)))}
1918
"eval!"]]
2019
(when @!result
2120
[nextjournal.clerk.render/inspect @!result])]))

notebooks/dice.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
(when side
1616
[:div.mt-2 {:style {:font-size "6em"}} side])
1717
[:button.bg-blue-500.hover:bg-blue-700.text-white.font-bold.py-2.px-4.rounded
18-
{:on-click (fn [e] (nextjournal.clerk.render/clerk-eval '(roll!)))} "Roll 🎲!"]])}
18+
{:on-click (fn [e] (nextjournal.clerk.render/clerk-eval {:recompute? true} '(roll!)))} "Roll 🎲!"]])}
1919
@dice
2020

2121
;; Our roll! function `resets!` our `dice` with a random side and prints and says the result. Finally it updates the notebook.

notebooks/document_linking.clj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
;; # 🖇️ Document Linking
2+
(ns document-linking
3+
(:require [nextjournal.clerk :as clerk]))
4+
5+
;; The helper `clerk/doc-url` allows to reference notebooks by path. We currently support relative paths with respect to the directory which started the Clerk application. An optional trailing hash fragment can appended to the path in order for the page to be scrolled up to the indicated identifier.
6+
(clerk/html
7+
[:ol
8+
[:li [:a {:href (clerk/doc-url "notebooks/viewers/html.clj")} "HTML"]]
9+
[:li [:a {:href (clerk/doc-url "notebooks/viewers/image.clj")} "Images"]]
10+
[:li [:a {:href (clerk/doc-url "notebooks/markdown.md" "appendix")} "Markdown / Appendix"]]
11+
[:li [:a {:href (clerk/doc-url "notebooks/how_clerk_works.clj" "step-3:-analyzer")} "Clerk Analyzer"]]
12+
[:li [:a {:href (clerk/doc-url "book.clj")} "The 📕Book"]]
13+
[:li [:a {:href (clerk/doc-url "")} "Homepage"]]])
14+
15+
;; The same functionality is available in the SCI context when building render functions.
16+
(clerk/with-viewer
17+
'(fn [_ _]
18+
[:ol
19+
[:li [:a {:href (nextjournal.clerk.viewer/doc-url "notebooks/viewers/html.clj")} "HTML"]]
20+
[:li [:a {:href (nextjournal.clerk.viewer/doc-url "notebooks/markdown.md")} "Markdown"]]
21+
[:li [:a {:href (nextjournal.clerk.viewer/doc-url "notebooks/viewer_api.clj")} "Viewer API / Tables"]]]) nil)

notebooks/viewers/html.clj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717

1818
(clerk/with-viewer
1919
'(fn [_ _] [:div
20-
"Go to "
21-
[:a.text-lg {:href (nextjournal.clerk.viewer/doc-url "notebooks/viewers/image.clj")} "images"]
22-
" notebook."]) nil)
20+
"Go to "
21+
[:a.text-lg {:href (nextjournal.clerk.viewer/doc-url "notebooks/viewers/image.clj")} "images"]
22+
" notebook."]) nil)
2323

2424
(clerk/html
25-
[:ol (list [:li "One"]
26-
[:li "Two"]
27-
[:li "Three"])])
25+
[:ol (list [:li [:a {:href (clerk/doc-url "notebooks/document_linking.clj")} "Cross Document Linking"]]
26+
[:li [:a {:href (clerk/doc-url "notebooks/rule_30.clj")} "Rule 30"]]
27+
[:li [:a {:href (clerk/doc-url "notebooks/markdown.md")} "Appendix"]])])

src/nextjournal/clerk.clj

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,46 @@
3030
(nextjournal.clerk/show! \"https://raw.githubusercontent.com/nextjournal/clerk-demo/main/notebooks/rule_30.clj\")
3131
(nextjournal.clerk/show! (java.io.StringReader. \";; # Notebook from String 👋\n(+ 41 1)\"))
3232
"
33-
[file-or-ns]
34-
(if config/*in-clerk*
35-
::ignored
36-
(try
37-
(webserver/set-status! {:progress 0 :status "Parsing…"})
38-
(let [file (cond
39-
(nil? file-or-ns)
40-
(throw (ex-info (str "`nextjournal.clerk/show!` cannot show `nil`.")
41-
{:file-or-ns file-or-ns}))
42-
43-
(or (symbol? file-or-ns) (instance? clojure.lang.Namespace file-or-ns))
44-
(or (some (fn [ext]
45-
(io/resource (str (str/replace (namespace-munge file-or-ns) "." "/") ext)))
46-
[".clj" ".cljc"])
47-
(throw (ex-info (str "`nextjournal.clerk/show!` could not find a resource on the classpath for: `" (pr-str file-or-ns) "`")
48-
{:file-or-ns file-or-ns})))
49-
50-
:else
51-
file-or-ns)
52-
doc (try (parser/parse-file {:doc? true} file)
53-
(catch java.io.FileNotFoundException _e
54-
(throw (ex-info (str "`nextjournal.clerk/show!` could not find the file: `" (pr-str file-or-ns) "`")
55-
{:file-or-ns file-or-ns}))))
56-
_ (reset! !last-file file)
57-
{:keys [blob->result]} @webserver/!doc
58-
{:keys [result time-ms]} (eval/time-ms (eval/+eval-results blob->result (assoc doc :set-status-fn webserver/set-status!)))]
59-
(println (str "Clerk evaluated '" file "' in " time-ms "ms."))
60-
(webserver/update-doc! result))
61-
(catch Exception e
62-
(webserver/show-error! e)
63-
(throw e)))))
33+
([file-or-ns] (show! {} file-or-ns))
34+
([opts file-or-ns]
35+
(if config/*in-clerk*
36+
::ignored
37+
(try
38+
(webserver/set-status! {:progress 0 :status "Parsing…"})
39+
(let [file (cond
40+
(nil? file-or-ns)
41+
(throw (ex-info (str "`nextjournal.clerk/show!` cannot show `nil`.")
42+
{:file-or-ns file-or-ns}))
43+
44+
(or (symbol? file-or-ns) (instance? clojure.lang.Namespace file-or-ns))
45+
(or (some (fn [ext]
46+
(io/resource (str (str/replace (namespace-munge file-or-ns) "." "/") ext)))
47+
[".clj" ".cljc"])
48+
(throw (ex-info (str "`nextjournal.clerk/show!` could not find a resource on the classpath for: `" (pr-str file-or-ns) "`")
49+
{:file-or-ns file-or-ns})))
50+
51+
:else
52+
file-or-ns)
53+
doc (try (merge opts
54+
{:nav-path (webserver/->nav-path file-or-ns)}
55+
(parser/parse-file {:doc? true} file))
56+
(catch java.io.FileNotFoundException _e
57+
(throw (ex-info (str "`nextjournal.clerk/show!` could not find the file: `" (pr-str file-or-ns) "`")
58+
{:file-or-ns file-or-ns})))
59+
(catch Exception e
60+
(throw (ex-info (str "`nextjournal.clerk/show!` could not not parse the file: `" (pr-str file-or-ns) "`")
61+
{::doc {:file file-or-ns}}
62+
e))))
63+
_ (reset! !last-file file)
64+
{:keys [blob->result]} @webserver/!doc
65+
{:keys [result time-ms]} (try (eval/time-ms (eval/+eval-results blob->result (assoc doc :set-status-fn webserver/set-status!)))
66+
(catch Exception e
67+
(throw (ex-info (str "`nextjournal.clerk/show!` encountered an eval error with: `" (pr-str file-or-ns) "`") {::doc doc} e))))]
68+
(println (str "Clerk evaluated '" file "' in " time-ms "ms."))
69+
(webserver/update-doc! result))
70+
(catch Exception e
71+
(webserver/update-doc! (assoc (-> e ex-data ::doc) :error e))
72+
(throw e))))))
6473

6574
#_(show! "notebooks/exec_status.clj")
6675
#_(clear-cache!)
@@ -373,7 +382,7 @@
373382
"Experimental notebook viewer. You probably should not use this."
374383
(partial with-viewer (:name v/notebook-viewer)))
375384

376-
(defn doc-url [path] (v/doc-url path))
385+
(defn doc-url [& args] (apply v/doc-url args))
377386

378387
(defmacro example
379388
"Evaluates the expressions in `body` showing code next to results in Clerk.

src/nextjournal/clerk/builder.clj

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,14 @@
284284
(fs/delete-tree tw-folder)
285285
(update opts :resource->url assoc "/css/viewer.css" url))))
286286

287-
(defn doc-url [{:as opts :keys [bundle?]} docs file path]
288-
(let [url (get (build-path->url opts docs) path)]
289-
(if bundle?
290-
(str "#/" url)
291-
(str (viewer/relative-root-prefix-from (viewer/map-index opts file)) url))))
287+
(defn doc-url
288+
([opts doc file path] (doc-url opts doc file path nil))
289+
([{:as opts :keys [bundle?]} docs file path fragment]
290+
(let [url (get (build-path->url opts docs) path)]
291+
(if bundle?
292+
(str "#/" url)
293+
(str (viewer/relative-root-prefix-from (viewer/map-index opts file))
294+
url (when fragment (str "#" fragment)))))))
292295

293296
(defn build-static-app! [{:as opts :keys [bundle?]}]
294297
(let [{:as opts :keys [download-cache-fn upload-cache-fn report-fn compile-css? expanded-paths error]}

0 commit comments

Comments
 (0)