3 [clojure.string :as str]
4 [clojure.walk :as walk]))
7 "check if `s` starts with `substr`. Return `false` if `s` is not a
11 (str/starts-with? s substr)))
13 (defn- match-code-blocks []
15 (let [acc (volatile! [])
16 state (volatile! :normal)]
19 ([result] (rf result))
21 (let [in-verbatim? (= :verbatim @state)
22 marker? (starts-with? line "```")]
24 (and (not in-verbatim?) marker?) ;go to verbatim
25 (do (vreset! state :verbatim)
28 ;; return what we've got and go to :normal
29 (and in-verbatim? marker?)
30 (let [res [:verbatim (str/join "\n" @acc)]]
31 (vreset! state :normal)
36 (do (vswap! acc conj line)
40 (rf result line))))))))
42 (defn- match-headings []
46 ([result] (rf result))
50 ;; the space character after the # is madatory
51 (starts-with? line "# ") [:h1 (subs line 2)]
52 (starts-with? line "## ") [:h2 (subs line 3)]
53 (starts-with? line "### ") [:h3 (subs line 4)]
56 (defn- generic-matcher
57 "Return a generic matcher transducer. Will wrap line that starts with
58 `start` within `[type line]`."
63 ([result] (rf result))
66 (if (starts-with? line start)
67 [type (subs line (count start))]
70 (defn- match-lists [] (generic-matcher "* " :li))
71 (defn- match-blockquotes [] (generic-matcher "> " :blockquote))
77 ([result] (rf result))
79 (let [spaces? #{\space \tab}
80 nonblank? (complement spaces?)]
82 (if-not (starts-with? line "=>")
85 (drop 2) ; drop the marker
86 (drop-while spaces?) ; drop also the optional spaces
87 (split-with nonblank?) ; separate URL from (optional) label
90 (apply str (drop-while spaces? %2))))))))))))
92 (defn match-paragraphs [] (generic-matcher "" :paragraph))
95 (comp (match-code-blocks)
103 "Given a string representing a gemtext document, parse it into an
104 hiccup-like data structure."
106 (transduce parser conj [] (str/split-lines str)))
108 (defn unparse [thing]
109 (let [sw (StringBuilder.)]
117 (if-not (keyword? (first t))
122 :verbatim (str "```\n" a "\n```")
127 :blockquote (str "> " a)
128 :link (str "=> " a " " b)
136 "Escape HTML entities in `str`"
144 "Convert a (gemtext) link an HTML element. If the link is pointing to
145 an image (guessed by href) transform it into an image, otherwise
146 return a (HTML) link."
148 (let [text (html-escape text)]
149 (if (re-matches #".*\.(jpg|jpeg|png|gif)" href)
153 [:p.link [:a {:href href}
156 (defn to-hiccup [doc]
165 (if-not (keyword? (first t))
171 :verbatim [:pre [:code a]]
175 :li [:ul [:li a]] ;; TODO!
176 :blockquote [:blockquote a]
185 (unparse (parse "```\nhello there\n```\n"))
187 (unparse (list [:h2 "hello there"] (list (list nil (list nil)))))
188 (unparse (list [:h2 "hello there"]))