Documentation
¶
Overview ¶
Package flagparser bridges between pflag and the GNU-getopt wording that rshell builtins are expected to match.
pflag is a fine option-parsing library but its error wording diverges from GNU coreutils on every common failure mode (unknown flag, missing argument, no-arg flag given a value, etc.), and it has no notion of GNU's left-to-right `--help` short-circuit. Two helpers fix that without touching pflag itself:
RewriteError translates pflag's error messages to GNU's getopt-style wording, optionally consulting the original argv to recover information pflag strips (e.g. the `=value` suffix on an unknown long flag).
TrialHelpTrimIndex decides whether the suffix after a `--help` token can be safely discarded so the builtin's handler can short-circuit. It trial-parses the prefix on a throw-away FlagSet; if every preceding option parses cleanly the suffix is dropped, otherwise the caller leaves the args alone and the real parse surfaces the earlier error — matching GNU's leftmost-bad- option rule.
Keeping this code in a dedicated package isolates the parser-shim concern from builtin registration. If we ever replace pflag with a hand-written GNU-getopt parser, the swap is local to this package.
Index ¶
Constants ¶
const NoArgSentinel = "\x00"
NoArgSentinel is the NoOptDefVal pflag passes to a no-argument flag's Set method when the user writes the bare flag (`-h`, `--all`); for the explicit-value form (`--all=true`) pflag passes the user's literal value instead.
We use a single NUL byte so the two cases are distinguishable: NUL is the C-string terminator and POSIX execve(2) refuses to pass argv elements containing it, so the user cannot forge this string from a shell. That lets Set reject every `=value` form — including `=true` — to match GNU getopt's "doesn't allow an argument" exit-1 error.
Variables ¶
This section is empty.
Functions ¶
func RegisterNoArgBool ¶ added in v0.0.24
RegisterNoArgBool installs a no-argument boolean flag on fs and returns the *bool target so the caller can read it like an ordinary fs.Bool result. Pass an empty shorthand for long-only flags (e.g. --total).
Unlike fs.BoolP, an explicit value (`--flag=true`, `--flag=false`, `-f=x`) is rejected with GNU's "doesn't allow an argument" wording (via RewriteError) instead of silently parsing — matching GNU getopt's no_argument semantics for flags where accepting a stray value would be surprising or unsafe (e.g. rm's --help/--verbose).
func RewriteError ¶
RewriteError translates pflag's default error messages to the GNU-getopt-style wording that matches GNU coreutils byte-for-byte. It returns the rewritten message without a trailing newline or any "cmd:" prefix; callers prepend the builtin name themselves.
args is the argv that was handed to fs.Parse. It is consulted only for the unknown-long-flag case, where pflag strips the `=value` suffix from its error string but GNU getopt reports the full token (`--no-such=value`, not just `--no-such`).
Patterns covered:
pflag → GNU
"unknown flag: --foo" → "unrecognized option '--foo'"
("--foo=value" if the original argv used =value)
"unknown shorthand flag: 'X' in -..." → "invalid option -- 'X'"
"flag needs an argument: --foo" → "option '--foo' requires an argument"
"flag needs an argument: 'X' in -Y" → "option requires an argument -- 'X'"
`invalid argument "..." for "DESC" flag: → "option '--LONG' doesn't allow
flag does not allow an argument` an argument"
Unknown messages are returned unchanged.
func TrialHelpTrimIndex ¶
TrialHelpTrimIndex returns the index of the first `--help` in args if trial-parsing the prefix [0..helpIdx] with a fresh FlagSet (1) succeeds and (2) actually sets the `help` flag. The second check matters because pflag can consume the `--help` token in ways that don't set the flag:
- As the value of a preceding value-taker. `grep -e --help` makes `--help` the pattern for -e, not a help request; the trial parse accepts it but `Lookup("help").Changed` stays false.
- As a positional, for FlagSets that called `SetInterspersed(false)` (xargs, tr, read). Anything after the first positional is left for the builtin's handler — `--help` included.
If the trial both parses and sets `help`, the suffix after `--help` is safely discardable and the builtin's handler can short-circuit — matching GNU coreutils' left-to-right semantics. Otherwise we return (0, false) so the real fs.Parse reports any later error and the handler sees the full argv.
registerFlags is invoked on a throw-away FlagSet to set up the trial; it must be safe to call multiple times. Every builtin's MakeFlags is pure flag-registration today, so this is fine.
Types ¶
This section is empty.