github.com/jmigpin/editor@v1.6.0/util/flagutil/flagset.go (about)

     1  package flagutil
     2  
     3  import (
     4  	"flag"
     5  	"strings"
     6  )
     7  
     8  // usefull to allow unknown flags to be collected, to possibly pass them to another program. The main issue is knowning which unknown flags are boolean that won't receive a value after space (ex: -mybool main.go, main.go is not an arg to mybool). In this case, the provided map allows to correct this without having to define the flags in the flagset.
     9  func ParseFlagSetSets(fs *flag.FlagSet, args []string, isBool map[string]bool) (unknownArgs, unnamedArgs, binaryArgs []string, _ error) {
    10  	// fs.parse stops parsing at the first non-flag
    11  
    12  	// ex: "-flag1=1 -flag2=2 main.go -arg1 -arg2"
    13  	// 	- flags are parsed until "main.go"
    14  	// 	- unknown flags go to the unknownArgs
    15  	// 	- "main.go" goes to the fl.unnamedArgs
    16  	// 	- "-arg1" "-arg2" goes to the fl.binaryArgs
    17  
    18  	// don't output help on error (will try to recover)
    19  	usageFn := fs.Usage
    20  	fs.Usage = func() {}
    21  	defer func() { fs.Usage = usageFn }()
    22  
    23  	for {
    24  		err := fs.Parse(args)
    25  		if err == nil {
    26  			break
    27  		}
    28  		if err == flag.ErrHelp {
    29  			return nil, nil, nil, err
    30  		}
    31  
    32  		// get failing arg (consumed by fs.parse, need to get from end)
    33  		k := len(args) - 1 - len(fs.Args())
    34  		arg := args[k]
    35  		unknownArgs = append(unknownArgs, arg)
    36  		args = args[k+1:]
    37  
    38  		// if not a boolean arg, it consumes the next arg
    39  		name := strings.TrimLeft(arg, "-")
    40  		if isBool != nil && !isBool[name] {
    41  			haveVal := strings.Index(arg, "=") >= 1
    42  			if !haveVal && len(args) > 0 {
    43  				arg2 := args[0]
    44  				args = args[1:]
    45  				unknownArgs = append(unknownArgs, arg2)
    46  			}
    47  		}
    48  	}
    49  
    50  	// split unnamed from named afterwards
    51  	args2 := fs.Args()
    52  	split1, split2 := len(args2), len(args2)
    53  	for i, a := range args2 {
    54  		if a[0] == '-' {
    55  			split1, split2 = i, i
    56  
    57  			// special double dash case (exclude arg)
    58  			if a == "--" {
    59  				split2 = i + 1
    60  			}
    61  
    62  			break
    63  		}
    64  	}
    65  	unnamedArgs, binaryArgs = args2[:split1], args2[split2:]
    66  
    67  	return
    68  }