diff --git a/README.md b/README.md index 2f0980e..f72b7cc 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ applications in an expressive way. + [Alternate Names](#alternate-names) + [Values from the Environment](#values-from-the-environment) + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) + + [Default Values for help output](#default-values-for-help-output) * [Subcommands](#subcommands) * [Subcommands categories](#subcommands-categories) * [Exit code](#exit-code) @@ -589,6 +590,48 @@ func main() { } ``` +#### Default Values for help output + +Sometimes it's useful to specify a flag's default help-text value within the flag declaration. This can be useful if the default value for a flag is a computed value. The default value can be set via the `DefaultText` struct field. + +For example this: + + +```go +package main + +import ( + "os" + + "gopkg.in/urfave/cli.v2" +) + +func main() { + app := &cli.App{ + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "port", + Usage: "Use a randomized port", + Value: 0, + DefaultText: "random", + }, + }, + } + + app.Run(os.Args) +} +``` + +Will result in help output like: + +``` +--port value Use a randomized port (default: random) +``` + + ### Subcommands Subcommands can be defined for a more git-like command line app. diff --git a/flag.go b/flag.go index 807c95f..10adca8 100644 --- a/flag.go +++ b/flag.go @@ -730,7 +730,6 @@ func stringifyFlag(f Flag) string { needsPlaceholder := false defaultValueString := "" val := fv.FieldByName("Value") - if val.IsValid() { needsPlaceholder = val.Kind() != reflect.Bool defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) @@ -740,6 +739,12 @@ func stringifyFlag(f Flag) string { } } + helpText := fv.FieldByName("DefaultText") + if helpText.IsValid() && helpText.String() != "" { + needsPlaceholder = val.Kind() != reflect.Bool + defaultValueString = fmt.Sprintf(" (default: %s)", helpText.String()) + } + if defaultValueString == " (default: )" { defaultValueString = "" } diff --git a/flag_generated.go b/flag_generated.go index e224fb8..1f48d9f 100644 --- a/flag_generated.go +++ b/flag_generated.go @@ -16,6 +16,7 @@ type BoolFlag struct { EnvVars []string Hidden bool Value bool + DefaultText string Destination *bool } @@ -59,6 +60,7 @@ type DurationFlag struct { EnvVars []string Hidden bool Value time.Duration + DefaultText string Destination *time.Duration } @@ -102,6 +104,7 @@ type Float64Flag struct { EnvVars []string Hidden bool Value float64 + DefaultText string Destination *float64 } @@ -139,12 +142,13 @@ func lookupFloat64(name string, set *flag.FlagSet) float64 { // GenericFlag is a flag with type Generic type GenericFlag struct { - Name string - Aliases []string - Usage string - EnvVars []string - Hidden bool - Value Generic + Name string + Aliases []string + Usage string + EnvVars []string + Hidden bool + Value Generic + DefaultText string } // String returns a readable representation of this value @@ -187,6 +191,7 @@ type Int64Flag struct { EnvVars []string Hidden bool Value int64 + DefaultText string Destination *int64 } @@ -230,6 +235,7 @@ type IntFlag struct { EnvVars []string Hidden bool Value int + DefaultText string Destination *int } @@ -267,12 +273,13 @@ func lookupInt(name string, set *flag.FlagSet) int { // IntSliceFlag is a flag with type *IntSlice type IntSliceFlag struct { - Name string - Aliases []string - Usage string - EnvVars []string - Hidden bool - Value *IntSlice + Name string + Aliases []string + Usage string + EnvVars []string + Hidden bool + Value *IntSlice + DefaultText string } // String returns a readable representation of this value @@ -309,12 +316,13 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int { // Int64SliceFlag is a flag with type *Int64Slice type Int64SliceFlag struct { - Name string - Aliases []string - Usage string - EnvVars []string - Hidden bool - Value *Int64Slice + Name string + Aliases []string + Usage string + EnvVars []string + Hidden bool + Value *Int64Slice + DefaultText string } // String returns a readable representation of this value @@ -351,12 +359,13 @@ func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { // Float64SliceFlag is a flag with type *Float64Slice type Float64SliceFlag struct { - Name string - Aliases []string - Usage string - EnvVars []string - Hidden bool - Value *Float64Slice + Name string + Aliases []string + Usage string + EnvVars []string + Hidden bool + Value *Float64Slice + DefaultText string } // String returns a readable representation of this value @@ -399,6 +408,7 @@ type StringFlag struct { EnvVars []string Hidden bool Value string + DefaultText string Destination *string } @@ -436,12 +446,13 @@ func lookupString(name string, set *flag.FlagSet) string { // StringSliceFlag is a flag with type *StringSlice type StringSliceFlag struct { - Name string - Aliases []string - Usage string - EnvVars []string - Hidden bool - Value *StringSlice + Name string + Aliases []string + Usage string + EnvVars []string + Hidden bool + Value *StringSlice + DefaultText string } // String returns a readable representation of this value @@ -484,6 +495,7 @@ type Uint64Flag struct { EnvVars []string Hidden bool Value uint64 + DefaultText string Destination *uint64 } @@ -527,6 +539,7 @@ type UintFlag struct { EnvVars []string Hidden bool Value uint + DefaultText string Destination *uint } diff --git a/flag_test.go b/flag_test.go index e8c8bcd..ccb1d45 100644 --- a/flag_test.go +++ b/flag_test.go @@ -67,6 +67,16 @@ func TestStringFlagHelpOutput(t *testing.T) { } } +func TestStringFlagDefaultText(t *testing.T) { + flag := &StringFlag{Name: "foo", Aliases: nil, Usage: "amount of `foo` requested", Value: "none", DefaultText: "all of it"} + expected := "--foo foo\tamount of foo requested (default: all of it)" + output := flag.String() + + if output != expected { + t.Errorf("%q does not match %q", output, expected) + } +} + func TestStringFlagWithEnvVarHelpOutput(t *testing.T) { os.Clearenv() os.Setenv("APP_FOO", "derp") @@ -482,7 +492,6 @@ func TestFloat64FlagApply_SetsAllNames(t *testing.T) { expect(t, v, float64(43.33333)) } - var float64SliceFlagTests = []struct { name string aliases []string @@ -523,8 +532,6 @@ func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) { } } - - var genericFlagTests = []struct { name string value Generic @@ -1100,7 +1107,6 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) { a.Run([]string{"run"}) } - func TestParseMultiFloat64SliceFromEnv(t *testing.T) { os.Clearenv() os.Setenv("APP_INTERVALS", "0.1,-10.5") @@ -1141,7 +1147,6 @@ func TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) { }).Run([]string{"run"}) } - func TestParseMultiBool(t *testing.T) { a := App{ Flags: []Flag{ diff --git a/generate-flag-types b/generate-flag-types index aa51154..3213dd0 100755 --- a/generate-flag-types +++ b/generate-flag-types @@ -145,6 +145,7 @@ def _write_cli_flag_types(outfile, types): EnvVars []string Hidden bool Value {type} + DefaultText string """.format(**typedef)) if typedef['dest']: