refactor: Rename sydnix → sydnix-cli

This commit is contained in:
Madeleine Sydney
2025-01-14 20:24:07 -07:00
parent 29fd94f9e2
commit 0e9bad81ee
20 changed files with 55 additions and 57 deletions

View File

@@ -0,0 +1,89 @@
(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)))

View File

@@ -0,0 +1,57 @@
(ns asciidoc.types
(:require
[clojure.spec.alpha :as s]
[spec-dict.main :refer [->opt dict]]))
(defn- make-block-arguments [req opt]
(let [args (dict req
(->opt opt)
^:opt {:a map?})]
(if (empty? req)
(s/? (s/and map? args))
(s/& (s/? map?) args))))
(defn- make-block
[& {:keys [name required-args optional-args content-spec]
:or {required-args {}
optional-args {}
content-spec (s/* ::block)}}]
(s/and seqable?
(s/cat :context (s/and keyword? #{name})
:arguments (make-block-arguments required-args optional-args)
:content content-spec)
;; Set arguments to {} if none were provided.
(s/conformer #(if (contains? % :arguments)
%
(assoc % :arguments {})))))
(s/def ::document
(make-block :name :document
:required-args {:title string?}
:optional-args {:author string?
:version string?}))
(s/def ::p
(make-block :name :p
:content-spec (s/* string?)))
(s/def ::description
(make-block :name :description
:required-opts {:described string?}))
(s/def ::section
(make-block :name :section
:required-args {:title string?}))
(s/def ::<>
(make-block :name :<>
:content (s/coll-of ::block)))
(s/def ::block
(s/and (s/or :document ::document
:section ::section
:description ::description
:<> ::<>
:p ::p)
;; `s/or` provides tagging that `make-block` already does.
(s/conformer #(nth % 1))))