#Argument Parser
Status: standard library specification draft.
This chapter defines std.cli, which lib/std writes in ordinary hd
over the language tier:
ArgParser, which declares flags, options, positionals, and subcommands;parseandparse_args, which read arguments intoParsed;CliError, the parse errors, and the exit status they give;usage, the generated help text.
The arguments themselves come from Args
(Program Arguments). What hd passes as a
program's arguments is CLI tier
(Program Arguments).
#Declaring Arguments
A ArgParser value lists what a program accepts. Its builder changes one shared parser through a mutable reference:
use std.cli.{Arg, ArgParser}
fn tool() -> *mut ArgParser:
ArgParser::new("count").arg(Arg { name: "verbose", kind: .Flag, short: 'v', help: "print each file" }).arg(Arg { name: "out", kind: .Option, short: 'o', help: "write the total here" }).arg(Arg { name: "pattern", kind: .Positional, required: true, help: "the files to count" })pub enum ArgKind:
Flag
Option
Positional
pub struct Arg:
pub name: string
pub kind: ArgKind = .Option
pub short: char? = .None
pub help: string = ""
pub required: bool = false
pub choices: List[string] = []
pub repeated: bool = false- std-cli.parser.decl-choices
std.clideclaresArgParser, a struct with private fields, and publicArgKindandArgas shown above. - std-cli.parser.new-help
ArgParser::new(program: string, about: string = "") -> *mut ArgParserreturns a new parser with automatic help. - std-cli.parser.arg
arg(*mut self, arg: Arg) -> *mut ArgParserappends a declaration in place and returns the same parser reference. - std-cli.parser.kind
ArgKind.Flagtakes no value,Optiontakes one value, andPositionaltakes a positional value. - std-cli.parser.namesAn argument's
nameis its lookup name; flags and options also accept--nameand an optional short form. - std-cli.parser.duplicateDeclaring any argument name twice, any short option twice, or a short form on a positional panics. Panic:
explicit-panic. - std-cli.parser.positional-orderPositionals fill declarations in order and are required only when their
requiredfield is true. - std-cli.parser.indexedDeclaration and parsing should take linear time in declaration and argument counts, using indexed option lookup and in-place appends.
- std-cli.parser.choices
choiceslimits supplied values when nonempty; an empty list allows any value. - std-cli.parser.repeated-values
repeated: truepermits repeated value-taking options and positional rest values; its default is false. - std-cli.parser.helpEvery parser declares the value-free flag
help, with short formhand descriptionPrint this help..
Why. A builder needs no fact types and no derivation, and it reads like Go's
flagand Node'sutil.parseArgstables. A typed form, which derives a parser from a struct asDeserializedoes, can follow over the same parser.
#Subcommands
A subcommand has its own argument declarations, as in ArgParser::new("notes").command("clean", *ArgParser::new("notes clean")).
- std-cli.command.decl
command(*mut self, name: string, parser: ArgParser) -> *mut ArgParseradds a command and returns the parent parser reference. - std-cli.command.snapshot
commandstores the supplied parser by value; later changes to the original builder do not change the stored command. - std-cli.command.no-positionalsDeclaring a command beside a positional, in either order, panics. Panic:
explicit-panic. - std-cli.command.duplicateDeclaring a command name twice panics. Panic:
explicit-panic. - std-cli.command.lookupThe first plain argument names a command through one indexed lookup.
- std-cli.command.scopeThe child parses only arguments after its name, with its own declarations; global options are read before the command.
- std-cli.command.unknownAn undeclared command name returns
CliError.UnknownCommand(text)with the supplied name astext. - std-cli.command.missing-requiredA parser with required commands returns
CliError.MissingCommandwhen no command was selected. - std-cli.command.end-scopeAn outer
--makes its following command name plain, but does not disable option parsing within the selected child. - std-cli.command.costDelegation should pass the original input and its offset without copying the remaining arguments at each nesting level.
#Parsing
parse reads a list of arguments, and parse_args reads the program's
own:
use std.cli.{Arg, ArgParser, CliError}
use std.host.Args
fn tool() -> *mut ArgParser:
ArgParser::new("count").arg(Arg { name: "verbose", kind: .Flag, short: 'v', help: "print each file" }).arg(Arg { name: "out", kind: .Option, short: 'o', help: "write the total here" }).arg(Arg { name: "pattern", kind: .Positional, required: true, help: "the files to count" })
fn target() -> string $ Args:
match tool().parse_args():
.Ok(parsed) => parsed.value("out").unwrap_or("stdout")
.Err(error) => "$error"| Rule | Method | Result |
|---|---|---|
std-cli.parse.parserparse |
pub fn parse(&self, arguments: List[string]) -> Result[Parsed, CliError] |
what arguments hold, read from first to last against the declarations |
std-cli.parse-args.parserparse_args |
pub fn parse_args(&self) -> Result[Parsed, CliError] $ Args |
parse of the list() of the Args provider that covers the call |
- std-cli.parse.plain
parseandparse_argsare plain calls, not bang calls.parsehas the empty requirement row.
#Argument Forms
Each argument is read by its form:
| Rule | Argument | Read as |
|---|---|---|
| std-cli.form.long-user-flagLong flag | --name |
a non-help flag name is set |
| std-cli.form.short-user-flagShort flag | -c |
a non-help flag whose short name is c is set |
| std-cli.form.long-optionLong option | --name VALUE |
the next argument is the value of the option name |
| std-cli.form.attachedAttached value | --name=VALUE |
the text after the first = is the value of the option name |
| std-cli.form.short-optionShort option | -c VALUE |
the next argument is the value of the option whose short name is c |
| std-cli.form.end-scopeEnd of options | -- |
dropped; later arguments in this parser are plain arguments |
| std-cli.form.dash-scopeLone dash | - |
a plain argument |
| std-cli.form.plain-argumentPositional | an argument that does not start with - |
a plain argument |
- std-cli.form.interleavedFlags, options, and positionals may come in any order before
--. - std-cli.form.no-clustersOnly the forms in the table name a flag or an option. So
-vq,-ofile, and-o=fileare each one unknown option. - std-cli.form.value-dashAn option's value is the next argument even when that argument starts with
-or is--. - std-cli.form.attached.textAn attached value may be empty, and may hold
=:--out=a=bgivesa=b. - std-cli.form.repeat-user-flagA non-help flag given more than once is set once.
- std-cli.form.repeat-declaredAn option with
repeated: trueretains every supplied value in argument order, andvaluereturns the last. - std-cli.form.repeat-refusedA second occurrence of a value-taking option with
repeated: falsereturnsInvalidValue. - std-cli.form.plain-commandIn a parser with commands, the first plain argument selects a command; otherwise, plain arguments are positionals.
use std.cli.{Arg, ArgParser}
fn tool() -> *mut ArgParser:
ArgParser::new("count").arg(Arg { name: "verbose", kind: .Flag, short: 'v', help: "print each file" }).arg(Arg { name: "out", kind: .Option, short: 'o', help: "write the total here" }).arg(Arg { name: "pattern", kind: .Positional, required: true, help: "the files to count" })
fn out_of(arguments: List[string]) -> string:
match tool().parse(arguments):
.Ok(parsed) => parsed.value("out").unwrap_or("stdout")
.Err(error) => "$error"
fn demo() -> List[string]:
[out_of(["-o", "a.txt", "*.txt"]), # a short option takes the next argument
out_of(["--out=b.txt", "*.txt"]), # an attached value
out_of(["--", "--out"])] # after --, a positional: "stdout"Why. Clusters and attached short values make
-ofileambiguous beside a flag-f. Go'sflagpackage leaves them out too, and a script rarely misses them.
#Parse Errors
CliError reports declaration-relative parse failures and refused typed values
(Typed Values):
pub enum CliError:
UnknownOption(text: string)
MissingValue(name: string)
UnexpectedValue(name: string)
MissingArgument(name: string)
InvalidValue(name: string, reason: string)
UnknownCommand(text: string)
MissingCommand
Help(usage: string)| Rule | Variant | When | Display text |
|---|---|---|---|
| std-cli.error.unknownUnknown option | UnknownOption |
an argument that starts with -, is not - or --, and names no declared flag or option |
unknown option TEXT |
| std-cli.error.missing-valueMissing value | MissingValue |
an option without = is the last argument |
option --NAME needs a value |
| std-cli.error.unexpected-valueUnexpected value | UnexpectedValue |
a flag is written --name=VALUE |
flag --NAME takes no value |
| std-cli.error.missing-argumentMissing argument | MissingArgument |
a required flag, option or positional is absent | missing argument NAME |
-
std-cli.error.enum-help
CliErrordeclares the eight variants above, all of whichparsemay return. -
std-cli.error.required-argument
MissingArgumentnames a missing required argument as--namefor a flag or option, or<name>for a positional. -
std-cli.error.traits
CliErrorimplementsEq,Debug, andDisplay. -
std-cli.error.text
UnknownOption'stextis the argument as written, up to its first=when it starts with--. -
std-cli.error.option-name
MissingValueandUnexpectedValuehold the option or flag’s long name. -
std-cli.error.displayIn the
Displaytext,TEXT,NAME, andREASONstand for the variant's field. -
std-cli.error.first-required
parsereturns the first error in argument order, then checks required arguments in declaration order. -
std-cli.error.help-stop
-hor--helpimmediately returnsCliError.Help(usage)for the current command, before reading later arguments or checking required arguments. -
std-cli.parse.choicesA value outside a nonempty
choiceslist returnsInvalidValue(name, reason), withreasonequal toexpected CHOICES, got VALUE. -
std-cli.parse.choices-text
CHOICESjoins the declared choices withor, andVALUEis the supplied value. -
std-cli.parse.repetition-textA refused repetition returns
InvalidValue(name, "argument cannot be repeated"). -
std-cli.command.error-unknown-text
UnknownCommand(text)displaysunknown command TEXT, with the supplied command name forTEXT. -
std-cli.command.error-missing-text
MissingCommanddisplaysmissing command. -
std-cli.error.help-displayThe
Displaytext ofHelp(usage)is exactlyusage. -
std-cli.error.help-valueHelp is recognized only as an option: an option value or a word after
--retains its ordinary meaning.
Why. Help succeeds even when an otherwise required command or argument is absent, as argparse and clap allow.
#Exit Status
A command-line failure picks its exit status through CliError, not
through Error. main reports a parse error and exits with its code:
use std.cli.{Arg, ArgParser}
use std.host.Args
use std.process.ExitCode
pub fn main() -> ExitCode $ Args + Console:
cli := ArgParser::new("tool").arg(Arg { name: "level", help: "how loud" })
parsed := match cli.parse_args():
.Ok(parsed) => parsed
.Err(error) => return error.exit()
println(parsed.value("level").unwrap_or("quiet"))
ExitCode(0)Open in playgroundWith --levl 3, this main writes unknown option --levl as error
output and exits with status 2.
- std-cli.error.exit-code-help
CliErrorhas the methodpub fn exit_code(self) -> ExitCode. It returnsExitCode(0)forHelp, otherwiseExitCode(2). - std-cli.error.exit-help
CliErrorhas the methodpub fn exit(self) -> ExitCode $ Console. It writesHelpto standard output or other errors to standard error, then returnsexit_code().
Why. As in clap, the exit code of a usage error belongs to the command-line error type.
Errorhas no exit code, somainchooses one by callingexit.
#Parsed Arguments
Parsed holds what parse read:
fn first(arguments: List[string]) -> string?:
match tool().parse(arguments):
.Ok(parsed) => parsed.value("pattern")
.Err(_) => .None- std-cli.parsed.private
Parsedis a value with private storage and implementsEqandDebug; its methods expose copied values. - std-cli.parsed.flag-presence
flag(self, name: string) -> boolreturns whether the declared flag was present. - std-cli.parsed.named-value
value(self, name: string) -> string?returns the last option value or the declared positional value, otherwise.None. - std-cli.parsed.positional-copy
positionals(self) -> List[string]returns a copy of every positional in input order, including undeclared extras. - std-cli.parsed.unknownFor an undeclared name,
flagreturns false andvaluereturns.None. - std-cli.parsed.all-values
values(self, name: string) -> List[string]returns copied option or declared positional values forname, in argument order. - std-cli.parsed.values-emptyFor flags, absent arguments, and undeclared names,
valuesreturns an empty list. - std-cli.parsed.command
command(self) -> (string, Parsed)?returns the selected command name and copied child result, or.Nonewithout a command.
#Typed Values
value_as reads an option's value as any type that implements
Parse:
use std.cli.{Arg, ArgParser, CliError}
fn max_lines(args: List[string]) -> Result[usize, CliError]:
parsed := ArgParser::new("tail").arg(Arg { name: "max", kind: .Option, short: .None, help: "lines to show" }).parse(args)?
.Ok(parsed.value_as::[usize]("max")?.unwrap_or(10))- std-cli.parsed.value-as
Parsedhas the methodpub fn value_as[T < Parse[Error = E], E < Display](self, name: string) -> Result[T?, CliError]. The call names the type, as inparsed.value_as::[usize]("max"). - std-cli.value-as.absentWhen
value(name)is.None,value_asreturns.Ok(.None). - std-cli.value-as.presentWhen
value(name)is.Some(text)andT::parse(text)returns.Ok(value),value_asreturns.Ok(.Some(value)). - std-cli.value-as.invalidWhen
T::parse(text)returns.Err(error),value_asreturns.Err(CliError.InvalidValue(name, reason)).reasonis theDisplaytext oferror. - std-cli.value-as.displayThe
Displaytext ofInvalidValueisinvalid value for --NAME: REASON.
--max value |
value_as::[usize]("max") |
|---|---|
| not given | .Ok(.None) |
"25" |
.Ok(.Some(25)) |
"x1" |
.Err(CliError.InvalidValue("max", "invalid digit at position 0")) |
Why. The error names the option, so a program can print it as it is, and carries the text, not the parse error, so
CliErrorstays one type for everyT. An absent option is.None, the same asvalue, sounwrap_orsupplies a default.
#Typed Records
The Cli trait reads typed command-line values over ArgParser.
use std.cli.Cli
@derive(Cli)
struct Pack:
verbose: bool
level: u8 = 6
exclude: List[string]
limit: u32?
fn compression() -> u8:
Pack::parse(["--level", "9"]).expect("valid arguments").level- std-cli.typed.trait
Clideclares the methods below.
| Method | Signature |
|---|---|
| Declaration | fn declare(parser: *mut ArgParser, arg: Arg) -> void |
| Reading | fn read(parsed: Parsed, arg: Arg) -> Result[Self, CliError] |
| Parser | fn parser() -> *mut ArgParser |
| Pure parsing | fn parse(arguments: List[string]) -> Result[Self, CliError] |
| Host parsing | fn parse_args() -> Result[Self, CliError] $ Args |
- std-cli.typed.parserThe default
parsercreates a parser and callsSelf::declarewith an empty name andrequired: true. - std-cli.typed.parseThe default
parseparses its arguments withSelf::parser(), then callsSelf::readwith the root declaration. - std-cli.typed.parse-argsThe default
parse_argsuses the coveringArgsprovider's program name and argument list. - std-cli.typed.requirements
parseis pure, andparse_argsrequires onlyArgs. - std-cli.typed.derive
@derive(Cli)on a record declares its fields throughDescriberand builds the result throughSource. - std-cli.typed.fieldsRecord fields become arguments with kebab-case names in declaration order.
- std-cli.typed.defaultsAn absent field with a declared default uses that default.
- std-cli.typed.requiredAn absent required scalar returns
MissingArgument("--name"), using its kebab-case name. - std-cli.typed.boolA named
boolfield declares a flag and reads false when absent, unless its field default applies. - std-cli.typed.scalarsThe scalar types below implement
Clithrough theirParseimplementations.
| Types |
|---|
string, char |
i8, i16, i32, i64 |
u8, u16, u32, u64, usize |
f32, f64 |
Path, Duration |
- std-cli.typed.scalar-errorsA refused scalar returns
InvalidValue(name, reason), with its argument name and the parse error'sDisplaytext. - std-cli.typed.containers
Option[T]andList[T]implementCliwhenTimplementsCli. - std-cli.typed.optionalAn absent optional field reads
.None, unless its field default applies. - std-cli.typed.list-valuesFor value-taking or flag declarations, a list reads every occurrence in order, or
[]when absent. - std-cli.typed.flag-listA
List[bool]flag field reads onetrueper occurrence. - std-cli.typed.viewEach list element is read through a constant-time one-value
Parsedview over shared storage. - std-cli.typed.boundsEvery field of a derived record must implement
Cli, checked at the derive. - std-cli.typed.newtypeA newtype derives
Clithrough its base type. - std-cli.typed.nested-recordParsing a record-typed field returns
InvalidValuenaming the field and explaining that subcommands are an enum.
Why. The typed layer reuses the builder's argument grammar and errors. Records do not implicitly flatten or become subcommands.
#Enum Value Sets
A payload-free enum derives a closed set of CLI values.
use std.cli.Cli
@derive(Cli)
enum Format:
Json
Markdown
@derive(Cli)
struct Report:
format: Format
fn report() -> Report:
Report::parse(["--format", "json"]).expect("valid format")- std-cli.enum-values.derive
@derive(Cli)on a payload-free enum reads the selected variant from one argument value. - std-cli.enum-values.namesAccepted values are the kebab-case variant names, matched exactly.
- std-cli.enum-values.invalidAn unknown value returns
InvalidValue(name, reason), withreasonequal toexpected CHOICES, got VALUE. - std-cli.enum-values.choice-order
CHOICESjoins the kebab-case names in declaration order withor. - std-cli.enum-values.helpThe generated argument's
choicescontains those names, so ordinary usage text lists them. - std-cli.enum-values.compositionEnum values compose with record defaults,
Option,List, and newtypes derived through the enum.
Why. The value set uses the builder's existing choice validation and help layout, while
Sourcereturns the actual enum variant.
#Short Field Facts
A Short field fact adds one short spelling to a typed CLI argument.
use std.cli.{Cli, short}
@derive(Cli)
struct Pack:
@short('v')
verbose: bool
fn verbose() -> bool:
Pack::parse(["-v"]).expect("valid flag").verbose- std-cli.short.fact
Short[F < Cli]is a typed field fact with the public fieldletter: char. - std-cli.short.constructor
short[F < Cli](letter: char) -> Short[F]constructs that fact. - std-cli.short.spellingA derived field's
Shortfact suppliesArg.short, while its long kebab-case name remains unchanged. - std-cli.short.boundA
Shortfact requires its field type to implementCli. - std-cli.short.duplicatesShort spellings retain the builder's duplicate-name checks. Panic:
explicit-panic.
Why. The fact configures the existing builder argument, so both spellings share its typed value, presence, repetition policy, and errors.
#Positional Field Facts
A Positional fact reads a typed field from plain arguments.
use std.cli.{Cli, positional}
use std.path.Path
@derive(Cli)
struct Files:
@positional
input: Path
@positional
extras: List[string]
fn files() -> Files:
Files::parse(["notes.txt", "other.txt"]).expect("valid paths")- std-cli.positional.fact
Positional[F < Cli]is a typed field fact with no fields. - std-cli.positional.constructor
positional[F < Cli]() -> Positional[F]constructs that fact. - std-cli.positional.boundA
Positionalfact requires its field type to implementCli. - std-cli.positional.orderMarked fields declare positional arguments in field declaration order.
- std-cli.positional.defaultsPositional fields retain their type's parsing, declared defaults, optional absence, and empty-list behavior.
- std-cli.positional.requiredAn absent required positional returns
MissingArgument("<name>"), using its kebab-case field name. - std-cli.positional.restA repeated positional, including a typed
List[T]field, consumes the remaining plain arguments in order. - std-cli.positional.rest-values
values(name)returns every value of a repeated positional, andvalue(name)returns its last value. - std-cli.positional.rest-lastDeclaring a positional after a repeated positional panics with a message naming both fields. Panic:
explicit-panic. - std-cli.positional.value-short-conflictA positional value argument retains the builder's refusal of short spellings. Panic:
explicit-panic.
Why. A rest list must be last among positional declarations, so later fields cannot become unreachable. Option declarations may follow it.
#Typed Subcommands
An enum with payload variants derives a set of subcommands.
use std.cli.Cli
@derive(Cli)
struct BuildOptions:
out: string = "site"
@derive(Cli)
enum Command:
Build(BuildOptions)
Stop
@derive(Cli)
struct Notes:
command: Command
fn notes() -> Notes:
Notes::parse(["build", "--out", "public"]).expect("valid command")- std-cli.typed-commands.deriveWhen any variant carries a payload, the enum's variants declare subcommands rather than option choices.
- std-cli.typed-commands.namesSubcommand names are the kebab-case variant names.
- std-cli.typed-commands.shapeEach variant must be unit or carry exactly one unnamed
Clipayload. - std-cli.typed-commands.payload-boundEach payload type must implement
Cli, checked at the derive. - std-cli.typed-commands.payloadA selected command delegates declaration and reading to its payload's root CLI parser.
- std-cli.typed-commands.unitA selected unit command constructs its unit variant without reading a payload.
- std-cli.typed-commands.scopeGlobal options precede the command name; arguments after it belong to the selected child's parser.
- std-cli.typed-commands.requiredA command field without a default is required unless its type is optional.
- std-cli.typed-commands.optionalAn absent
Command?reads.None. - std-cli.typed-commands.defaultAn absent defaulted command field reads its default; a selected command overrides that default.
- std-cli.typed-commands.nestedA command's payload may declare another command at the next level.
- std-cli.typed-commands.shape-errorAn unsupported payload shape returns
InvalidValuewhen parsing, with a reason naming the declared variant. - std-cli.typed-commands.one-fieldMultiple command fields at one level return
InvalidValuenaming both fields when parsing. - std-cli.typed-commands.no-repeatedA repeated command field, including one inside a wrapper, returns
InvalidValuenaming that field when parsing. - std-cli.typed-commands.help-scopeChild help uses the full command path, beginning with the
Argsprogram name forparse_args. - std-cli.typed-commands.optional-usageAn optional or defaulted command's usage term is
[<command>]. - std-cli.typed-commands.no-field-factsA command field carrying
ShortorPositionalreturnsInvalidValuenaming the field when parsing.
Why. Each level selects one command and delegates its remaining input, without implicitly flattening records. Repeated commands would need a delimiter separating their child arguments.
#Documentation In Typed Help
Typed CLI help uses the declaration documentation carried by std.structure.
use std.cli.Cli
## Pack archives for distribution.
@derive(Cli)
struct Pack:
## Print detailed progress.
verbose: bool
fn pack_help() -> string:
match Pack::parse(["--help"]):
.Err(.Help(text)) => text
_ => panic("expected help")- std-cli.typed-help.type-docA root derived CLI uses its type's
VariantInfo.type_docas the parser's about text. - std-cli.typed-help.field-docA derived record argument uses its
Member.docas argument help. - std-cli.typed-help.variant-docUnit-enum choice descriptions and subcommand descriptions use their variants'
VariantInfo.doc. - std-cli.typed-help.choice-linesDocumented choices add declaration-ordered
name: descriptionlines to argument help, after any field documentation. - std-cli.typed-help.payload-docA subcommand's help includes its variant documentation followed by its payload type documentation, when both exist and differ.
- std-cli.typed-help.current-command
-hand--helpreturnCliError.Helpfor the current command, including only that scope's about text and argument declarations. - std-cli.typed-help.absent-docAbsent documentation adds no description.
Why. Help reads the same declaration metadata as every other derivation, and preserves the command parser's existing scope boundaries.
#Usage Text
usage returns the help text. For the ArgParser above, with one more flag
dry-run that has no short name and no help, it is:
usage: count [options] <pattern>
arguments:
pattern the files to count
options:
-v, --verbose print each file
-o, --out <value> write the total here
--dry-run
-h, --help Print this help.
-
std-cli.usage.parser
pub fn usage(&self) -> stringreturns the lines below, joined by\n, with no final line break. -
std-cli.usage.command-termsThe usage line names the program,
[options], and any command or positional terms. -
std-cli.usage.positional-termA positional is
<name>when required, and[<name>]otherwise. -
std-cli.usage.argumentsWhen a positional is declared, an empty line and the line
arguments:follow, then one entry per positional, in declaration order. A positional's term is its name. -
std-cli.usage.options-help-lastAn empty line and
options:precede user-declared flags and options in declaration order, followed by automatic help. -
std-cli.usage.termA flag's or option's term is
-c, --name, or four spaces and--namewhen it has no short name. An option's term ends with<value>. -
std-cli.usage.entry-choicesAn entry starts with two spaces and its term, padded to the longest term only when help or choices follow.
-
std-cli.usage.widthA width counts characters, as
pad_enddoes. -
std-cli.usage.no-descriptionAn entry with empty help and choices is two spaces and its term, without padding.
-
std-cli.usage.automatic-helpAutomatic help is listed last as
-h, --helpwith descriptionPrint this help.. -
std-cli.usage.aboutWhen
aboutis nonempty, one empty line and its text follow the usage line. -
std-cli.usage.builder
usageshould write its result with oneStringBuilder, without repeated concatenation of the accumulated text. -
std-cli.usage.choicesChoices append
[choices: A, B]after help, separated by one space when help is nonempty. -
std-cli.usage.descriptionAfter a padded term, two spaces precede its help or choices.
-
std-cli.usage.commandsDeclared commands appear after the program description and before argument or option sections, following an empty line and
commands:. -
std-cli.usage.command-orderEach command entry is two spaces and its name, in declaration order.
-
std-cli.usage.command-aboutA nonempty command description follows its name, padded to the longest command name, and two spaces.
Why. One column of help text is the layout of Go's
flagoutput and ofhd help. The four spaces keep the long names of every term aligned.
See also: Program Arguments, Map Providers, Splitting And Padding.