90 lines
2.8 KiB
Clojure
Executable File
90 lines
2.8 KiB
Clojure
Executable File
(ns asciidoc.render
|
|
(:require
|
|
[clojure.pprint :refer [pprint]]
|
|
[asciidoc.types :as types]
|
|
[clojure.spec.alpha :as s]
|
|
[clojure.zip :as zip]))
|
|
|
|
(defn- block-zip [root-block]
|
|
(zip/zipper #(s/conform ::block %)
|
|
:content
|
|
(fn [block children] (assoc block :content children))
|
|
root-block))
|
|
|
|
(defn- escape-line [line]
|
|
;; TODO
|
|
line)
|
|
|
|
(declare render*)
|
|
|
|
(defn- render-attributes [attributes]
|
|
(let [sorted-attributes (->> attributes
|
|
seq
|
|
(sort-by first))]
|
|
(doseq [[k v] sorted-attributes]
|
|
(printf ":%s: %s\n" (name k) v))))
|
|
|
|
(defn- render-document-header [depth {:keys [arguments] :as block}]
|
|
(println "=" (:title arguments))
|
|
(when-let [author (:author arguments)]
|
|
(println author)
|
|
(when-let [version (:version arguments)]
|
|
(println version)))
|
|
(when-let [attributes (:a arguments)]
|
|
(render-attributes attributes))
|
|
(println)
|
|
(run! #(render* (inc depth) %) (:content block)))
|
|
|
|
(defn- render-p [block]
|
|
(apply println (:content block)))
|
|
|
|
(defn- render-description [depth {{:keys [described]} :arguments :as block}]
|
|
(printf "%s::\n" described)
|
|
(run! #(render* (inc depth) %) (:content block)))
|
|
|
|
(defn- render-section [depth {:keys [arguments] :as block}]
|
|
(print (apply str (repeat (inc depth) \=))
|
|
(:title arguments)
|
|
"\n\n")
|
|
(run! #(render* (inc depth) %) (:content block))
|
|
(println))
|
|
|
|
(defn- render* [depth block]
|
|
(case (:context block)
|
|
:document (do (assert (zero? depth)
|
|
"Document block should only occur as root node.")
|
|
(render-document-header depth block))
|
|
:section (render-section depth block)
|
|
:p (render-p block)
|
|
:description (render-description depth block)
|
|
:<> (run! #(render* (inc depth) %) (apply concat (:content block)))
|
|
(throw (ex-info "no case" {:for (:context block)
|
|
:block block}))))
|
|
|
|
(def my-manpage
|
|
[:document {:title "sydnix(1)"
|
|
:author "Madeleine Sydney Ślaga"
|
|
:a {:doctype "manpage"
|
|
:manmanual "SYDNIX"
|
|
:mansource "SYDNIX"}}
|
|
[:section {:title "Name"}
|
|
[:p "sydnix - Inspect and operate upon the system."]]
|
|
[:section {:title "Synopsis"}
|
|
[:p "*sydnix* [_COMMAND_]... [_OPTION_]... [_FILE_]..."]]
|
|
[:section {:title "Options"}
|
|
[:description {:described "*--flake=URI*"}
|
|
"UJri is a flake"]]])
|
|
|
|
(defn conform! [spec x]
|
|
(let [x' (s/conform spec x)]
|
|
(if (= x' :clojure.spec.alpha/invalid)
|
|
(throw (ex-info "invalid" (s/explain-data spec x)))
|
|
x')))
|
|
|
|
;; Currently unrelentingly recursive. We'll fix this if/when it bnecomes a
|
|
;; problem. Shame Clojure skimps out on general TCO. }:(
|
|
(defn render
|
|
"Render an AsciiDoc block to `*out*`."
|
|
[block]
|
|
(render* 0 (conform! :asciidoc.types/document block)))
|