Merge pull request #661 from rliebz/custom-flag-help
Allow customization of prefixes and environment variable hints in flag help strings
This commit is contained in:
commit
ac249472b7
20
flag.go
20
flag.go
@ -37,6 +37,14 @@ var HelpFlag Flag = BoolFlag{
|
|||||||
// to display a flag.
|
// to display a flag.
|
||||||
var FlagStringer FlagStringFunc = stringifyFlag
|
var FlagStringer FlagStringFunc = stringifyFlag
|
||||||
|
|
||||||
|
// FlagNamePrefixer converts a full flag name and its placeholder into the help
|
||||||
|
// message flag prefix. This is used by the default FlagStringer.
|
||||||
|
var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames
|
||||||
|
|
||||||
|
// FlagEnvHinter annotates flag help message with the environment variable
|
||||||
|
// details. This is used by the default FlagStringer.
|
||||||
|
var FlagEnvHinter FlagEnvHintFunc = withEnvHint
|
||||||
|
|
||||||
// FlagsByName is a slice of Flag.
|
// FlagsByName is a slice of Flag.
|
||||||
type FlagsByName []Flag
|
type FlagsByName []Flag
|
||||||
|
|
||||||
@ -710,13 +718,13 @@ func stringifyFlag(f Flag) string {
|
|||||||
|
|
||||||
switch f.(type) {
|
switch f.(type) {
|
||||||
case IntSliceFlag:
|
case IntSliceFlag:
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return FlagEnvHinter(fv.FieldByName("EnvVar").String(),
|
||||||
stringifyIntSliceFlag(f.(IntSliceFlag)))
|
stringifyIntSliceFlag(f.(IntSliceFlag)))
|
||||||
case Int64SliceFlag:
|
case Int64SliceFlag:
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return FlagEnvHinter(fv.FieldByName("EnvVar").String(),
|
||||||
stringifyInt64SliceFlag(f.(Int64SliceFlag)))
|
stringifyInt64SliceFlag(f.(Int64SliceFlag)))
|
||||||
case StringSliceFlag:
|
case StringSliceFlag:
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return FlagEnvHinter(fv.FieldByName("EnvVar").String(),
|
||||||
stringifyStringSliceFlag(f.(StringSliceFlag)))
|
stringifyStringSliceFlag(f.(StringSliceFlag)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -744,8 +752,8 @@ func stringifyFlag(f Flag) string {
|
|||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
||||||
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return FlagEnvHinter(fv.FieldByName("EnvVar").String(),
|
||||||
fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
|
fmt.Sprintf("%s\t%s", FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
||||||
@ -795,5 +803,5 @@ func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
||||||
return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
|
return fmt.Sprintf("%s\t%s", FlagNamePrefixer(name, placeholder), usageWithDefault)
|
||||||
}
|
}
|
||||||
|
77
flag_test.go
77
flag_test.go
@ -158,6 +158,83 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var prefixStringFlagTests = []struct {
|
||||||
|
name string
|
||||||
|
usage string
|
||||||
|
value string
|
||||||
|
prefixer FlagNamePrefixFunc
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"foo", "", "", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: foo, ph: value\t"},
|
||||||
|
{"f", "", "", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: f, ph: value\t"},
|
||||||
|
{"f", "The total `foo` desired", "all", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: f, ph: foo\tThe total foo desired (default: \"all\")"},
|
||||||
|
{"test", "", "Something", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: test, ph: value\t(default: \"Something\")"},
|
||||||
|
{"config,c", "Load configuration from `FILE`", "", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: config,c, ph: FILE\tLoad configuration from FILE"},
|
||||||
|
{"config,c", "Load configuration from `CONFIG`", "config.json", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("name: %s, ph: %s", a, b)
|
||||||
|
}, "name: config,c, ph: CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlagNamePrefixer(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
FlagNamePrefixer = prefixedNames
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, test := range prefixStringFlagTests {
|
||||||
|
FlagNamePrefixer = test.prefixer
|
||||||
|
flag := StringFlag{Name: test.name, Usage: test.usage, Value: test.value}
|
||||||
|
output := flag.String()
|
||||||
|
if output != test.expected {
|
||||||
|
t.Errorf("%q does not match %q", output, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var envHintFlagTests = []struct {
|
||||||
|
name string
|
||||||
|
env string
|
||||||
|
hinter FlagEnvHintFunc
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"foo", "", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("env: %s, str: %s", a, b)
|
||||||
|
}, "env: , str: --foo value\t"},
|
||||||
|
{"f", "", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("env: %s, str: %s", a, b)
|
||||||
|
}, "env: , str: -f value\t"},
|
||||||
|
{"foo", "ENV_VAR", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("env: %s, str: %s", a, b)
|
||||||
|
}, "env: ENV_VAR, str: --foo value\t"},
|
||||||
|
{"f", "ENV_VAR", func(a, b string) string {
|
||||||
|
return fmt.Sprintf("env: %s, str: %s", a, b)
|
||||||
|
}, "env: ENV_VAR, str: -f value\t"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlagEnvHinter(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
FlagEnvHinter = withEnvHint
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, test := range envHintFlagTests {
|
||||||
|
FlagEnvHinter = test.hinter
|
||||||
|
flag := StringFlag{Name: test.name, EnvVar: test.env}
|
||||||
|
output := flag.String()
|
||||||
|
if output != test.expected {
|
||||||
|
t.Errorf("%q does not match %q", output, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var stringSliceFlagTests = []struct {
|
var stringSliceFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
value *StringSlice
|
value *StringSlice
|
||||||
|
8
funcs.go
8
funcs.go
@ -26,3 +26,11 @@ type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
|
|||||||
// FlagStringFunc is used by the help generation to display a flag, which is
|
// FlagStringFunc is used by the help generation to display a flag, which is
|
||||||
// expected to be a single line.
|
// expected to be a single line.
|
||||||
type FlagStringFunc func(Flag) string
|
type FlagStringFunc func(Flag) string
|
||||||
|
|
||||||
|
// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix
|
||||||
|
// text for a flag's full name.
|
||||||
|
type FlagNamePrefixFunc func(fullName, placeholder string) string
|
||||||
|
|
||||||
|
// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help
|
||||||
|
// with the environment variable details.
|
||||||
|
type FlagEnvHintFunc func(envVar, str string) string
|
||||||
|
Loading…
Reference in New Issue
Block a user