From 04821d8be5d773153718948454c864495704f67b Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Thu, 21 Apr 2022 19:13:02 +0300 Subject: Send correctors to each render as well --- src/clarktown/engine.clj | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/clarktown/engine.clj (limited to 'src/clarktown/engine.clj') diff --git a/src/clarktown/engine.clj b/src/clarktown/engine.clj new file mode 100644 index 0000000..17e5867 --- /dev/null +++ b/src/clarktown/engine.clj @@ -0,0 +1,140 @@ +(ns clarktown.engine + (:require + [clojure.string :as string])) + + +(defn- stitch-code-blocks + "Since code blocks can span multiple blocks (a block is separated by + two line breaks from another block) , we need to stitch them together + into one block in order for a block parser to be able to do anything + with it." + [blocks] + (loop [stitched-blocks [] + code-block-started? false + blocks blocks] + (if (empty? blocks) + stitched-blocks + (let [block (first blocks)] + (if (and (string/starts-with? (string/trim block) "```") + (not (string/ends-with? (string/trim block) "```"))) + (recur (conj stitched-blocks block) + true + (drop 1 blocks)) + (if code-block-started? + (let [last-block (last stitched-blocks) + last-block-index (- (count stitched-blocks) 1)] + (if (string/ends-with? (string/trim block) "```") + (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block)) + false + (drop 1 blocks)) + (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block)) + true + (drop 1 blocks)))) + (recur (conj stitched-blocks block) + false + (drop 1 blocks)))))))) + + +(defn- correct-block-separations + "Corrects block separations and adds newlines above or + below a block where needed." + [correctors lines] + (->> lines + (map-indexed + (fn [index line] + (let [add-line-above? (some #(true? (% lines line index)) (:empty-line-above? correctors)) + add-line-below? (some #(true? (% lines line index)) (:empty-line-below? correctors))] + (cond + ; If code block starts but there is no empty newline + ; above, let's fix that + (and add-line-above? + (not add-line-below?)) + (str \newline line) + + ; If the code block ends, but there is no empty newline + ; below, let's fix that. + (and add-line-below? + (not add-line-above?)) + (str line \newline) + + ; If the code block needs a newline both above and below, + ; let's fix that. + (and add-line-above? + add-line-below?) + (str \newline line \newline) + + ; otherwise is what it is + :else line)))))) + + +(defn- correct-markdown + "Corrects invalid Markdown for the parser." + [markdown given-correctors] + (let [lines (string/split-lines markdown)] + (->> lines + (correct-block-separations (:block-separations given-correctors)) + (string/join \newline)))) + + +(defn- find-parser-by-block + "Find a parser from `parsers` that matches the given `block`." + [parsers block] + (->> parsers + (filter + (fn [{:keys [matcher]}] + (when matcher + (matcher block)))) + first)) + + +(defn- parse-block-with-known-parser + "Parses a given `block` with a known `parser`." + [parser given-parsers given-correctors block] + (loop [block block + renderers (:renderers parser)] + (if (empty? renderers) + block + (let [renderer (first renderers)] + (recur (renderer block given-parsers given-correctors) + (drop 1 renderers)))))) + + +(defn- parse-block-with-unknown-parsers + "Parses the given `block` with all the parsers that do not have + a matcher function, useful for any fallback parsing one might want + to do." + [given-parsers given-correctors block] + (loop [block block + parsers (filter #(= nil (:matcher %)) given-parsers)] + (if (empty? parsers) + block + (recur (loop [block block + renderers (:renderers (first parsers))] + (if (empty? renderers) + block + (let [renderer (first renderers)] + (recur (renderer block parsers given-correctors) + (drop 1 renderers))))) + (drop 1 parsers))))) + + +(defn- parse-blocks + "Parses each individual Markdown block, given as `blocks`, with + the list of `parsers`." + [blocks given-parsers given-correctors] + (for [block blocks] + (if-let [parser (find-parser-by-block given-parsers block)] + (->> (string/trim block) + (parse-block-with-known-parser parser given-parsers given-correctors)) + (->> (string/trim block) + (parse-block-with-unknown-parsers given-parsers given-correctors))))) + + +(defn render + "Parses given `markdown` with `parsers`." + [markdown given-parsers given-correctors] + (let [blocks (-> (correct-markdown markdown given-correctors) + (string/split #"\n\n") + stitch-code-blocks) + parsed-blocks (parse-blocks blocks given-parsers given-correctors)] + (string/join "\n\n" parsed-blocks))) \ No newline at end of file -- cgit v1.2.3 From 77b065ba5cd57d4a02b0cae68d74412d1234554c Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Fri, 22 Apr 2022 14:34:18 +0300 Subject: Make code more narrow --- src/clarktown/core.clj | 2 +- src/clarktown/engine.clj | 56 +++++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 28 deletions(-) (limited to 'src/clarktown/engine.clj') diff --git a/src/clarktown/core.clj b/src/clarktown/core.clj index a624275..2a3e3a1 100644 --- a/src/clarktown/core.clj +++ b/src/clarktown/core.clj @@ -27,4 +27,4 @@ ([markdown given-parsers] (render markdown given-parsers correctors/default-correctors)) ([markdown given-parsers given-correctors] - (engine/render markdown given-parsers given-correctors))) \ No newline at end of file + (engine/render markdown given-parsers given-correctors))) diff --git a/src/clarktown/engine.clj b/src/clarktown/engine.clj index 17e5867..2dc9089 100644 --- a/src/clarktown/engine.clj +++ b/src/clarktown/engine.clj @@ -39,32 +39,34 @@ "Corrects block separations and adds newlines above or below a block where needed." [correctors lines] - (->> lines - (map-indexed - (fn [index line] - (let [add-line-above? (some #(true? (% lines line index)) (:empty-line-above? correctors)) - add-line-below? (some #(true? (% lines line index)) (:empty-line-below? correctors))] - (cond - ; If code block starts but there is no empty newline - ; above, let's fix that - (and add-line-above? - (not add-line-below?)) - (str \newline line) - - ; If the code block ends, but there is no empty newline - ; below, let's fix that. - (and add-line-below? - (not add-line-above?)) - (str line \newline) - - ; If the code block needs a newline both above and below, - ; let's fix that. - (and add-line-above? - add-line-below?) - (str \newline line \newline) - - ; otherwise is what it is - :else line)))))) + (let [above-correctors (:empty-line-above? correctors) + below-correctors (:empty-line-below? correctors)] + (map-indexed + (fn [index line] + (let [add-line-above? (some #(true? (% lines line index)) above-correctors) + add-line-below? (some #(true? (% lines line index)) below-correctors)] + (cond + ; If code block starts but there is no empty newline + ; above, let's fix that + (and add-line-above? + (not add-line-below?)) + (str \newline line) + + ; If the code block ends, but there is no empty newline + ; below, let's fix that. + (and add-line-below? + (not add-line-above?)) + (str line \newline) + + ; If the code block needs a newline both above and below, + ; let's fix that. + (and add-line-above? + add-line-below?) + (str \newline line \newline) + + ; otherwise is what it is + :else line))) + lines))) (defn- correct-markdown @@ -137,4 +139,4 @@ (string/split #"\n\n") stitch-code-blocks) parsed-blocks (parse-blocks blocks given-parsers given-correctors)] - (string/join "\n\n" parsed-blocks))) \ No newline at end of file + (string/join "\n\n" parsed-blocks))) -- cgit v1.2.3