urfave-cli/flag.go
Yicheng Qin 5903a0a844 Add BoolTFlag type
Compared to BoolFlag type, BoolTFlag treats 'true' as the default value
for the flag.

Without it, we have to use --no-action flag if we set the action is done
in default. But sometimes it is bad to maintain flags with negative meanings.
And it will be painful if we change the default value for the flag.

As this implementation, it keeps all existing functionality. So it
is compatible with old versions.
2014-03-05 17:24:22 -08:00

234 lines
4.2 KiB
Go

package cli
import (
"flag"
"fmt"
"strconv"
"strings"
)
// Flag is a common interface related to parsing flags in cli.
// For more advanced flag parsing techniques, it is recomended that
// this interface be implemented.
type Flag interface {
fmt.Stringer
// Apply Flag settings to the given flag set
Apply(*flag.FlagSet)
getName() string
}
func flagSet(name string, flags []Flag) *flag.FlagSet {
set := flag.NewFlagSet(name, flag.ContinueOnError)
for _, f := range flags {
f.Apply(set)
}
return set
}
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
type StringSlice []string
func (f *StringSlice) Set(value string) error {
*f = append(*f, value)
return nil
}
func (f *StringSlice) String() string {
return fmt.Sprintf("%s", *f)
}
func (f *StringSlice) Value() []string {
return *f
}
type StringSliceFlag struct {
Name string
Value *StringSlice
Usage string
}
func (f StringSliceFlag) String() string {
return fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage)
}
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f StringSliceFlag) getName() string {
return f.Name
}
type IntSlice []int
func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value)
if err != nil {
return err
} else {
*f = append(*f, tmp)
}
return nil
}
func (f *IntSlice) String() string {
return fmt.Sprintf("%d", *f)
}
func (f *IntSlice) Value() []int {
return *f
}
type IntSliceFlag struct {
Name string
Value *IntSlice
Usage string
}
func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)
}
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Var(f.Value, name, f.Usage)
})
}
func (f IntSliceFlag) getName() string {
return f.Name
}
type BoolFlag struct {
Name string
Usage string
}
func (f BoolFlag) String() string {
return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)
}
func (f BoolFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Bool(name, false, f.Usage)
})
}
func (f BoolFlag) getName() string {
return f.Name
}
type BoolTFlag struct {
Name string
Usage string
}
func (f BoolTFlag) String() string {
return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)
}
func (f BoolTFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Bool(name, true, f.Usage)
})
}
func (f BoolTFlag) getName() string {
return f.Name
}
type StringFlag struct {
Name string
Value string
Usage string
}
func (f StringFlag) String() string {
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
}
func (f StringFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.String(name, f.Value, f.Usage)
})
}
func (f StringFlag) getName() string {
return f.Name
}
type IntFlag struct {
Name string
Value int
Usage string
}
func (f IntFlag) String() string {
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
}
func (f IntFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Int(name, f.Value, f.Usage)
})
}
func (f IntFlag) getName() string {
return f.Name
}
type Float64Flag struct {
Name string
Value float64
Usage string
}
func (f Float64Flag) String() string {
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
}
func (f Float64Flag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Float64(name, f.Value, f.Usage)
})
}
func (f Float64Flag) getName() string {
return f.Name
}
func prefixFor(name string) (prefix string) {
if len(name) == 1 {
prefix = "-"
} else {
prefix = "--"
}
return
}
func prefixedNames(fullName string) (prefixed string) {
parts := strings.Split(fullName, ",")
for i, name := range parts {
name = strings.Trim(name, " ")
prefixed += prefixFor(name) + name
if i < len(parts)-1 {
prefixed += ", "
}
}
return
}