Skip to content

Commit cdee8a8

Browse files
committed
parent 4b959df
author Andrea Amantini <[email protected]> 1680188333 +0200 committer Andrea Amantini <[email protected]> 1693237293 +0200 Add internal-link tokenizer Make basic example functional Allow internal links to namespaces Make internal link scroll to var Put the notebook title as link content Make linter happy Refactor Fix hash fragment in links to var Omit reader quote-var dispatch in link text Kondo Include notebook presentation in doc-url rebinding scope Simplify Explain Coherent keys Handle fragments from vars Naming Reduce noise
1 parent c91a41f commit cdee8a8

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

src/nextjournal/clerk/parser.cljc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,15 +287,17 @@
287287

288288
(defn markdown-context []
289289
(update markdown.parser/empty-doc
290-
:text-tokenizers (partial map markdown.parser/normalize-tokenizer)))
291-
292-
#_(markdown-context)
290+
:text-tokenizers
291+
(comp (partial mapv markdown.parser/normalize-tokenizer)
292+
(partial cons markdown.parser/internal-link-tokenizer))))
293293

294294
(defn parse-markdown
295295
"Like `n.markdown.parser/parse` but allows to reuse the same context in successive calls"
296296
[ctx md]
297297
(markdown.parser/apply-tokens ctx (markdown/tokenize md)))
298298

299+
#_(parse-markdown-string {:doc? true} "# Title\nSome [[internal-link]] to be followed.")
300+
299301
(defn update-markdown-blocks [{:as state :keys [md-context]} md]
300302
(let [{::markdown.parser/keys [path]} md-context
301303
doc (parse-markdown md-context md)
@@ -348,9 +350,7 @@
348350
state))))
349351

350352
#_(parse-clojure-string {:doc? true} "'code ;; foo\n;; bar")
351-
#_(parse-clojure-string "'code , ;; foo\n;; bar")
352353
#_(parse-clojure-string "'code\n;; foo\n;; bar")
353-
#_(keys (parse-clojure-string {:doc? true} (slurp "notebooks/viewer_api.clj")))
354354
#_(parse-clojure-string {:doc? true} ";; # Hello\n;; ## 👋 Section\n(do 123)\n;; ## 🤚🏽 Section")
355355

356356
(defn parse-markdown-cell [{:as state :keys [nodes]} opts]

src/nextjournal/clerk/render.cljs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@
865865
[:path {:fill-rule "evenodd" :d "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" :clip-rule "evenodd"}]])
866866

867867
(defn render-code-block [code-string {:as opts :keys [id]}]
868-
[:div.viewer.code-viewer.w-full.max-w-wide {:data-block-id id}
868+
[:div.viewer.code-viewer.w-full.max-w-wide {:id id}
869869
[code/render-code code-string (assoc opts :language "clojure")]])
870870

871871
(defn render-folded-code-block [code-string {:as opts :keys [id]}]

src/nextjournal/clerk/viewer.cljc

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
(java.nio.file Files StandardOpenOption)
3232
(javax.imageio ImageIO))))
3333

34+
(declare doc-url)
35+
3436
(defrecord ViewerEval [form])
3537

3638
(defrecord ViewerFn [form #?(:cljs f)]
@@ -714,6 +716,43 @@
714716
(doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00")
715717
(.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))
716718

719+
#?(:clj (defn resolve-internal-link [link]
720+
(if (fs/exists? link)
721+
{:path link}
722+
(let [sym (symbol link)]
723+
(if (qualified-symbol? sym)
724+
(when-some [var (try (requiring-resolve sym)
725+
(catch Exception _ nil))]
726+
(merge {:var var} (resolve-internal-link (-> var symbol namespace))))
727+
(when-some [ns (try (require sym)
728+
(find-ns sym)
729+
(catch Exception _ nil))]
730+
(cond-> {:ns ns}
731+
(fs/exists? (analyzer/ns->file sym))
732+
(assoc :path (analyzer/ns->file sym)))))))))
733+
734+
#_(resolve-internal-link "notebooks/hello.clj")
735+
#_(resolve-internal-link "nextjournal.clerk.tap")
736+
#_(resolve-internal-link "rule-30/board")
737+
738+
(defn process-internal-link [link]
739+
#?(:clj
740+
(let [{:keys [path var]} (resolve-internal-link link)]
741+
{:path path
742+
:fragment (when var (str (-> var symbol str) "-code"))
743+
:title (or (when var (-> var symbol str))
744+
(when path (:title (parser/parse-file {:doc? true} path)))
745+
link)})
746+
:cljs
747+
{:path link :title link}))
748+
749+
#_(process-internal-link "notebooks/rule_30.clj")
750+
#_(process-internal-link "viewers.html")
751+
#_(process-internal-link "how-clerk-works/hashes")
752+
#_(process-internal-link "rule-30/first-generation")
753+
754+
(declare html)
755+
717756
(def markdown-viewers
718757
[{:name :nextjournal.markdown/doc
719758
:transform-fn (into-markup (fn [{:keys [id]}] [:div.viewer.markdown-viewer.w-full.max-w-prose.px-8 {:data-block-id id}]))}
@@ -742,6 +781,11 @@
742781
{:name :nextjournal.markdown/monospace :transform-fn (into-markup [:code])}
743782
{:name :nextjournal.markdown/strikethrough :transform-fn (into-markup [:s])}
744783
{:name :nextjournal.markdown/link :transform-fn (into-markup #(vector :a (:attrs %)))}
784+
{:name :nextjournal.markdown/internal-link
785+
:transform-fn (update-val
786+
(fn [{:keys [text]}]
787+
(let [{:keys [path fragment title]} (process-internal-link text)]
788+
(html [:a.internal-link {:href (doc-url path fragment)} title]))))}
745789

746790
;; inlines
747791
{:name :nextjournal.markdown/text :transform-fn (into-markup [:<>])}
@@ -1129,7 +1173,7 @@
11291173

11301174
#_(update-if {:n "42"} :n #(Integer/parseInt %))
11311175

1132-
(declare html doc-url)
1176+
(declare html)
11331177

11341178
(defn home? [{:keys [nav-path]}]
11351179
(contains? #{"src/nextjournal/home.clj" "'nextjournal.clerk.home"} nav-path))

0 commit comments

Comments
 (0)