Skip to content

Add :help option to dispatch: help without :restrict#155

Merged
borkdude merged 20 commits into
mainfrom
help-option
Jun 3, 2026
Merged

Add :help option to dispatch: help without :restrict#155
borkdude merged 20 commits into
mainfrom
help-option

Conversation

@borkdude
Copy link
Copy Markdown
Contributor

@borkdude borkdude commented Jun 2, 2026

No description provided.

borkdude added 20 commits June 2, 2026 23:22
(dispatch table args {:help {:prog "mytool"}}) (or :help true) intercepts
--help/-h natively in dispatch-tree (no dependence on :restrict surfacing it as
an error) and installs help-error-fn for bad/missing subcommands and flag
errors, reusing dispatch own table + :inherit. --help/-h print help for the
command they follow and exit 0; misuse exits 1. help-error-fn also fires for a
native :cause :help. --help/-h reserved while :help is on.
…fn; :prog on dispatch

dispatch now threads :prog, :inherit and the command tree into the error data,
so an :error-fn gets them for free. help-error-fn is therefore a plain
:error-fn (pass cli/help-error-fn directly, no builder, no table/inherit/prog to
re-supply). dispatch gains a top-level :prog; :help is a plain toggle that
installs help-error-fn + native --help (drops the :help {:prog} map form). No
more passing table/:inherit twice.
dispatch :help now injects a --help/-h boolean into every node spec, so it
parses as a real option and shows up in each command's Options (-h, --help).
Respects a user-defined :help/:h (does not clobber). Fixes the must-precede
parent pointer to skip options also available at the current level (a general
fix; was wrong for any redefined option). help-error-fn is now private (the
:help option is the public interface); dropped its :restrict help branch and
removed it from README + the test (covered by help-option-test). README: one
Help section centered on :help, with a single-command example.
with-help-opt now fills defaults into a user-defined :help (keeping its
position and overrides) instead of ignoring it, so `:help {}` in a spec places
--help where you want; otherwise it is appended last.
…n map order

Clojure maps are not ordered, so the help renderer no longer depends on live
map order. A vec-of-pairs :spec keeps its order through injection and rendering;
format-command-help takes :order. with-help-opt preserves a vec spec (positions
--help where you put a :help pair, else appends). command-help-context/render-help
mapify only for set reasoning, rendering Options from the raw (possibly-ordered)
spec. Moved ->spec-map earlier. Docs: lead with vec-of-pairs / :order for stable
option order.
A map spec has no reliable order, so there is no position to merge a :help into.
Respect a user-defined :help as-is, else append. The defaults-merge/positioning
stays in the vec-of-pairs branch, where position is real.
node-with-help keeps the spec a map (adds :help so it parses) and sets a display
:order: an explicit entry :order is used verbatim (you choose order, which keys
to list, and whether to list --help); otherwise one is constructed from the spec
(vec-of-pairs order or map keys) with --help appended. render-help renders
Options via that :order. format-command-help takes :order too. No display path
depends on Clojure map order anymore.
…ntry

Order is specified once, on the command entry (:order), and honored by both
dispatch and format-command-help via render-help reading (:order node). No
separate format-command-help arg.
format-command-help was public but only the lib internals render help (via the
private render-help/command-help-context, installed by the :help option). Drop
the public fn, its tests, README section and CHANGELOG entry. Help is obtained
via the :help option (prints + exits); the dedup ("child wins") and ordering
behaviors it used to test are now covered through the :help path in
help-option-test. Public help surface: dispatch :help/:prog + *exit-fn*.
These are reached only via dispatch :help (the inject-helpd tree), where every
node :spec is already a map. The defensive ->spec-map calls were no-ops. The one
real vec->map conversion stays in node-with-help: one per node, at inject.
--help/-h is a success path: dispatch routes it to a :help-fn (print-command-help)
that prints help and returns - no *exit-fn*, the process ends 0 like a normal
:fn. Real errors (unknown/missing subcommand, flag) go to :error-fn, which prints
a terse message and exits non-zero via *exit-fn*. Bare group is now terse ("No
subcommand given." + commands + hint, exit 1) instead of full help, matching
git/cli-tools/clap/argparse; full help is via --help on the group. Both handlers
overridable (:help-fn / :error-fn). *exit-fn* is errors-only now.
Making :help-fn/:error-fn pluggable creates an external use case: a custom
:help-fn needs a public way to render the standard help and add to it. That is
format-command-help - re-exposed (public), and the default :help-fn now dogfoods
it. Restored the defensive ->spec-map in command-help-context/render-help since
they are reachable standalone again (vec-of-pairs specs). Default handlers stay
private. Tests + README + CHANGELOG restored, plus a custom :help-fn test.
Drop the invented :unknown-subcommand/:missing-subcommand remap; the
default :error-fn passes the dispatch cause as-is into *exit-fn*.
Mirrors format-command-help: takes the :error-fn data map and returns the
terse error string (commands+hint for :no-match/:input-exhausted, usage+hint
for flag causes). The default :error-fn now prints it via a thin
print-command-error wrapper. A custom :error-fn can render the standard
message and add its own output, then exit via *exit-fn*.
The :prog/:inherit threading was duplicated in three spots (the flag
error-fn wrapper and both dispatch-tree branches). One helper now.
Match the terse style of released entries; drop rationale and edge-case
asides.
@borkdude borkdude merged commit 096aac7 into main Jun 3, 2026
20 checks passed
@borkdude borkdude deleted the help-option branch June 3, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant