From 4761303e6d6d189b7bfb4cd62fb31b124a69ebe4 Mon Sep 17 00:00:00 2001 From: Madeleine Sydney Date: Sat, 11 Jan 2025 01:56:33 -0700 Subject: [PATCH] feat: Gen help for options --- scripts/sydnix/src/asciidoc/render.clj | 15 +++++++++++++-- scripts/sydnix/src/asciidoc/types.clj | 12 +++++++++++- scripts/sydnix/src/sydnix/commands/help.clj | 16 ++++++++++++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/scripts/sydnix/src/asciidoc/render.clj b/scripts/sydnix/src/asciidoc/render.clj index ff9a8ec..a2a3f56 100644 --- a/scripts/sydnix/src/asciidoc/render.clj +++ b/scripts/sydnix/src/asciidoc/render.clj @@ -38,11 +38,15 @@ (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-p (:content block)) + (run! #(render* (inc depth) %) (:content block)) (println)) (defn- render* [depth block] @@ -52,6 +56,8 @@ (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})))) @@ -64,7 +70,10 @@ [:section {:title "Name"} [:p "sydnix - Inspect and operate upon the system."]] [:section {:title "Synopsis"} - [:p "*sydnix* [_COMMAND_]... [_OPTION_]... [_FILE_]..."]]]) + [: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)] @@ -72,6 +81,8 @@ (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] diff --git a/scripts/sydnix/src/asciidoc/types.clj b/scripts/sydnix/src/asciidoc/types.clj index b61a365..a2f5834 100644 --- a/scripts/sydnix/src/asciidoc/types.clj +++ b/scripts/sydnix/src/asciidoc/types.clj @@ -16,7 +16,7 @@ :or {required-args {} optional-args {} content-spec (s/* ::block)}}] - (s/and vector? + (s/and seqable? (s/cat :context (s/and keyword? #{name}) :arguments (make-block-arguments required-args optional-args) :content content-spec) @@ -35,13 +35,23 @@ (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)))) diff --git a/scripts/sydnix/src/sydnix/commands/help.clj b/scripts/sydnix/src/sydnix/commands/help.clj index 6079c67..c529a3a 100644 --- a/scripts/sydnix/src/sydnix/commands/help.clj +++ b/scripts/sydnix/src/sydnix/commands/help.clj @@ -14,6 +14,11 @@ (defn- find-dispatched [dispatch] (find-satisfying #(= dispatch (:cmds %)) *cli-table*)) +(defn- format-p [s] + (-> s + (str/replace #"^ +" " ") + (str/replace #"\n +" "\n"))) + (defn- docs-for-command [command-spec] (let [command (cons "sydnix" (:cmds command-spec))] [:document {:title (str (str/join "-" command) @@ -29,13 +34,20 @@ [:section {:title "Synopsis"} [:p (format "%s [_option_…]" (str/join " " command))]] - [:section {:title "Options"} - [:p "synopsis"]]])) + (concat [:section {:title "Options"}] + (for [[opt opt-spec] (:spec command-spec)] + [:description {:described (format "*--%s%s*" + (name opt) + (if-let [ref (:ref opt-spec)] + (str "=" ref) + ""))} + [:p (format-p (:desc opt-spec))]]))])) (defn- render-docs-for-command [command-spec] (try (ar/render (docs-for-command command-spec)) (catch Exception e (prn e) + (s/explain :asciidoc.types/document command-spec) (throw e))))