112 lines
5.6 KiB
Fennel
112 lines
5.6 KiB
Fennel
(local fennel (require :fennel))
|
|
(fn _G.pp [x] (print (fennel.view x)))
|
|
|
|
(var footnote-counter 1)
|
|
|
|
(fn render-contents [contents]
|
|
(var rendered "<p>")
|
|
(each [_ line (ipairs contents)]
|
|
(_G.pp line)
|
|
(match (. line :type)
|
|
"raw-text" (set rendered (.. rendered line.text "\n"))
|
|
"Italics" (set rendered (.. rendered "<em>" line.text "</em>\n"))
|
|
"Bold" (set rendered (.. rendered "<b>" line.text "</b>\n"))
|
|
"Strikethrough" (set rendered (.. rendered "<del>" line.text "</del>\n"))
|
|
"Monospace" (set rendered (.. rendered "<code>" line.text "</code>\n"))
|
|
"Link" (set rendered (.. rendered "<a href=\"" line.destination "\" class=\"" line.class "\">" line.title "</a>\n"))
|
|
"Footnote-Link" (do
|
|
(set rendered (.. rendered "<sup>\n<a href=fn:" (tostring footnote-counter) " id=fnref:" (tostring footnote-counter) ">[" (tostring footnote-counter) "]</a>\n</sup>\n"))
|
|
(set footnote-counter (+ footnote-counter 1)))))
|
|
(.. rendered "</p>"))
|
|
|
|
(local render-grammar
|
|
{:Header (fn render-header [{: contents : size}]
|
|
(let [header-type (tostring size)
|
|
header (.. "h" header-type)
|
|
contents-render (render-contents contents)]
|
|
(.. "<" header ">\n" contents-render "</" header ">\n")))
|
|
:List (fn render-list [{: elements}]
|
|
(var list-str "<ul>\n")
|
|
(var depth 0)
|
|
(each [_ element (ipairs elements)]
|
|
(_G.pp element)
|
|
(let [contents-render (render-contents (. element :contents))
|
|
indent-level (. element :indent-level)]
|
|
(_G.pp (.. "indent-level " indent-level " depth: " depth))
|
|
(if (= indent-level depth) ; If we're at the right indent level
|
|
(set list-str (.. list-str "<li>" contents-render "</li>\n")) ; Just add the string as a list element
|
|
(do ; Otherwise
|
|
(while (not (= depth indent-level)) ; While our depth level is different from the indent level
|
|
(if (> indent-level depth) ; If we need to increase depth
|
|
(do
|
|
(set list-str (.. list-str "<ul>\n")) ; Add another layer in the render
|
|
(set depth (+ depth 1))) ; Increase our depth level
|
|
(do ; We need to decrease depth
|
|
(set list-str (.. list-str "</ul>\n")) ; Close a layer
|
|
(set depth (- depth 1))))) ; Reduce depth level
|
|
(set list-str (.. list-str "<li>" contents-render "</li>\n"))))))
|
|
(while (not (= depth 0))
|
|
(set list-str (.. list-str "</ul>\n"))
|
|
(set depth (- depth 1))
|
|
(_G.pp (.. "depth: " depth)))
|
|
(set list-str (.. list-str "</ul>\n")) ; Close the first one
|
|
list-str)
|
|
:Quote (fn render-quote [{: contents}]
|
|
(let [contents-render (render-contents contents)]
|
|
(.. "<blockquote>\n" contents-render "</blockquote>\n")))
|
|
:Paragraph (fn render-paragraph [{: contents}]
|
|
(render-contents contents)) ; Contents render handles the <p> tag?
|
|
:Image (fn render-image [{: link : contents}]
|
|
(.. "<img\n src=" link "\n alt=" (render-contents contents) " />")) ; TODO this fucks up the alt tag
|
|
; Tags are a type of metadata
|
|
:Tag (fn metadata-tag [{: tags} metadata]
|
|
(if (= metadata.tags nil)
|
|
(tset metadata "tags" [tags])
|
|
(table.insert metadata.tags tags))
|
|
metadata)
|
|
:Metadata (fn metadata [{: key : val} metadata]
|
|
(if (= metadata.key nil)
|
|
(tset metadata key [val])
|
|
(table.insert metadata.key val))
|
|
metadata)
|
|
; Not sure what to do about code either
|
|
; Need to look into pygments or whatever see how that works
|
|
; Or find some sort of minimal js solution?
|
|
; Not really sure
|
|
:Code (fn code [{: codehint : contents}]
|
|
(.. "<code>\n" contents "</code>\n"))
|
|
; Each footnote gets an incremental ID
|
|
; the contents parser will link to the appropriate footnote
|
|
; Don't forget to link to the ref (back link)
|
|
; See seirdy's footnotes for an example
|
|
; https://seirdy.one/meta/site-design/#fn:1
|
|
:Footnote (fn footnotes [{: elements}]
|
|
(var count 1)
|
|
(var rendered "<ol>\n")
|
|
(each [_ element (ipairs elements)]
|
|
(let [contents-render (render-contents element.contents)]
|
|
(set rendered (.. rendered "<li id=fn:" count ">\n"))
|
|
(set rendered (.. rendered contents-render "</li>\n"))
|
|
(set rendered (.. rendered "<a href=\"#fnref:" count "\">Back</a>\n"))
|
|
(set count (+ count 1))))
|
|
(.. rendered "</ol>\n"))})
|
|
|
|
(fn render [blocks grammar]
|
|
(var rendered "")
|
|
(var metadata {})
|
|
(each [_ section (ipairs blocks)]
|
|
(each [_ block (ipairs section)]
|
|
(let [rule-set (. grammar (. block :type))]
|
|
(if (. block :is-metadata)
|
|
(set metadata (rule-set block metadata)) ; Handle metadata, TODO this doesn't handle sections for metadata semantics
|
|
(set rendered (.. rendered (rule-set block))))))
|
|
;(_G.pp rendered))) ; Write to the rendered string
|
|
(set rendered (.. rendered "\n<break/>\n"))) ; TODO Section "rendering"
|
|
; Should each section be returned seperately?
|
|
; Then we can add metadata to it easily.
|
|
; Final section
|
|
(values rendered metadata))
|
|
|
|
{: render
|
|
: render-grammar}
|