From 2072d2730e0a7991bdf6474275f9fe9cd8fac182 Mon Sep 17 00:00:00 2001 From: Asko Nomm Date: Wed, 6 Apr 2022 13:43:59 +0200 Subject: Fixes list blocks, which can now be of any depth and should work just fine. --- src/clarktown/core.clj | 5 +- src/clarktown/parsers.clj | 14 +--- src/clarktown/parsers/list_block.clj | 104 +++++++++++++++++++++++++++ src/clarktown/parsers/ordered_list_block.clj | 25 ------- 4 files changed, 108 insertions(+), 40 deletions(-) create mode 100644 src/clarktown/parsers/list_block.clj delete mode 100644 src/clarktown/parsers/ordered_list_block.clj (limited to 'src/clarktown') 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 "") + (str "
    " result "
")) + (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 "
  • " value (render-items (:items inner-item)) "
  • ") + (str result "
  • " value "
  • ")) + (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 "
      " result "
    ") - (let [value (-> (first items) - (string/replace-first #"\d\." "") - string/trim - (parser/parse parsers))] - (recur (str result "
  • " value "
  • ") - (drop 1 items)))))) -- cgit v1.2.3