A very long way towards extensible formatters

This commit is contained in:
Simon Brooke 2017-08-07 23:21:45 +01:00
parent 91367e40aa
commit 19a715c4fb

View file

@ -6,6 +6,7 @@
[noir.io :as io] [noir.io :as io]
[noir.session :as session] [noir.session :as session]
[markdown.core :as md] [markdown.core :as md]
[taoensso.timbre :as timbre]
[smeagol.authenticate :as auth] [smeagol.authenticate :as auth]
[clj-yaml.core :as yaml] [clj-yaml.core :as yaml]
[clojure.data.json :as json])) [clojure.data.json :as json]))
@ -35,7 +36,7 @@
;;;; ;;;;
;;;; Right, doing the data visualisation thing is tricky. Doing it in the ;;;; Right, doing the data visualisation thing is tricky. Doing it in the
;;;; pipeline doesn't work, because the md-to-html-string filter messes up ;;;; pipeline doesn't work, because the md-to-html-string filter messes up
;;;; both YAML and JSON notation. So we need to extract the visualisation YAML ;;;; both YAML and JSON notation. So we need to extract the visualisation
;;;; fragments from the Markdown text and replace them with tokens we will ;;;; fragments from the Markdown text and replace them with tokens we will
;;;; recognise afterwards, perform md-to-html-string, and then replace our ;;;; recognise afterwards, perform md-to-html-string, and then replace our
;;;; tokens with the transformed visualisation specification. ;;;; tokens with the transformed visualisation specification.
@ -88,6 +89,63 @@
"\n</div>")) "\n</div>"))
;; TODO: This isn't (yet) exactly what I want. The formatters ought to be configurable
;; without editing the Smeagol code directly. But it's a long way in the right direction.
(def ^:dynamic *formatters*
{"vega" process-vega
"vis" process-vega
"mermaid" process-mermaid})
(defn get-first-token
"Return the first space-separated token of this `string`."
[^String string]
(if string (first (cs/split string #"[^a-zA-Z0-9]+"))))
(defn- process-markdown-fragment
"Within the context of `process-text`, process a fragment believed to be markdown.
As with `process-text`, this function returns a map with two top-level keys:
`:inclusions`, a map of constructed keywords to inclusion specifications,
and `:text`, an HTML text string with the keywords present where the
corresponding inclusion should be inserted."
[index result fragments processed]
(process-text
(+ index 1)
result
(rest fragments)
(cons (first fragments) processed)))
(defn- apply-formatter
"Within the context of `process-text`, process a fragment for which an explicit
§formatter has been identified.
As with `process-text`, this function returns a map with two top-level keys:
`:inclusions`, a map of constructed keywords to inclusion specifications,
and `:text`, an HTML text string with the keywords present where the
corresponding inclusion should be inserted."
[index result fragments processed fragment token formatter]
(let
[kw (keyword (str "inclusion-" index))]
(process-text
(+ index 1)
(assoc
result
:inclusions
(assoc
(:inclusions result)
kw
(apply
formatter
(list
(subs fragment (count token))
index))))
(rest fragments)
(cons kw processed))))
(defn process-text (defn process-text
"Process this `text`, assumed to be markdown potentially containing both local links "Process this `text`, assumed to be markdown potentially containing both local links
and YAML visualisation specifications, and return a map comprising JSON visualisation and YAML visualisation specifications, and return a map comprising JSON visualisation
@ -99,46 +157,20 @@
([text] ([text]
(process-text 0 {:inclusions {}} (cs/split text #"```") '())) (process-text 0 {:inclusions {}} (cs/split text #"```") '()))
([index result fragments processed] ([index result fragments processed]
(cond (let [fragment (first fragments)
(empty? fragments) first-token (get-first-token fragment)
(assoc result :text formatter (*formatters* first-token)]
(local-links (cond
(empty? fragments)
(assoc result :text
(local-links
(md/md-to-html-string (md/md-to-html-string
(cs/join "\n\n" (reverse processed)) (cs/join "\n\n" (reverse processed))
:heading-anchors true))) :heading-anchors true)))
;;; TODO: refactor; generalise extension architecture formatter
(clojure.string/starts-with? (first fragments) "vis") (apply-formatter index result fragments processed fragment first-token formatter)
(let [kw (keyword (str "inclusion-" index))] true
(process-text (process-markdown-fragment index result fragments processed)))))
(+ index 1)
(assoc
result
:inclusions
(assoc
(:inclusions result)
kw
(process-vega
(subs (first fragments) 3)
index)))
(rest fragments)
(cons kw processed)))
(clojure.string/starts-with? (first fragments) "mermaid")
(let [kw (keyword (str "inclusion-" index))]
(process-text
(+ index 1)
(assoc
result
:inclusions
(assoc
(:inclusions result)
kw
(process-mermaid
(subs (first fragments) 7)
index)))
(rest fragments)
(cons kw processed)))
true
(process-text (+ index 1) result (rest fragments) (cons (first fragments) processed)))))
(defn reintegrate-inclusions (defn reintegrate-inclusions