Call FlagStringer in String() method of slice flags

The default help template relies on the String() method of Flag
to render the flag. For most flag types, String() indirects through
FlagStringer, so that is the best place to customize flag rendering.

FlagStringer was not called for slice flags because their help output
differs from other flags in two ways: there can be multiple default
values, and the flag name is shown two times to indicate that the flag
can be specified multiple times.

To make multiple values work in the FlagStringer, I simply changed
GetValue() to return all values.

Showing the flag more than once is achieved through a new interface,
DocGenerationSliceFlag, which the FlagStringer uses to decide whether
the flag is a slice flag type.
This commit is contained in:
Felix Lange
2022-09-30 15:01:22 +02:00
committed by Dan Buch
parent 4959a9fa9b
commit 82ea9f70c0
8 changed files with 97 additions and 119 deletions

29
flag.go
View File

@@ -126,6 +126,14 @@ type Flag interface {
RunAction(*Context) error
}
// DocGenerationSliceFlag extends DocGenerationFlag for slice-based flags.
type DocGenerationSliceFlag interface {
DocGenerationFlag
// IsSliceFlag returns true for flags that can be given multiple times.
IsSliceFlag() bool
}
// Countable is an interface to enable detection of flag values which support
// repetitive flags
type Countable interface {
@@ -300,24 +308,13 @@ func stringifyFlag(f Flag) string {
usageWithDefault := strings.TrimSpace(usage + defaultValueString)
return withEnvHint(f.GetEnvVars(),
fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault))
}
func stringifySliceFlag(usage string, names, defaultVals []string) string {
placeholder, usage := unquoteUsage(usage)
if placeholder == "" {
placeholder = defaultPlaceholder
pn := prefixedNames(df.Names(), placeholder)
sliceFlag, ok := f.(DocGenerationSliceFlag)
if ok && sliceFlag.IsSliceFlag() {
pn = pn + " [ " + pn + " ]"
}
defaultVal := ""
if len(defaultVals) > 0 {
defaultVal = fmt.Sprintf(formatDefault("%s"), strings.Join(defaultVals, ", "))
}
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
pn := prefixedNames(names, placeholder)
return fmt.Sprintf("%s [ %s ]\t%s", pn, pn, usageWithDefault)
return withEnvHint(df.GetEnvVars(), fmt.Sprintf("%s\t%s", pn, usageWithDefault))
}
func hasFlag(flags []Flag, fl Flag) bool {