xflag

A drop-in replacement for flag.Parse that accepts flags anywhere in the argument list. Used internally by cli to drive its parser, and usable on its own with a stdlib *flag.FlagSet.

import "github.com/pressly/cli/xflag"

At a glance

One function. The link goes to godoc for the canonical reference.

FUNCTIONS
    func ParseToEnd(f *flag.FlagSet, arguments []string) error

Usage

Define flags on a stdlib *flag.FlagSet, then call xflag.ParseToEnd instead of f.Parse:

f := flag.NewFlagSet("greet", flag.ContinueOnError)
verbose := f.Bool("verbose", false, "enable verbose output")
name    := f.String("name", "world", "who to greet")

if err := xflag.ParseToEnd(f, os.Args[1:]); err != nil {
    log.Fatal(err)
}

fmt.Println(*verbose, *name, f.Args())

All three of these invocations parse the same way:

greet --verbose --name=alice arg1 arg2
greet arg1 --verbose arg2 --name=alice
greet arg1 arg2 --verbose --name=alice

Stdlib's flag.Parse would stop at arg1 in the second and third forms, treating --verbose and --name as positional arguments.


Why this exists

Go's flag package stops parsing at the first non-flag argument. That behavior is well-known (see #4513 and #63138) and unlikely to change. Most CLI users today expect Docker- and Git-style behavior where flags can appear anywhere. xflag.ParseToEnd bridges that gap without giving up the standard library's flag.FlagSet.