summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAsko Nomm <asko@bien.ee>2022-04-06 13:43:59 +0200
committerAsko Nomm <asko@bien.ee>2022-04-06 13:43:59 +0200
commit2072d2730e0a7991bdf6474275f9fe9cd8fac182 (patch)
treef2f2e4190d38edafbac730487839adf356fa7149 /src
parent3770175783d53f9008d81dca8b19741b218d925f (diff)
Fixes list blocks, which can now be of any depth and should work just fine.
Diffstat (limited to 'src')
-rw-r--r--src/clarktown/core.clj5
-rw-r--r--src/clarktown/parsers.clj14
-rw-r--r--src/clarktown/parsers/list_block.clj104
-rw-r--r--src/clarktown/parsers/ordered_list_block.clj25
4 files changed, 108 insertions, 40 deletions
diff --git a/src/clarktown/core.clj b/src/clarktown/core.clj
index 3663c11..f192cc4 100644
--- a/src/clarktown/core.clj
+++ b/src/clarktown/core.clj
@@ -24,7 +24,4 @@
([markdown]
(render markdown parsers/parsers))
([markdown given-parsers]
- (parser/parse markdown given-parsers)))
-
-
-(render (slurp "/Users/asko/work/clarktown/test.md")) \ No newline at end of file
+ (parser/parse markdown given-parsers))) \ No newline at end of file
diff --git a/src/clarktown/parsers.clj b/src/clarktown/parsers.clj
index 01a6351..b5b6132 100644
--- a/src/clarktown/parsers.clj
+++ b/src/clarktown/parsers.clj
@@ -10,8 +10,7 @@
[clarktown.parsers.quote-block :as quote-block]
[clarktown.parsers.heading-block :as heading-block]
[clarktown.parsers.code-block :as code-block]
- [clarktown.parsers.unordered-list-block :as unordered-list-block]
- [clarktown.parsers.ordered-list-block :as ordered-list-block]
+ [clarktown.parsers.list-block :as list-block]
[clarktown.parsers.paragraph-block :as paragraph-block]))
@@ -31,20 +30,13 @@
:renderers [quote-block/render]}
{:matcher code-block/is?
:renderers [code-block/render]}
- {:matcher unordered-list-block/is?
+ {:matcher list-block/is?
:renderers [bold/render
italic/render
inline-code/render
strikethrough/render
link-and-image/render
- unordered-list-block/render]}
- {:matcher ordered-list-block/is?
- :renderers [bold/render
- italic/render
- inline-code/render
- strikethrough/render
- link-and-image/render
- ordered-list-block/render]}
+ list-block/render]}
{:renderers [bold/render
italic/render
inline-code/render
diff --git a/src/clarktown/parsers/list_block.clj b/src/clarktown/parsers/list_block.clj
new file mode 100644
index 0000000..9485f67
--- /dev/null
+++ b/src/clarktown/parsers/list_block.clj
@@ -0,0 +1,104 @@
+(ns clarktown.parsers.list-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn is?
+ "Determines whether we're dealing with a list block or not."
+ [block]
+ (->> (string/trim block)
+ (re-matches #"(?s)^(\d\.|\*).*$")))
+
+
+(defn string->indent-n
+ [str]
+ (count (take-while #{\space} str)))
+
+
+(defn compose-items-with-indent-guides
+ [block]
+ (->> (string/split-lines block)
+ (mapv
+ (fn [line]
+ {:id (random-uuid)
+ :indent-n (string->indent-n line)
+ :value (-> line
+ string/trim)}))))
+
+
+(defn find-parent-id
+ [items index]
+ (let [indent-n-at-index (:indent-n (nth items index))]
+ (-> (->> (split-at index items)
+ first
+ reverse
+ (remove #(or (> (:indent-n %) indent-n-at-index)
+ (= (:indent-n %) indent-n-at-index)))
+ first
+ :id))))
+
+
+(defn compose-items-with-parents
+ [block]
+ (let [items (compose-items-with-indent-guides block)]
+ (->> items
+ (map-indexed
+ (fn [index line]
+ (merge line {:parent (find-parent-id items index)}))))))
+
+
+(defn add-to-parent
+ [items item]
+ (->> items
+ (mapv
+ (fn [i]
+ (if (= (:id i) (:parent item))
+ (if (:items i)
+ (assoc i :items (concat (:items i) [item]))
+ (assoc i :items [item]))
+ (if (:items i)
+ (assoc i :items (add-to-parent (:items i) item))
+ i))))))
+
+
+(defn compose-item-tree
+ [block]
+ (loop [result []
+ items (compose-items-with-parents block)]
+ (if (empty? items)
+ result
+ (let [item (first items)
+ parent (:parent item)
+ new-item {:id (:id item)
+ :value (:value item)}]
+ (recur (if parent
+ (add-to-parent result item)
+ (concat result [new-item]))
+ (drop 1 items))))))
+
+
+(defn render-items
+ [items]
+ (loop [result ""
+ inner-items items]
+ (if (empty? inner-items)
+ (if (string/starts-with? (:value (first items)) "*")
+ (str "<ul>" result "</ul>")
+ (str "<ol>" result "</ol>"))
+ (let [inner-item (first inner-items)
+ value (if (string/starts-with? (:value inner-item) "*")
+ (-> (string/replace-first (:value inner-item) "*" "")
+ string/trim)
+ (-> (string/replace-first (:value inner-item) #"\d\." "")
+ string/trim))]
+ (recur (if (:items inner-item)
+ (str result "<li>" value (render-items (:items inner-item)) "</li>")
+ (str result "<li>" value "</li>"))
+ (drop 1 inner-items))))))
+
+
+(defn render
+ "Renders the ordered list block"
+ [block _]
+ (-> (compose-item-tree block)
+ (render-items))) \ No newline at end of file
diff --git a/src/clarktown/parsers/ordered_list_block.clj b/src/clarktown/parsers/ordered_list_block.clj
deleted file mode 100644
index 4dfaf38..0000000
--- a/src/clarktown/parsers/ordered_list_block.clj
+++ /dev/null
@@ -1,25 +0,0 @@
-(ns clarktown.parsers.ordered-list-block
- (:require
- [clojure.string :as string]
- [clarktown.parser :as parser]))
-
-
-(defn is?
- "Determines whether we're dealing with a list block or not."
- [block]
- (re-matches #"(?s)^\d\..*$" (string/trim block)))
-
-
-(defn render
- "Renders the ordered list block"
- [block parsers]
- (loop [result ""
- items (string/split-lines block)]
- (if (empty? items)
- (str "<ol>" result "</ol>")
- (let [value (-> (first items)
- (string/replace-first #"\d\." "")
- string/trim
- (parser/parse parsers))]
- (recur (str result "<li>" value "</li>")
- (drop 1 items))))))