github.com/wtrep/tgf@v1.18.8/arguments.go (about)

     1  package main
     2  
     3  import (
     4  	"strings"
     5  
     6  	"gopkg.in/alecthomas/kingpin.v2"
     7  )
     8  
     9  // ApplicationArguments allows proper management between managed and non managed arguments provided to kingpin
    10  type ApplicationArguments struct {
    11  	*kingpin.Application
    12  	longs  map[string]bool
    13  	shorts map[rune]bool
    14  }
    15  
    16  func (app ApplicationArguments) add(name, description string, isSwitch bool, shorts ...rune) *kingpin.FlagClause {
    17  	flag := app.Application.Flag(name, description)
    18  	switch len(shorts) {
    19  	case 0:
    20  		break
    21  	case 1:
    22  		flag = flag.Short(shorts[0])
    23  		app.shorts[shorts[0]] = isSwitch
    24  	default:
    25  		panic("Maximum one short option should be specified")
    26  	}
    27  
    28  	app.longs[name] = isSwitch
    29  	return flag
    30  }
    31  
    32  // Switch adds a switch argument to the application
    33  // A switch is a boolean flag that do not require additional value
    34  func (app ApplicationArguments) Switch(name, description string, shorts ...rune) *kingpin.FlagClause {
    35  	return app.add(name, description, true, shorts...)
    36  }
    37  
    38  // Argument adds an argument to the application
    39  // The argument requires additional argument to be complete
    40  func (app ApplicationArguments) Argument(name, description string, shorts ...rune) *kingpin.FlagClause {
    41  	return app.add(name, description, false, shorts...)
    42  }
    43  
    44  // SplitManaged splits the managed by kingpin and unmanaged argument to avoid error
    45  func (app ApplicationArguments) SplitManaged(args []string) (managed []string, unmanaged []string) {
    46  Arg:
    47  	for i := 1; i < len(args); i++ {
    48  		arg := args[i]
    49  		if arg == "--" {
    50  			unmanaged = append(unmanaged, args[i+1:]...)
    51  			break
    52  		}
    53  		if strings.HasPrefix(arg, "--") {
    54  			argSplit := strings.Split(args[i][2:], "=")
    55  			if isSwitch, ok := app.longs[argSplit[0]]; ok {
    56  				managed = append(managed, arg)
    57  				if !isSwitch && len(argSplit) == 1 {
    58  					// This is not a switch (bool flag) and there is no argument with
    59  					// the flag, so the argument must be after and we add it to
    60  					// the managed args if there is.
    61  					i++
    62  					if i < len(args) {
    63  						managed = append(managed, args[i])
    64  					}
    65  				}
    66  			} else {
    67  				unmanaged = append(unmanaged, arg)
    68  			}
    69  		} else if strings.HasPrefix(arg, "-") {
    70  			withArg := false
    71  			for pos, opt := range arg[1:] {
    72  				if isSwitch, ok := app.shorts[opt]; ok {
    73  					if !isSwitch {
    74  						// This is not a switch (bool flag), so we check if there are characters
    75  						// following the current flag in the same word. If it is not the case,
    76  						// then the argument must be after and we add it to the managed args
    77  						// if there is. If it is the case, then, the argument is included in
    78  						// the current flag and we consider the whole word as a managed argument.
    79  						withArg = pos == len(arg[1:])-1
    80  						break
    81  					}
    82  				} else {
    83  					unmanaged = append(unmanaged, arg)
    84  					continue Arg
    85  				}
    86  			}
    87  			managed = append(managed, arg)
    88  			if withArg {
    89  				// The next argument must be an argument to the current flag
    90  				i++
    91  				if i < len(args) {
    92  					managed = append(managed, args[i])
    93  				}
    94  			}
    95  		} else {
    96  			unmanaged = append(unmanaged, arg)
    97  		}
    98  	}
    99  	return
   100  }
   101  
   102  // NewApplication returns an initialized copy of ApplicationArguments
   103  func NewApplication(app *kingpin.Application) ApplicationArguments {
   104  	return ApplicationArguments{
   105  		Application: app,
   106  		longs: map[string]bool{
   107  			"help-man":               true,
   108  			"help-long":              true,
   109  			"completion-bash":        true,
   110  			"completion-script-bash": true,
   111  			"completion-script-zsh":  true,
   112  		},
   113  		shorts: map[rune]bool{},
   114  	}
   115  }