Documentation
¶
Overview ¶
Package argv binds a command line against static tables.
It is the Go half of what usage-argv is in Rust: the same grammar, proved against the same conformance corpus, with the same division of labour. The parser answers one question — which token becomes which flag or argument — and leaves everything that needs a value's type to the layer above it.
Why tables rather than a command tree ¶
Every Go CLI framework builds a model of the CLI at run time. cobra constructs a [cobra.Command] per subcommand with a flag set each; kong walks a struct with reflection. Both pay for the whole CLI on every invocation, including the 200 commands the user did not type. At mise's size that is 2M instructions for cobra and 58M for kong before the first token is read.
The tables here are package-level data with no pointers to build, so the Go linker lays them out and nothing runs before main. Binding a mise-sized command line then costs about 2,700 instructions, which is below the run-to-run variance of the Go runtime's own startup — the parse disappears into the noise rather than showing up in it.
Tables are meant to be generated from a usage spec. Writing them by hand is supported and is what the tests do, but a real CLI declares its spec and gets these emitted.
Index ¶
- Constants
- Variables
- func AllHelp(spec HelpSpec, path []string, chain []*Command, help HelpTable) string
- func AppletFromArgv0(argv0, name, bin string) (applet string, ok bool)
- func ApplyDefaultIf(meta Metadata, scope []uint64, filled map[uint64][]string, ...)
- func ApplyOverrides(meta Metadata, order map[uint64]int) map[uint64]bool
- func EnvTruth(value string) bool
- func IsHelpFlag(f *Flag) bool
- func IsVersionFlag(f *Flag) bool
- func LongHelp(spec HelpSpec, path []string, chain []*Command, help HelpTable) string
- func LookupEnv(name string) (string, bool)
- func MulticallBasename(argv0 string) string
- func RelationshipValues(m *Meta, values []string, source Source, negated bool) []string
- func Render(err *Error, path []string, chain []*Command, help HelpTable) string
- func RenderAnswer(a Answer, shell Shell) string
- func Respond(argv []string, root *Command, help HelpTable, meta Metadata) (string, bool)
- func RewriteMulticall(argv0 string, args []string, name, bin string) []string
- func Script(bin string, shell Shell) string
- func ShortHelp(spec HelpSpec, path []string, chain []*Command, help HelpTable) string
- func SplitValue(value string, delimiter byte, delimit bool) []string
- func UsageLine(path []string, cmd *Command, help HelpTable) string
- type Answer
- type Arg
- type ArgAction
- type Candidate
- type CandidateKind
- type Code
- type Command
- type DefaultIf
- type DoubleDash
- type Error
- func Bool(name, value string) (bool, *Error)
- func Check(m *Meta, values []string, occurrences int) *Error
- func CheckDisplaced(m *Meta, values []string) *Error
- func CheckRelationships(meta Metadata, entries []uint64, sourceOf func(uint64) Source) *Error
- func CheckRelationshipsWithValues(meta Metadata, entries []uint64, sourceOf func(uint64) Source, ...) *Error
- func CheckRelationshipsWithValuesAndRequirements(meta Metadata, entries []uint64, sourceOf func(uint64) Source, ...) *Error
- func Duration(name, value string) (time.Duration, *Error)
- func Each[T any](name string, values []string, convert func(string, string) (T, *Error)) ([]T, *Error)
- func Float(name, value string) (float64, *Error)
- func Int(name, value string) (int64, *Error)
- func Uint(name, value string) (uint64, *Error)
- type Event
- type Example
- type Files
- type Flag
- type Heading
- type Help
- type HelpSpec
- type HelpTable
- type Kind
- type Meta
- type Metadata
- type Parser
- func (p *Parser) Collecting() *Flag
- func (p *Parser) Command() *Command
- func (p *Parser) CommandStart() int
- func (p *Parser) DoubleDashSeen() bool
- func (p *Parser) Err() error
- func (p *Parser) Event() Event
- func (p *Parser) FlagsInScope(fn func(*Flag) bool)
- func (p *Parser) FlagsStopped() bool
- func (p *Parser) Next() bool
- func (p *Parser) PendingArg() *Arg
- func (p *Parser) SubcommandsPossible() bool
- type Position
- type Request
- type Shell
- type Source
- type SplitLine
- type UnknownFlags
- type ValueCondition
- type ValueRequirement
Constants ¶
const ( FilesMarker = "\x01files" DirsMarker = "\x01dirs" ExecutablePathsMarker = "\x01executables" CommandsMarker = "\x01commands" )
The line a shell reads to mean "paths belong here too".
A whole line rather than a flag on the protocol, because every one of the five shells can already split output into lines and look at the last one. `\x01` opens it because no candidate can contain a control character — the parser's values are escaped before they are rendered anywhere — so it cannot be mistaken for one.
const MaxDepth = 16
MaxDepth is how deep a command tree the parser will descend.
The ancestor chain lives in a fixed-size array so that a parse allocates nothing; this is that array's size. mise, the largest usage CLI, is four levels deep.
const RequestName = "__complete_word__"
RequestName is the argument that marks a completion request.
Long and ugly on purpose: it is typed by a script, never by a person, and it has to be a word no CLI would want for itself.
Variables ¶
var ( // HelpLong is the synthetic --help. HelpLong = &Flag{Key: ^uint64(0), Name: "help", Longs: []string{"help"}, Action: ActionHelpLong} // HelpShort is the synthetic -h. HelpShort = &Flag{Key: ^uint64(0) - 1, Name: "help", Shorts: []byte{'h'}, Action: ActionHelpShort} // VersionLong is the synthetic --version, offered only where the command says // Version. VersionLong = &Flag{Key: ^uint64(0) - 2, Name: "version", Longs: []string{"version"}, Action: ActionVersion} // VersionShort is the synthetic -V. VersionShort = &Flag{Key: ^uint64(0) - 3, Name: "version", Shorts: []byte{'V'}, Action: ActionVersion} )
The two flags every CLI answers to without declaring them. Package-level so that an event can point at one without allocating, and so that a caller can compare a reported flag against them by identity.
var HelpSections = [...]string{
"about", "usage", "commands", "args", "flags",
"grouped_args", "ungrouped_args", "grouped_flags", "ungrouped_flags",
"after_help",
}
HelpSections is the vocabulary a HelpTemplate may name, and nothing else.
A closed list on purpose. Handing a template the metadata behind a page instead would make this renderer's internals part of the spec and ask every implementation to expose the metadata behind a section. They agree on these boundaries and the small colour-tag vocabulary instead.
about BeforeHelp, the version banner, and the description usage the Usage: synopsis, however many lines it takes commands the subcommand list, or the flattened bodies under FlattenHelp args every argument group, each under its heading flags this command's flag groups, then the globals it inherits grouped_args arguments with a declared help heading ungrouped_args arguments under the default Arguments heading grouped_flags flags with a declared help heading ungrouped_flags flags under Flags, plus inherited global flags after_help examples, AfterHelp, and the author/license footer on a long page
An array rather than a slice, so the vocabulary cannot grow or shrink the way a package-level slice can. The names themselves are still assignable; nothing in this package writes them.
var HelpStyles = [...]string{
"heading", "option", "metavar",
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white",
"bright-black", "bright-red", "bright-green", "bright-yellow", "bright-blue",
"bright-magenta", "bright-cyan", "bright-white",
"bold", "dim", "italic", "underline",
}
HelpStyles is the closed style vocabulary accepted by HelpTemplate.
Functions ¶
func AppletFromArgv0 ¶
AppletFromArgv0 is the applet name to parse as the first word, when argv0 is not the dispatcher. ok is false for a dispatcher invocation (busybox ls): skip argv0 and parse the rest. ok is true for a symlink invocation (ls -l): inject the basename.
func ApplyDefaultIf ¶
func ApplyDefaultIf(meta Metadata, scope []uint64, filled map[uint64][]string, sources map[uint64]Source, negated map[uint64]bool)
ApplyDefaultIf fills entries still unset after Fill, using sibling state.
First matching DefaultIf wins; an unconditional Default applies only when none did. Mutates `filled` and `sources` in place. A no-op when nothing declares DefaultIf, so generated parsers can always call it.
`negated` is which flags arrived as their negate form (`--no-json`). An Equals DefaultIf on a bool reads that as "false", the same way RelationshipValues does for requires_if. A nil map is all false.
func ApplyOverrides ¶
ApplyOverrides decides last-one-wins between flags declared to override each other, returning the keys that lost.
`order` gives the position of each key's last occurrence on the command line. A key absent from it was not typed, and cannot win or lose: the declaration is about which of two *given* flags survives.
A loser must be treated as absent by everything downstream, and in particular must not be refilled from `env` or `default`. Filling it afterwards would leave both flags standing and undo the last-one-wins the user asked for by typing the second one.
The relationship is symmetric however it was declared. `--file overrides --stdin` establishes the pair; it does not mean `--file` always wins. The corpus pins that directly: with `--file` declaring it and `--stdin` typed last, `--file` is the one that loses.
func EnvTruth ¶
EnvTruth reports whether an environment value sets a flag that holds no value.
A flag with no value has nowhere to put the text, so the variable has to be read as a yes or a no — and `EX_VERBOSE=0` meaning "verbose" would be a trap.
An allow-list rather than a not-falsy test, matching usage-lib exactly, which means `yes`, `on` and `TrUe` are all false. That is worth knowing rather than discovering: the corpus pins `1`, `true`, `false` and `0`, and the rest of the list is here so the two implementations cannot drift on the cases it does not.
func IsHelpFlag ¶
IsHelpFlag reports whether a flag is one the parser supplied for --help or -h.
func IsVersionFlag ¶
IsVersionFlag reports whether a flag is one the parser supplied for --version or -V.
func LookupEnv ¶
LookupEnv reads the process environment, for callers that want it.
Fill takes the lookup as a parameter rather than reading the environment itself, so that a test of a parse is not a test of the machine it runs on. Generated code passes this, because a real CLI does want the real environment.
func MulticallBasename ¶
MulticallBasename is the last path component of argv0, with a trailing .exe stripped so Windows and Unix agree.
func RelationshipValues ¶
RelationshipValues canonicalizes the values used by value-conditional relationships. It leaves value-taking entries alone and turns every boolean source into the same "true" or "false" spelling.
func Render ¶
Render turns a failure into the text a CLI should print to stderr.
`path` and `chain` are the command as invoked, as for ShortHelp, so the usage line names the command the user was actually in rather than the program.
Help and version are not failures and render as nothing: a caller that gets CodeHelp should print the page, not this.
func RenderAnswer ¶
RenderAnswer writes an answer in the protocol `shell` reads.
Named for what it renders rather than just `Render`, because Render already belongs to failures. Two things in one package both turning a value into text for a terminal is reason enough to say which.
func Respond ¶
Respond is the whole of what a CLI has to do: recognize the request, answer it, and write the text its shell reads.
Returns false where argv is an ordinary invocation, which is the caller's cue to parse it as one.
func RewriteMulticall ¶
RewriteMulticall prepends argv0's basename when it is an applet rather than the dispatcher. args are the tokens after the program name.
func Script ¶
Script is the completion script for `bin` in `shell`, ready to be written to a file or sourced.
The binary is named rather than found: a script that resolved the binary itself would complete against whichever copy came first on `PATH`, which is not always the one the user is typing.
Every invocation quotes the name, so one containing a space still *runs*. Registering it is another matter: zsh's `#compdef` line is a magic comment read by `compinit` before any shell quoting happens, and there is nowhere to put a quote in it. A binary whose name is not a single shell word therefore cannot be completed in zsh by anyone, which the panic below says out loud rather than leaving to be discovered at a prompt.
func ShortHelp ¶
ShortHelp renders what `-h` prints for the command at the end of `chain`.
`path` is the command as invoked, binary first. `chain` is the commands from the root down to this one, which is what a page needs to work out which inherited globals are still this command's to offer.
func SplitValue ¶
SplitValue applies a generated table's ASCII delimiter to one bound value. Delimit is false for trailing positional values protected by DontDelimitTrailingValues.
Types ¶
type Arg ¶
type Arg struct {
// Key is a caller-assigned identifier, echoed back in the event.
Key uint64
// Required is used while binding when AllowMissingPositional reserves words
// for later required positionals.
Required bool
// Name is unused by binding, kept so a table entry can carry its own name for
// diagnostics.
Name string
// Var is whether this argument keeps taking values once it has one.
Var bool
// VarMax is how many words a variadic may take before the next argument gets
// the rest. Zero means unbounded.
//
// A bound belongs here, in the table binding reads, rather than with the
// metadata: it decides where a word lands, not whether what landed is
// acceptable. clap's num_args works the same way, and specs are commonly
// generated from clap commands.
VarMax uint32
// AllowNegativeNumbers accepts negative numeric tokens in strict flag mode.
AllowNegativeNumbers bool
// ValueTerminator ends this variadic positional without becoming a value.
ValueTerminator string
// Delimiter splits one token into several values. Zero disables splitting.
Delimiter byte
// DoubleDash is this argument's relationship to the -- separator.
DoubleDash DoubleDash
}
Arg is a positional argument.
type Candidate ¶
type Candidate struct {
Kind CandidateKind
// Value is the text to insert.
Value string
// Describe is the one-line help, where there is any. A shell that can show a
// description beside a completion uses it; one that cannot ignores it.
Describe string
}
Candidate is one thing that could be typed where the cursor is.
func Candidates ¶
Candidates is everything that could go at a position, given a partial word.
`partial` is what the user has typed of the current word, and filtering happens here rather than in the shell so that every shell agrees about what matches.
type CandidateKind ¶
type CandidateKind uint8
Kind of thing a candidate is, so a shell can decorate or filter them.
const ( // CandidateCommand is a subcommand name or alias. CandidateCommand CandidateKind = iota // CandidateFlag is a flag spelling. CandidateFlag // CandidateValue is one of a declared `choices` list. CandidateValue )
type Code ¶
type Code uint8
Code is a class of binding failure.
The grammar specifies the class, not the wording: diagnostics are a quality-of-implementation concern, but a strict parser and a lenient one must be tellable apart mechanically. These are the codes the conformance corpus uses.
const ( // CodeUnknownFlag means a flag-like token matched no flag in scope. CodeUnknownFlag Code = iota // CodeMissingFlagValue means a flag needing a value did not get one. CodeMissingFlagValue // CodeUnexpectedArg means a word arrived with no argument left to hold it. CodeUnexpectedArg // CodeSubcommandConflict means an argument was bound before a subcommand. CodeSubcommandConflict // CodeArgRequiresDoubleDash means a double_dash="required" argument was // offered a word before any -- had been seen. CodeArgRequiresDoubleDash // CodeTooDeep means the command tree is deeper than MaxDepth. CodeTooDeep // CodeHelp means --help or -h was given. Not a failure; see [Error]. CodeHelp // CodeVersion means --version or -V was given. Not a failure either. CodeVersion // CodeMissingRequiredFlag means a required flag never appeared. CodeMissingRequiredFlag // CodeMissingRequiredArg means a required argument was never filled. CodeMissingRequiredArg // CodeInvalidChoice means a value was given that is not among the declared // choices. CodeInvalidChoice // CodeVarTooFew means fewer values than var_min. CodeVarTooFew // CodeVarTooMany means more occurrences than a repeatable flag's var_max. CodeVarTooMany // CodeConflictingFlags means two flags declared to conflict were both given. CodeConflictingFlags // CodeInvalidValue means a value was given that the target type could not be // built from. CodeInvalidValue // CodeDuplicateFlag means a strict command received a single-valued flag // more than once. CodeDuplicateFlag )
type Command ¶
type Command struct {
// Name is the canonical name, used to select this command.
Name string
// Aliases are alternative names that also select it.
Aliases []string
Flags []*Flag
// Args are positional arguments, in the order they are filled.
Args []*Arg
Subcommands []*Command
// DefaultSubcommand is where a word goes when it names no subcommand of this
// one.
//
// The spec's default_subcommand. `mise build` means `mise run build`: the word
// names no command, so the parser descends into `run` and lets run have it —
// even where this command declares an argument of its own, which is what makes
// the property worth having rather than a synonym for a positional.
//
// Applied at most once per parse, so a CLI cannot loop through it, and only
// where a subcommand could still be selected.
DefaultSubcommand *Command
// ExternalSubcommand is whether an unmatched word is forwarded as an external
// command plus the rest of argv.
//
// clap's allow_external_subcommands. Known subcommands still win; a
// DefaultSubcommand still catches first. Once the unmatched word is taken,
// remaining tokens — including --help — are not parsed as this command's flags.
ExternalSubcommand bool
// ArgRequiredElseHelp shows this command's help when no argv token follows its name.
ArgRequiredElseHelp bool
// SubcommandNegatesReqs lets a selected child satisfy this command's requirements.
SubcommandNegatesReqs bool
// ArgsConflictWithSubcommands rejects selecting a child after this command
// has already bound a flag or positional.
ArgsConflictWithSubcommands bool
// SubcommandPrecedenceOverArg lets a known child interrupt a variadic value owner.
SubcommandPrecedenceOverArg bool
// AllowMissingPositional lets later required positionals claim remaining words
// while earlier optional positionals stay empty.
AllowMissingPositional bool
// DontDelimitTrailingValues disables delimiter splitting after -- and for
// automatic trailing arguments. It is inherited by subcommands.
DontDelimitTrailingValues bool
// UnknownFlags is what an unrecognized flag-like token means here. Already
// resolved: inheritance is a question for whoever builds the tables.
UnknownFlags UnknownFlags
// Version is whether this command answers to --version and -V.
//
// Set on the root, and only when the CLI declares a version: a --version that
// answers with nothing is worse than one that is not there.
Version bool
// DisableHelpFlag removes the synthetic --help and -h entries.
DisableHelpFlag bool
// DisableHelpSubcommand removes the synthetic `help` route.
DisableHelpSubcommand bool
// DisableVersionFlag removes the synthetic --version and -V entries.
DisableVersionFlag bool
// Key is a caller-assigned identifier, echoed back in the event.
//
// Generated code dispatches on this instead of comparing strings. Rust needs
// 64 bits here because two macro expansions cannot see each other and must
// hash their way to uniqueness; a Go generator sees the whole spec at once and
// can simply count, but the width costs nothing and keeps the two tables
// interchangeable.
Key uint64
}
Command is a command: its flags, its positional arguments, and its subcommands.
Every field is plain data or a slice of pointers to plain data, which is what lets a generated table be package-level `var` the linker initializes. Check with `go tool nm`: the symbols should be type D, and the package should have no init function.
type DoubleDash ¶
type DoubleDash uint8
DoubleDash is how an argument relates to the -- separator.
const ( // DoubleDashOptional lets values appear on either side of a --. DoubleDashOptional DoubleDash = iota // DoubleDashRequired accepts values only after a --. DoubleDashRequired // DoubleDashPreserve keeps a -- as a value rather than consuming it as a // separator. DoubleDashPreserve // DoubleDashAutomatic behaves as if a -- had been given once the argument // takes a value, so the rest of the command line is values. A wrapper can then // forward flags without its caller typing the separator. DoubleDashAutomatic )
type Error ¶
type Error struct {
Code Code
// Token is the whole token as typed, for CodeUnknownFlag and
// CodeUnexpectedArg. A bundle containing an unrecognized letter reports -fz
// rather than the letter alone, which is also the unit in which it is
// rejected.
Token string
// Flag is set for CodeMissingFlagValue.
Flag *Flag
// Arg is set for CodeArgRequiresDoubleDash.
Arg *Arg
// Cmd is what CodeHelp was asked about.
Cmd *Command
// All asks for this command and every visible descendant rather than one page.
All bool
// Long distinguishes --help from -h, which print different amounts.
Long bool
// Name is the flag or argument the post-binding rules rejected, as the spec
// spells it.
Name string
// Spelling is how the entry is typed, where the rule that raised this knew —
// see [Meta.Spelling]. Empty means only the name is known.
Spelling string
// OtherSpelling is the same for [Error.Other].
OtherSpelling string
// Choices carries the declared list for CodeInvalidChoice, rather than the
// offending value: the value is the caller's to render, and it has it.
Choices []string
// Bound and Got are the declared limit and what was actually counted, for the
// two var codes.
Bound uint32
Got int
// Value is the text that would not convert, and Want the type it was being
// converted to, for CodeInvalidValue. The text is carried because the whole
// point of the error is to show it back.
Value string
Want string
// Reason explains a declarative validation failure. Empty for ordinary typed
// conversion failures, which use Want instead.
Reason string
// Other is the flag [Name] cannot be given with, for CodeConflictingFlags.
// Both are carried because either alone reads as a puzzle: which flag is
// unwelcome depends on what else was given.
Other string
}
Error is a binding failure.
It carries the offending token so a caller can render a good message, but no message of its own beyond the code: rendering belongs to a cold path, and building a string here would allocate on the way to reporting that nothing was allocated.
Help and Version ride in this type without being failures, as clap and usage-argv both have them: a parse that stops to print help has not produced a value, and every caller already handles the "no value" shape.
The parser holds one of these inline and hands back a pointer to it, so a failing parse allocates nothing either.
func Bool ¶
Bool converts a bound value to a bool.
The spellings are Go's own, which are also the ones `strconv.ParseBool` takes: `1`, `t`, `T`, `true`, `TRUE`, `True` and their false counterparts. Note this is *wider* than EnvTruth, which an environment variable setting a value-less flag goes through — that one is an allow-list matching usage-lib, and the two answer different questions: this converts a value somebody typed, that one decides whether a variable counts as setting a flag at all.
func Check ¶
Check applies the rules that judge what ended up bound.
`values` is the result of Fill, and `occurrences` is how many times a repeatable flag was given — which is not `len(values)`, since one occurrence of a variadic can bring several. Pass 0 for an argument.
The first failure is returned; a caller wanting all of them should call this per entry, which it is doing anyway.
func CheckDisplaced ¶
CheckDisplaced judges the words an entry was typed, and nothing else about it.
It is the half of Check that still applies to a flag which lost an `overrides`. Such a flag is out of the running for `required`, for `env` and `default`, and for the rules that read one entry to judge another — but `overrides` settles which of a pair is *in effect*, not whether the word the loser was handed was ever one it accepts. `--log-level=v --trace` is refused for that reason, and usage-lib and the Rust derives agree; the corpus pins it as `overrides-do-not-erase-an-invalid-choice`.
Pass the values the command line supplied, before any `env` or `default` fallback: a loser is not filled from either, so there is nothing else to judge.
func CheckRelationships ¶
CheckRelationships verifies the rules that read one entry's state to judge another, once every entry's final state is known.
`entries` is every key in scope, so each declaration is visited once, and `sourceOf` reports where each entry's value came from — the whole Source rather than a yes or no, because the rules need both readings of it.
As a *partner*, only the command line and the environment count. `conflicts` asks whether a flag has a value rather than how it got one, so an environment variable counts on both sides and the corpus pins the one-sided and neither-side-typed cases. A default does not count: it is a fallback rather than something the user said, and counting it would make a defaulted flag conflict with every partner anyone types.
As the entry *being judged*, a default does count — it has a value, so it is not missing. usage-lib agrees on both halves, and a caller that collapsed `sourceOf` into one predicate would get one of them wrong whichever way it chose.
A key removed by ApplyOverrides should not appear in `entries` at all: it lost, so it is out of the running rather than merely absent.
func CheckRelationshipsWithValues ¶
func CheckRelationshipsWithValues(meta Metadata, entries []uint64, sourceOf func(uint64) Source, valuesOf func(uint64) []string) *Error
CheckRelationshipsWithValues also enforces value-conditional requirements.
`valuesOf` reports canonical values for an entry. Boolean flags should report "true" or "false" regardless of whether that value came from a spelling such as `--feature`, its negation, or a truthy environment value.
func CheckRelationshipsWithValuesAndRequirements ¶
func CheckRelationshipsWithValuesAndRequirements(meta Metadata, entries []uint64, sourceOf func(uint64) Source, valuesOf func(uint64) []string, requirementsOf func(uint64) bool) *Error
CheckRelationshipsWithValuesAndRequirements additionally selects which entries have their positive requirement rules enforced. Conflicts always apply.
func Duration ¶
Duration converts a bound value to a duration, in Go's notation: `1h30m`, `250ms`, `2s`.
func Each ¶
func Each[T any](name string, values []string, convert func(string, string) (T, *Error)) ([]T, *Error)
Each maps a conversion over the values a variadic or repeatable entry collected, stopping at the first that will not convert.
Written out because the alternative is every caller writing the same loop, and getting the early return wrong in a way that reports the last failure instead of the first.
func Float ¶
Float converts a bound value to a float.
The two standard libraries disagree at three edges, and each one is settled the way Rust settles it — a spec that means one thing compiled through the derive and another through this is the failure mode the whole port is written against.
- Go takes digit separators (`1_5`) and hexadecimal floats (`0x1.8p0`); `f64::from_str` takes neither, so they are refused before parsing. Neither `_` nor `x` appears in any float Rust accepts, which is why this is a check on two characters rather than a grammar of its own.
- A number too large to hold is `inf` in Rust and a range error in Go, which hands back the same ±Inf beside it. The value is kept and the error is not.
- A signed NaN — `+nan`, `-NaN` — parses in Rust and not in Go. The sign means nothing on either side.
Everything else agrees: `inf`, `infinity`, a bare `.5` or `5.`, and an underflow to zero.
func Uint ¶
Uint is Int for a value that may not be negative.
A leading `+` is a sign, not a digit, and Rust takes it: `"+8".parse::<u64>()` is 8, while `strconv.ParseUint` refuses the string outright. Refusing `+8` here would have the same spec accept a value in Rust and reject it in Go — and the message would have said it was not a non-negative whole number, about a value that is plainly both.
func (*Error) Error ¶
Error is the message Go's own error interface asks for.
The tokens go through `safe` here as they do in Render: this string reaches a terminal too, by way of whatever logs or prints it, and a rejected argument carrying an escape sequence can recolour that output or forge a line in it. Where the message quotes the spec — a flag's name, an argument's — there is nothing to escape, because the author wrote it and the parse tables hold it.
type Event ¶
type Event struct {
Kind Kind
// Command is set when Kind is KindCommand.
Command *Command
// Flag is set when Kind is KindFlag.
Flag *Flag
// Arg is set when Kind is KindArg.
Arg *Arg
// Value is the bound value. Meaningful for KindArg always, and for KindFlag
// when HasValue is set.
Value string
// HasValue distinguishes a flag that took a value from one that did not, and
// a value-taking flag given the empty string (--jobs=) from a boolean one.
HasValue bool
// Negated is true when a flag was set through its Negate form.
Negated bool
// Delimit says whether a positional value should honor Arg.Delimiter.
Delimit bool
// Values is the remaining argv when Kind is KindExternal: the unmatched name
// first, then every token after it. Shares memory with the argv the parser
// was given.
Values []string
}
Event is something the parser bound.
One struct with a Kind rather than three types, so that an event is returned by value and costs nothing: a Go interface here would box every binding.
Values are strings that share memory with the argv the parser was given. Slicing a Go string does not copy, so a value costs no allocation — and it is the raw bytes the operating system supplied, which on Unix need not be valid UTF-8. Convert where you build the target type, not here.
type Example ¶
type Example struct {
Header string
Code string
// Help introduces the line on the long page, printed above the command
// rather than beside it.
Help string
}
Example is one worked invocation, as a page prints it.
type Files ¶
type Files uint8
Files says whether paths belong at this position as well as the candidates.
const ( // NoFiles means the position takes only what the CLI named. NoFiles Files = iota // AnyFile means files, directories, whatever the shell shows for a path. AnyFile // Dirs means directories only. Dirs // ExecutablePaths means executable files at a filesystem path. ExecutablePaths // Commands means command names from the shell and PATH. Commands )
type Flag ¶
type Flag struct {
// Key is a caller-assigned identifier, echoed back in the event. This is how
// generated code knows which field to assign without any string comparison.
Key uint64
// Name is unused by binding, kept so a table entry can carry its own name for
// diagnostics.
Name string
// Longs are long forms, written without the leading --.
Longs []string
// HiddenLongs are accepted long aliases omitted from help and completion.
// Every entry also appears in Longs so parsing remains table-driven.
HiddenLongs []string
// Shorts are short forms, as single bytes.
//
// Should be ASCII. A cluster like -xyz is walked one byte at a time, so a
// non-ASCII short can never be matched, and the remainder after a value-taking
// one — which becomes its value — would begin in the middle of a character.
Shorts []byte
// HiddenShorts are accepted short aliases omitted from help and completion.
// Every entry also appears in Shorts.
HiddenShorts []byte
// Negate is a long form that sets the flag to false, written without the --.
// Empty means the flag has none.
Negate string
// TakesValue is whether the flag takes a value.
TakesValue bool
// ValueOptional is whether an occurrence may omit that value. A bare flag
// still emits an event, with HasValue false, instead of producing a
// missing-value error.
ValueOptional bool
// BoolValue allows an attached true or false value on a boolean long flag.
// Detached words remain positional and the flag still renders as a switch.
BoolValue bool
// Variadic is whether one occurrence of this flag keeps taking values, until a
// flag-like token or the end of the command line.
//
// This is the spec's variadic flag argument (--include <pattern>...). It is
// not the spec's flag-level var=#true, which means the flag may be repeated
// and takes one value each time — repetition needs nothing from the parser,
// since it already reports every occurrence separately. Conflating the two
// makes a merely repeatable flag greedy enough to eat a positional.
Variadic bool
// VarMax is how many values one variadic occurrence may take, after which the
// next word belongs to whatever comes next. Zero means unbounded.
//
// Only for Variadic. A merely repeatable flag is bounded on how many times it
// was given, which no single token can decide, so that bound stays with the
// metadata and is checked after the parse.
VarMax uint32
// AllowHyphenValues is whether a detached value may itself look like a flag.
//
// The default is to refuse: `--jobs --force` is far more likely a forgotten
// value than a jobs of `"--force"`. Declared, the next token is taken
// whatever it looks like — including `--` — which is clap's
// allow_hyphen_values and the spec's property of the same name. A variadic
// occurrence still stops collecting at a later flag-like token, so a second
// occurrence of the flag is not eaten as a value.
AllowHyphenValues bool
// AllowNegativeNumbers accepts negative numeric tokens as detached values
// without accepting arbitrary dash-prefixed words.
AllowNegativeNumbers bool
// ValueTerminator ends one variadic occurrence without becoming a value.
ValueTerminator string
// Delimiter splits one token into several values. Zero disables splitting.
Delimiter byte
// RequireEquals is whether the value must be attached with `=`.
//
// `--flag=value` is accepted and `--flag value` is not, which is clap's
// require_equals and the spec's property of the same name. A short's
// attached form (`-i9229`, `-i=9229`) still binds: only the following word
// is refused.
RequireEquals bool
// DefaultMissing is the value used when the flag is present but no value is
// given. Empty means unset: the flag then errors if a value is missing.
//
// clap's default_missing_value and the spec's default_missing. `--color`
// binds this, `--color=never` binds `never`, and an absent flag is not bound.
// Combined with RequireEquals, a following word is still refused.
DefaultMissing string
// Global is whether the flag is recognized by every command beneath the one
// that declares it.
Global bool
// Action says whether this flag binds or requests built-in output.
Action ArgAction
}
Flag is a flag, addressed by any of its long or short forms.
type Heading ¶
Heading is prose introducing one help section, printed between the heading and its entries. Keyed by title, because a section is assembled from everything that names it rather than owned by any one entry.
type Help ¶
type Help struct {
// Key matches the entry this describes in the parse tables.
Key uint64
// Hide keeps an entry out of help without keeping it out of the parse. A
// hidden flag still binds; help simply does not invite anyone to type it.
Hide bool
HideDefaultValue bool
HideEnv bool
HideEnvValues bool
HidePossibleValues bool
HideShortHelp bool
HideLongHelp bool
// Demanded is `required` and undefaulted, which is what decides whether the
// usage line angles an entry or brackets it.
//
// Precomputed rather than read from [Meta], so that rendering a page does not
// drag the post-binding table in with it — which would undo the whole reason
// these are separate.
Demanded bool
// Repeatable preserves the spec's `var` on a flag for callers that inspect a
// HelpTable. Help renderers deliberately omit repeatability markers because
// the flag's ordinary spelling is valid for every occurrence.
Repeatable bool
// ValueName is what a flag's value is called. Empty for a flag that takes
// none.
ValueName string
// ValueNames preserves a fixed-arity value's distinct placeholders. It is
// empty for the ordinary single-name case represented by ValueName.
ValueNames []string
// ValueArity is the exact number of values when a fixed-arity argument uses
// one placeholder for every slot. Zero means the arity is not exact.
ValueArity uint32
// ValueDemanded is the same required-and-undefaulted test as [Help.Demanded],
// applied to the flag's *value* rather than to the flag.
//
// The two are independent, and usage-lib writes both: `<--v <n>>` is a
// required flag whose value must be given, and `<--jobs [n]>` is a required
// flag whose value has a default. Angling the value unconditionally — which
// is what usage-argv does — is invisible until a spec has a flag whose value
// is optional or defaulted, and mise has none.
ValueDemanded bool
// Short is the one-line help, and Long the fuller text `--help` prefers.
Short string
Long string
// Deprecated is the migration message, with optional warn/remove milestones.
Deprecated string
DeprecatedWarnAt string
DeprecatedRemoveAt string
// Heading groups an entry into a section of the page. Presentational only.
Heading string
// DisplayOrderSet distinguishes an explicit zero from declaration order.
DisplayOrder uint32
DisplayOrderSet bool
// VisibleAliases are the aliases a command advertises. The parse table merges
// hidden ones in beside these, because binding does not care which is which;
// a page does, and that is the whole of the distinction.
VisibleAliases []string
// Choices, Env and Default are the annotations a page appends to an entry's
// help: `[a, b]`, `[env: X]`, `(default: y)`.
//
// Duplicated from [Meta] rather than read from it, which is the price of
// keeping the two tables separable: a CLI that prints help should not have to
// carry the post-binding table, and one that applies the rules should not have
// to carry the help strings.
Choices []string
Env string
EnvFallback []string
DeprecatedEnv []string
Default []string
// BeforeHelp and AfterHelp bracket this command's page, overriding the
// spec-wide text. The long variants are preferred by `--help`.
BeforeHelp string
AfterHelp string
BeforeLongHelp string
AfterLongHelp string
SubcommandHelpHeading string
SubcommandValueName string
NextLineHelp bool
FlattenHelp bool
SubcommandRequired bool
// Examples are worked invocations, printed last.
Examples []Example
// Headings is prose for the sections this command's entries build, by title.
Headings []Heading
}
Help is what a page needs to say about one command, flag or argument.
type HelpSpec ¶
type HelpSpec struct {
// Name is what the spec calls the program, and Bin what it is invoked as.
// The header prefers Name and falls back to Bin.
Name string
Bin string
// Version is printed beside the name on the root's page, and only when the
// spec declares one — a `--version` that answers with nothing is worse than
// one that is not there.
Version string
// LongVersion is the extended text used for --version; -V uses Version.
LongVersion string
// About is the root's description, which the root's page uses in place of the
// command's own.
About string
// LongAbout is what `--help` prefers over About.
LongAbout string
// Author and License are printed at the end of every long page.
Author string
License string
// BeforeHelp and AfterHelp bracket every page that does not override them,
// and the long variants are what `--help` prefers.
BeforeHelp string
AfterHelp string
BeforeLongHelp string
AfterLongHelp string
// HelpTemplate is how every page in this CLI is laid out, as named sections:
// `{{about}}`, `{{usage}}`, `{{commands}}`, `{{args}}`, `{{flags}}` and
// `{{after_help}}`, which an author may reorder, omit or wrap. Empty means the
// default order, which is what every page in the fleet is compared against.
// Runtime colour tags such as `{$heading}...{/$}` are removed because this
// renderer produces the portable plain page. A doubled dollar sign escapes a
// delimiter: `{$$heading}` is literal `{$heading}` and `{/$$}` is literal `{/$}`.
// See [HelpSections].
HelpTemplate string
}
HelpSpec is what a page needs from the CLI as a whole rather than from one command: the parts of the header that come from the spec's root.
type HelpTable ¶
type HelpTable []Help
HelpTable is the cold help table, indexed by key: entry `Key` sits at `HelpTable[Key-1]`.
type Kind ¶
type Kind uint8
Kind is which of the things an Event reports.
const ( // KindCommand means a subcommand was selected; parsing continues inside it. KindCommand Kind = iota // KindFlag means a flag was given. KindFlag // KindArg means a word was bound to a positional argument. KindArg // KindExternal means an unmatched word was forwarded as an external command: // the name, then every remaining token, including flags. KindExternal )
type Meta ¶
type Meta struct {
// Key matches the [Flag.Key] or [Arg.Key] this describes, so the two tables
// cannot drift apart on identity even though they are separate data.
Key uint64
// Name is what the spec calls it, for the error.
Name string
// Spelling is how a user types it — `--file`, `-f` — for the errors raised
// here, which judge an *entry* and so never see a [Flag].
//
// Carried rather than derived from the name: a name is a long form wherever
// there is one, but `--a` and `-a` are both one character and guessing
// between them can name a different flag entirely. Empty for an argument,
// which is typed as its value rather than as a form.
Spelling string
// ValueName is what a flag's value is called — the `DIR` of `--into <DIR>` —
// and empty where the entry is an argument, which is named by its value
// already. Read by completion rather than by any rule here: what a value is
// called is what says whether a path belongs there.
ValueName string
// CompleteType is the type a spec's `complete` block names for this entry,
// where it names one. Also completion's, and carried for the same reason: an
// author who wrote `complete "input" type="file"` said what the position
// takes, and the alternative is inferring it from a name they did not choose.
CompleteType string
// Flag distinguishes a missing flag from a missing argument, which the
// grammar reports as different classes.
Flag bool
// RequiresIfBoolean says this entry's conditional relationships compare a
// boolean rather than text, so their explicit values need normalization.
RequiresIfBoolean bool
// Required means it must end up with a value, from anywhere.
Required bool
// RejectDuplicate makes a second occurrence of a single-valued flag an
// error. Usage is permissive by default; commands opt into this policy.
RejectDuplicate bool
// Choices is the visible set shown in diagnostics.
Choices []string
// AcceptedChoices also includes hidden values and aliases.
AcceptedChoices []string
IgnoreCase bool
// AllowUnknownChoices keeps Choices presentational rather than restrictive.
AllowUnknownChoices bool
// Default fills in when neither the command line nor the environment did.
Default []string
// Env names an environment variable to fall back to. Empty means none.
Env string
// EnvFallback names additional environment variables in declaration order.
EnvFallback []string
// DeprecatedEnv names deprecated aliases, consulted after ordinary fallbacks.
DeprecatedEnv []string
// VarMin is the fewest values a variadic may end up with. Zero means no
// bound. It is a check rather than a limit, because nothing about a single
// word tells you a variadic will end up short.
VarMin uint32
// VarMax is the most times a repeatable flag may be given. Zero means no
// bound.
//
// Occurrences, not values. A variadic's per-occurrence bound is a limit that
// binding applies, and lives on [Flag.VarMax] and [Arg.VarMax] instead — a
// value bound here would fail an invocation that never broke it.
VarMax uint32
// Validate is a portable expr expression evaluated once for each raw value.
// The environment contains one string variable, `value`.
Validate string
// ValidateError is reported when Validate returns false. Empty uses the
// runtime's generic validation message.
ValidateError string
// Conflicts names entries this one cannot be given alongside.
Conflicts []uint64
// Overrides names entries this one is mutually exclusive with, resolved by
// whichever was given last rather than reported as a mistake.
Overrides []uint64
// RequiredUnless makes this required when none of them is present.
RequiredUnless []uint64
RequiredUnlessAll []uint64
// RequiredIf makes this required when any of them is present.
RequiredIf []uint64
RequiredIfEq []ValueCondition
RequiredIfEqAll []ValueCondition
// Requires names entries that must be satisfied when this one is given.
Requires []uint64
// RequiresIf names entries required when this entry explicitly has Value.
// Defaults do not activate the condition, but may satisfy the requirement.
RequiresIf []ValueRequirement
// DefaultIf binds Value when another entry matches. First match wins.
// Two-argument form (When empty) is presence; When set is equality.
// An applied DefaultIf is a default, not an explicit value.
DefaultIf []DefaultIf
}
Meta is the cold half of a flag or argument's declaration.
Everything binding deliberately does not know. A generated table holds one of these per entry, indexed by Meta.Key — see Metadata — and a program that never applies the rules never touches them.
type Metadata ¶
type Metadata []Meta
Metadata is the cold table, indexed by key.
Keys are dense from 1, so entry `Key` sits at `Metadata[Key-1]` and a lookup is an index rather than a map — which also keeps the table static data the linker can lay out, where a Go map would need building at init.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser reads a command line once, left to right, against static tables.
There is no backtracking, no reordering, and no second pass: what a token binds to is decided when it is read, from the command in scope at that moment. That is what makes the grammar a single loop, and also why a -- or a subcommand word changes the meaning of everything after it and nothing before it.
Use it as a scanner:
p := argv.New(root, os.Args[1:])
for p.Next() {
switch ev := p.Event(); ev.Kind {
case argv.KindCommand:
// ev.Command was selected
case argv.KindFlag:
// ev.Flag was given, with ev.Value if ev.HasValue
case argv.KindArg:
// ev.Value filled ev.Arg
case argv.KindExternal:
// ev.Values is the unmatched name, then the rest of argv
}
}
if err := p.Err(); err != nil {
// binding failed, or help was asked for
}
A Parser holds everything it needs inline, so a parse reaches the allocator zero times — on success and on failure alike. Keep it on the stack (New returns it by value) and Go will not heap-allocate it either.
func (*Parser) Collecting ¶
Collecting reports a variadic flag that is still claiming words, if there is one.
Ask between events, because the answer is gone by the end: the call that finds argv exhausted is the one that clears it. A completion needs it — the next word after `--tools a ⌶` is another tool, not the positional that follows.
func (*Parser) Command ¶
Command reports the command in scope: the root, or the deepest subcommand selected so far.
func (*Parser) CommandStart ¶
CommandStart is where the command in scope began: the index in argv just after its name, or at the unmatched word routed into a default subcommand. argv[CommandStart():] is what that command was given.
func (*Parser) DoubleDashSeen ¶
DoubleDashSeen reports whether a -- was consumed as a separator.
False when flag interpretation stopped for another reason, such as an automatic argument taking a value, and false for a -- that a preserve argument kept as a value.
func (*Parser) Err ¶
Err returns the failure that stopped the parse, or nil.
Help and version requests arrive here too, with Error.Code set to CodeHelp or CodeVersion. They are not failures; they are the other way a parse ends without producing a value, and every caller already handles that shape.
func (*Parser) Event ¶
Event returns what the last Parser.Next bound. Valid only while Next reported true.
func (*Parser) FlagsInScope ¶
FlagsInScope calls fn for every flag a word here could name, in the order the parser itself would look in, so what a completion offers and what the parser accepts cannot disagree — including the shadowing rule. Return true from fn to stop early.
func (*Parser) FlagsStopped ¶
FlagsStopped reports whether flag interpretation has stopped, for any reason.
Wider than Parser.DoubleDashSeen, and the question completion asks: past a separator or past the first value of an automatic argument, a dash-prefixed word is a value, so there is no flag there to offer.
func (*Parser) Next ¶
Next reads the next event, reporting false when argv is exhausted or the parse failed. Check Parser.Err afterwards to tell those two apart.
An error is terminal: the parse stops there, since continuing past a token that could not be understood would only produce bindings derived from a guess. Events already yielded before an error are therefore not a partial result — a caller that assigned them into fields should discard the whole attempt.
func (*Parser) PendingArg ¶
PendingArg is the positional the next word would fill, if there is one left.
A variadic stays here until it reaches its bound, which is what makes it the answer to "what could go where the cursor is" as many times as it can be filled.
func (*Parser) SubcommandsPossible ¶
SubcommandsPossible reports whether a word here could still name a subcommand.
The other half of the rule Parser.FlagsStopped answers for flags: descent stops once a positional of this command has taken a word, so a later word that happens to equal a subcommand name is just a value. A completion that offered one there would be advertising a word the parser no longer accepts as a command.
type Position ¶
type Position struct {
// Cmd is the command in scope: the deepest one the words selected.
Cmd *Command
// Chain is the commands the words passed through, root first, which is what
// [ShortHelp] and the scope rules want.
Chain []*Command
// FlagsPossible is whether a dash-prefixed word here would still be read as a
// flag. False past a `--`, and past the first value of an `automatic`
// argument — there is no flag of *this* CLI to offer in either place.
FlagsPossible bool
// SubcommandsPossible is whether a word here could still name a subcommand.
// False once a positional of this command has taken a word: the parser stops
// descending there, so a later word matching a subcommand name is a value.
SubcommandsPossible bool
// AwaitingValue is a flag whose value the cursor is standing in, because the
// last word was a flag that takes one and has not been given it. Nothing else
// belongs here: the parser refuses a flag-like token in that place.
AwaitingValue *Flag
// Collecting is a variadic flag still claiming words. The next word would be
// another of its values — so the positional after it is not offered — but a
// flag-like token ends the collection and binds, so flags are.
Collecting *Flag
// NextArg is the positional a word here would fill, if any are left.
NextArg *Arg
// NextArgValues is how many values are already bound to NextArg. Non-zero only
// while a variadic positional is still collecting.
NextArgValues uint32
// SeparatorSeen is whether a `--` has been typed. Narrower than
// FlagsPossible, and what an argument requiring a separator is asking about.
SeparatorSeen bool
// HelpTopic is whether the word here names a command to *read about* rather
// than one to run — after `help`, where nothing else belongs.
HelpTopic bool
}
Position is what the cursor is standing in, after the words before it.
func Walk ¶
Walk reads the words before the cursor and reports what the cursor is at.
Errors are not failures here. A line being completed is by definition unfinished — a flag with no value yet, a word that names nothing yet — so a parse error means "the grammar runs out here", which is exactly the position being asked about. The walk stops at the first one and reports the state it reached, where a real parse must discard everything.
type Request ¶
type Request struct {
Shell Shell
// Line is the command line as typed, and Cursor a byte offset into it.
Line string
Cursor int
}
Request is a completion request as a shell sent it.
func ParseRequest ¶
ParseRequest reads a completion request out of argv, and reports whether this was one at all.
`argv` is what the program was given, without its own name — the same slice New takes, so a caller asks this first and parses only if the answer is no.
The flags are read by hand. There are three, and reading them with the parser would mean putting them in the tables this is deliberately outside of. Anything unrecognized is ignored rather than refused: a completion that errors out is a shell that beeps at every keystroke.
type Shell ¶
type Shell uint8
Shell is a completion protocol, named for the shell that reads it.
func ShellNamed ¶
ShellNamed is the shell a `--shell` argument names, and whether it named one.
A completion request comes from a script this package wrote, so the name is one of five — but it arrives as text off a command line, and a shell that sends something else should get an answer rather than a crash.
type Source ¶
type Source uint8
Source says where a value came from, which callers need because the rules distinguish them: an `overrides` loser is not refilled from the environment, and a value that arrived from `env` is still checked against `choices`.
func Fill ¶
Fill applies the fallbacks: command line, then environment, then default.
`given` is what binding produced, and nil means the command line said nothing — which is distinct from a flag given an empty value, since `--jobs=` binds the empty string and that is a value.
`lookupEnv` is passed in rather than read from the process, so that a caller testing a parse is not testing the machine it runs on. LookupEnv wraps os.LookupEnv for callers that do want the process environment.
An environment variable set to the empty string is set. Treating empty as unset would make `EX_JOBS=` mean something no other empty value in the grammar means.
func (Source) Given ¶
Given reports whether a source counts as the flag having been *given*, which is the question the rules comparing two entries ask.
A default does not count, and that is the whole reason this exists. usage-lib and clap both treat `env` as a value source and a default as a fallback: with `--file` defaulted and only `--stdin` typed, a declared conflict between them does not fire. Counting the default would make a defaulted flag conflict with every partner anyone types, which is a CLI nobody can use.
type SplitLine ¶
type SplitLine struct {
// Words are the words, unquoted — what argv would hold had the line been run.
//
// Always at least one: a cursor sitting after a space is completing a word
// that does not exist yet, and an empty word is how that is said. Candidates
// for "anything at all" and candidates for "something starting with `no`" are
// the same question with a different prefix, and a caller should not have to
// special-case the empty one.
Words []string
// Cword is which of Words the cursor is in.
Cword int
// Prefix is the part of that word before the cursor, unquoted — what a
// candidate must start with.
Prefix string
}
SplitLine is a command line as the shell would have passed it, plus where the cursor was.
func Split ¶
Split splits a line at a byte cursor, the way `shell` would have split it.
`cursor` is a byte offset into `line`; anything past the end is treated as the end, and an offset landing inside a multi-byte character is moved back to that character's start rather than being taken literally — a completion request is not a place to be strict about a shell's arithmetic.
func (SplitLine) Argv ¶
Argv is the words a parser should walk: after the program name, before the cursor's word.
Two things dropped for two reasons. The program name, because argv does not contain it and the parse tables describe what comes *after* it. The word being completed, because it is half-typed by definition — feeding it in would ask what can follow a word the user has not finished, when the question is what that word could be.
type UnknownFlags ¶
type UnknownFlags uint8
UnknownFlags is what to do with a flag-like token that names no flag in scope.
The default is UnknownFlagsValue: the token carries on to the positional arguments, because a spec is often parsing a command line whose flags belong to something else — a wrapped tool, a task script. A CLI that owns all of its flags declares UnknownFlagsError and gets typo detection instead.
Stored per command and already resolved: inheritance is a question for whoever builds the tables, and answering it at generation time keeps it out of the parse.
const ( // UnknownFlagsValue offers the token to the positionals. If none can take it, // it is an unexpected argument. UnknownFlagsValue UnknownFlags = iota // UnknownFlagsError rejects the token. UnknownFlagsError )
type ValueCondition ¶
type ValueRequirement ¶
ValueRequirement is one value-conditional relationship.