From 7c3eba77fd3de0e108efba94018233a57e66989e Mon Sep 17 00:00:00 2001 From: Asko Nõmm Date: Wed, 11 May 2022 20:42:30 +0300 Subject: Implement indented code blocks. --- src/clarktown/correctors.clj | 3 ++ src/clarktown/correctors/atx_heading_block.clj | 2 +- src/clarktown/correctors/indented_code_block.clj | 57 ++++++++++++++++++++++++ src/clarktown/engine.clj | 8 ++-- src/clarktown/matchers/indented_code_block.clj | 10 +++++ src/clarktown/parsers.clj | 10 +++++ src/clarktown/renderers/indented_code_block.clj | 17 +++++++ 7 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 src/clarktown/correctors/indented_code_block.clj create mode 100644 src/clarktown/matchers/indented_code_block.clj create mode 100644 src/clarktown/renderers/indented_code_block.clj (limited to 'src') diff --git a/src/clarktown/correctors.clj b/src/clarktown/correctors.clj index 6b7cc1c..cd5e7e8 100644 --- a/src/clarktown/correctors.clj +++ b/src/clarktown/correctors.clj @@ -1,6 +1,7 @@ (ns clarktown.correctors (:require [clarktown.correctors.fenced-code-block :as fenced-code-block] + [clarktown.correctors.indented-code-block :as indented-code-block] [clarktown.correctors.atx-heading-block :as atx-heading-block] [clarktown.correctors.list-block :as list-block])) @@ -10,10 +11,12 @@ default-block-separation-correctors {:newline-above [fenced-code-block/newline-above? + indented-code-block/newline-above? atx-heading-block/newline-above? list-block/newline-above?] :newline-below [fenced-code-block/newline-below? + indented-code-block/newline-below? atx-heading-block/newline-below? list-block/newline-below?]}) diff --git a/src/clarktown/correctors/atx_heading_block.clj b/src/clarktown/correctors/atx_heading_block.clj index 6668700..5a5f713 100644 --- a/src/clarktown/correctors/atx_heading_block.clj +++ b/src/clarktown/correctors/atx_heading_block.clj @@ -20,7 +20,7 @@ there's no empty newline above, we need to create one, and so this function must then return `true`." [lines line index] - (and (is-atx-heading? (string/trim line)) + (and (is-atx-heading? line) (> index 0) (not (= (-> (nth lines (- index 1)) string/trim) "")) diff --git a/src/clarktown/correctors/indented_code_block.clj b/src/clarktown/correctors/indented_code_block.clj new file mode 100644 index 0000000..47deeb7 --- /dev/null +++ b/src/clarktown/correctors/indented_code_block.clj @@ -0,0 +1,57 @@ +(ns clarktown.correctors.indented-code-block + (:require + [clojure.string :as string] + [clarktown.matchers.list-block :as list-block-matcher])) + + +(defn- in-code-block? + "Determines whether the current `line` is within a code block." + [lines index] + (->> (take index lines) + (filter #(string/starts-with? (string/trim %) "```")) + count + odd?)) + + +(defn newline-above? + "Determines whether there's a need for an empty new line + above the `line` at the current `index`. In the case of a + code block, which starts with three backticks (```), if there's + no empty newline above, we need to create one, and so this + function must then return `true`." + [lines line index] + (let [space-count (count (take-while #{\space} line)) + not-first? (> index 0) + prev-line (when not-first? + (nth lines (- index 1))) + space-count-prev-line (count (take-while #{\space} prev-line))] + (and (>= space-count 4) + not-first? + (not (in-code-block? lines index)) + (not (list-block-matcher/match? line)) + (not (list-block-matcher/match? prev-line)) + (not (>= space-count-prev-line 4)) + (not (= (-> prev-line + string/trim) + ""))))) + +(defn newline-below? + "Determines whether there's a need for an empty new line + below the `line` at the current `index`. In the case of a + code block, which ends with three backticks (```), if there's + no empty newline above, we need to create one, and so this + function must then return `true`." + [lines line index] + (let [space-count (count (take-while #{\space} line)) + not-last? (< index (- (count lines) 1)) + next-line (when not-last? + (nth lines (+ index 1))) + space-count-next-line (count (take-while #{\space} next-line))] + (and (>= space-count 4) + not-last? + (not (in-code-block? lines index)) + (not (list-block-matcher/match? line)) + (not (list-block-matcher/match? next-line)) + (not (>= space-count-next-line 4)) + (not (= (-> next-line + string/trim) ""))))) diff --git a/src/clarktown/engine.clj b/src/clarktown/engine.clj index 5eb22d5..dc07e9f 100644 --- a/src/clarktown/engine.clj +++ b/src/clarktown/engine.clj @@ -70,7 +70,7 @@ (defn- remove-excess-newlines - "Replaces all occurences of 3 or more concecutive newlines into + "Replaces all occurrences of 3 or more consecutive newlines into two newlines." [markdown] (string/replace markdown #"\n{3,}" "\n\n")) @@ -133,10 +133,8 @@ [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))))) + (parse-block-with-known-parser parser given-parsers given-correctors block) + (parse-block-with-unknown-parsers given-parsers given-correctors block)))) (defn render diff --git a/src/clarktown/matchers/indented_code_block.clj b/src/clarktown/matchers/indented_code_block.clj new file mode 100644 index 0000000..b7cf563 --- /dev/null +++ b/src/clarktown/matchers/indented_code_block.clj @@ -0,0 +1,10 @@ +(ns clarktown.matchers.indented-code-block + (:require + [clojure.string :as string])) + + +(defn match? + "Determines whether the given block is a indented code block." + [block] + (->> (string/split-lines block) + (every? #(>= (count (take-while #{\space} %)) 4)))) \ No newline at end of file diff --git a/src/clarktown/parsers.clj b/src/clarktown/parsers.clj index 0d3b019..8ca27b3 100644 --- a/src/clarktown/parsers.clj +++ b/src/clarktown/parsers.clj @@ -10,6 +10,8 @@ [clarktown.renderers.quote-block] [clarktown.matchers.fenced-code-block] [clarktown.renderers.fenced-code-block] + [clarktown.matchers.indented-code-block] + [clarktown.renderers.indented-code-block] [clarktown.matchers.list-block] [clarktown.renderers.list-block] [clarktown.renderers.paragraph-block] @@ -60,6 +62,13 @@ :renderers [clarktown.renderers.fenced-code-block/render]}) +(def + ^{:doc "Detects, parses and renders a indented code block."} + indented-code-block-parser + {:matcher clarktown.matchers.indented-code-block/match? + :renderers [clarktown.renderers.indented-code-block/render]}) + + (def ^{:doc "Detects, parses and renders a list block."} list-block-parser @@ -91,5 +100,6 @@ heading-block-parser quote-block-parser fenced-code-block-parser + indented-code-block-parser list-block-parser paragraph-block-parser]) diff --git a/src/clarktown/renderers/indented_code_block.clj b/src/clarktown/renderers/indented_code_block.clj new file mode 100644 index 0000000..b3828ec --- /dev/null +++ b/src/clarktown/renderers/indented_code_block.clj @@ -0,0 +1,17 @@ +(ns clarktown.renderers.indented-code-block + (:require + [clojure.string :as string])) + + +(defn render + "Renders the indented code block." + [block _ _] + (str + "
"
+    (-> (->> (string/split-lines block)
+             (map #(subs % 4))
+             (string/join \newline))
+        (string/replace #"&" "&")
+        (string/replace #"<" "<")
+        (string/replace #">" ">"))
+    "
")) \ No newline at end of file -- cgit v1.2.3