117 lines
4.2 KiB
Plaintext
117 lines
4.2 KiB
Plaintext
#!/usr/bin/env janet
|
|
|
|
(defn read-from-file [file-path]
|
|
"Read a file from string filepath"
|
|
(let [f (file/open file-path :r)
|
|
content (file/read f :all)]
|
|
(file/close f)
|
|
content))
|
|
|
|
(defn htmlspecialchars
|
|
"Convert html special chars from a string"
|
|
[value]
|
|
(string/replace-all "\"" """
|
|
(string/replace-all "'" "'"
|
|
(string/replace-all "<" "<"
|
|
(string/replace-all ">" ">"
|
|
(string/replace-all "&" "&" value))))))
|
|
|
|
(def md-to-ast
|
|
"A custom markdown flavored grammar"
|
|
~{
|
|
# Symbole
|
|
:end-of-line (* (? "\r") "\n")
|
|
:space "\u0020"
|
|
:tab (+ "\u0009" (4 :space))
|
|
|
|
:code-block-tag "```"
|
|
:list-item-starter (+ "*" "-")
|
|
:italic-tag "*"
|
|
:bold-tag "**"
|
|
:stroke-tag "~~"
|
|
:code-line-tag "`"
|
|
|
|
:rich-text-tag (+ :italic-tag :bold-tag :stroke-tag :code-line-tag)
|
|
:basic-text (some (if-not (+ :end-of-line :code-line-tag :stroke-tag :bold-tag :italic-tag) 1))
|
|
|
|
:c-basic-text (cmt (<- :basic-text),|[:text $0])
|
|
|
|
:bold (cmt (* :bold-tag :rich-text :bold-tag),|[:bold $0 $&])
|
|
:italic (cmt (* :italic-tag :rich-text :italic-tag),|[:italic $0 $&])
|
|
:stroke (cmt (* :stroke-tag :rich-text :stroke-tag),|[:stroke $0 $&])
|
|
:code-line (cmt (* :code-line-tag (<- :rich-text) :code-line-tag),|[:code-line $0 $&])
|
|
|
|
:rich-text (cmt (some (+ :code-line :bold :italic :stroke :c-basic-text)),|(map (fn [arg] [(get arg 0) (get arg 1)]) $&))
|
|
:line (cmt (* :rich-text :end-of-line),|[:line $0])
|
|
|
|
# Block
|
|
:heading (cmt (* (<- (between 1 6 "#")) :space (<- :basic-text)),|[:heading (length $0) $1])
|
|
:hr (cmt (* (at-least 3 (+ "-" "_" "*")) :end-of-line),|[:hr])
|
|
:code-block (cmt (* :code-block-tag (? (<- :basic-text)) :end-of-line (<- (some (if-not :code-block-tag 1))) :code-block-tag),|[:code-block $0 $1])
|
|
:quote (cmt (* ">" :space (? :rich-text)),|[:quote $0])
|
|
:list-item (cmt (* (<- (? (between 0 2 :tab))) :list-item-starter :space :rich-text),|[:list-item (/ (length $0) 4) $1])
|
|
:list (cmt (some (* :list-item (? :end-of-line))),|[:list $&])
|
|
|
|
:block (+ :heading
|
|
:hr
|
|
:code-block
|
|
:quote
|
|
:list
|
|
:line
|
|
:end-of-line)
|
|
|
|
:main (some (* :block (? :end-of-line)))})
|
|
|
|
(defn ast-to-html
|
|
"Convert an AST to html"
|
|
[ast]
|
|
(defn to-codeblock [lang value] (string "<pre><code>" (htmlspecialchars value) "</code></pre>"))
|
|
(defn to-codeline [value] (string "<code>" (ast-to-html value) "</code>"))
|
|
(defn to-heading [level value] (string "<h" level ">" (htmlspecialchars value) "</h" level ">"))
|
|
(defn to-quote [value] (string "<blockquote>" (ast-to-html value) "</blockquote>"))
|
|
(defn to-line [value] (string "<p>" (ast-to-html value) "</p>"))
|
|
(defn to-italic [value] (string "<em>" (ast-to-html value) "</em>"))
|
|
(defn to-bold [value] (string "<strong>" (ast-to-html value) "</strong>"))
|
|
(defn to-stroke [value] (string "<stroke>" (ast-to-html value) "</stroke>"))
|
|
|
|
(string/join
|
|
(map
|
|
|(match $0
|
|
[:code-block lang value]
|
|
(to-codeblock lang value)
|
|
[:heading level value]
|
|
(to-heading level value)
|
|
[:quote value]
|
|
(to-quote value)
|
|
[:hr]
|
|
"<hr/>"
|
|
[:line value]
|
|
(to-line value)
|
|
[:text value]
|
|
(htmlspecialchars value)
|
|
[:italic value]
|
|
(to-italic value)
|
|
[:stroke value]
|
|
(to-stroke value)
|
|
[:bold value]
|
|
(to-bold value)
|
|
[:code-line value]
|
|
(to-codeline value)
|
|
_
|
|
(error (string "Invalid symbol: " (get $0 0))))
|
|
ast)
|
|
""))
|
|
|
|
(defn pp-ast
|
|
"Pretty prints the Mardown AST (as provided by (peg/match md-to-ast))"
|
|
[ast]
|
|
(if ast
|
|
(do
|
|
(print "[")
|
|
(map |(printf "\t%q" $0) ast)
|
|
(print "]"))))
|
|
|
|
(defn main [bin & args]
|
|
# (pp-ast (peg/match md-to-ast (read-from-file "raw/~blog/blog.md")))
|
|
(print (ast-to-html (peg/match md-to-ast (read-from-file "raw/~blog/blog.md")))))
|