Noted while reviewing #205.
runCompile detects a help request itself:
positional, err := parseArgs(fs, args)
if errors.Is(err, flag.ErrHelp) {
writeCommandHelp(stdout, newCompileCommand())
return 0
}
That is correct — detecting help through flag.ErrHelp rather than pre-scanning argv is what keeps morphic compile -o --help spec.yaml treating --help as -o's value, and TestRun_HelpFlagAsFlagValuepins it. The problem is where it lives: every subcommand added to the table has to repeat the same four lines, and a subcommand that forgets them regresses-htomorphic: flag: help requested` with nothing to catch it. The command table exists precisely so a subcommand becomes reachable and documented in one edit; this is the part that is still two.
The obvious shape is for dispatch to own it — a command supplies its FlagSet and its run body, and the shared caller maps flag.ErrHelp to writeCommandHelp + exit 0. That needs care, because runCompile currently needs the parsed options handle as well as the FlagSet, and because parseArgs's loop over positionals is compile-specific.
Cost grows with the second subcommand, not before it, so this is worth doing when one lands rather than now.
Noted while reviewing #205.
runCompiledetects a help request itself:That is correct — detecting help through
flag.ErrHelprather than pre-scanning argv is what keepsmorphic compile -o --help spec.yamltreating--helpas-o's value, andTestRun_HelpFlagAsFlagValuepins it. The problem is where it lives: every subcommand added to the table has to repeat the same four lines, and a subcommand that forgets them regresses-htomorphic: flag: help requested` with nothing to catch it. The command table exists precisely so a subcommand becomes reachable and documented in one edit; this is the part that is still two.The obvious shape is for dispatch to own it — a command supplies its
FlagSetand its run body, and the shared caller mapsflag.ErrHelptowriteCommandHelp+ exit 0. That needs care, becauserunCompilecurrently needs the parsed options handle as well as theFlagSet, and becauseparseArgs's loop over positionals is compile-specific.Cost grows with the second subcommand, not before it, so this is worth doing when one lands rather than now.