From 0cb6639c5824bbddb24e458e73a5a4e36ceefb23 Mon Sep 17 00:00:00 2001 From: jokemanfire Date: Thu, 9 Jan 2025 17:13:35 +0800 Subject: [PATCH 1/3] while print flag , the placeholder if need but not set. print flag type first. Signed-off-by: jokemanfire --- examples_test.go | 2 +- flag.go | 14 +++- flag_impl.go | 15 +++++ flag_test.go | 146 ++++++++++++++++++++-------------------- godoc-current.txt | 8 +++ help_test.go | 20 +++--- testdata/godoc-v3.x.txt | 8 +++ 7 files changed, 127 insertions(+), 86 deletions(-) diff --git a/examples_test.go b/examples_test.go index 500ecfe6c6..44db0478cb 100644 --- a/examples_test.go +++ b/examples_test.go @@ -143,7 +143,7 @@ func ExampleCommand_Run_appHelp() { // help, h Shows a list of commands or help for one command // // GLOBAL OPTIONS: - // --name value a name to say (default: "bob") + // --name string a name to say (default: "bob") // --help, -h show help // --version, -v print the version } diff --git a/flag.go b/flag.go index 20d47c1e66..c3a96b3018 100644 --- a/flag.go +++ b/flag.go @@ -180,6 +180,11 @@ type LocalFlag interface { IsLocal() bool } +// FlagType is an interface to detect if a flag is a string, bool, etc. +type FlagType interface { + GetFlagType() string +} + func newFlagSet(name string, flags []Flag) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) @@ -304,9 +309,14 @@ func stringifyFlag(f Flag) string { } placeholder, usage := unquoteUsage(df.GetUsage()) needsPlaceholder := df.TakesValue() - + // if needsPlaceholder is true, placeholder is empty if needsPlaceholder && placeholder == "" { - placeholder = defaultPlaceholder + // try to get type from flag + if v1, ok := f.(FlagType); ok && v1.GetFlagType() != "" { + placeholder = v1.GetFlagType() + } else { + placeholder = defaultPlaceholder + } } defaultValueString := "" diff --git a/flag_impl.go b/flag_impl.go index 3b3780d269..2cbb7b23cd 100644 --- a/flag_impl.go +++ b/flag_impl.go @@ -98,6 +98,21 @@ func (f *FlagBase[T, C, V]) GetValue() string { return fmt.Sprintf("%v", f.Value) } +// GetFlagType returns the type of the flag. +func (f *FlagBase[T, C, V]) GetFlagType() string { + ty := reflect.TypeOf(f.Value) + if ty == nil { + return "" + } + // if it is a Slice, then return the slice type. Will nested slices be used in the future? + if ty.Kind() == reflect.Slice { + elemType := ty.Elem() + return "[]" + elemType.Name() + } + // TODO. Hashmap is a bit difficult to judge, it will be fixed in the future + return ty.Name() +} + // Apply populates the flag given the flag set and environment func (f *FlagBase[T, C, V]) Apply(set *flag.FlagSet) error { tracef("apply (flag=%[1]q)", f.Name) diff --git a/flag_test.go b/flag_test.go index 801c36a406..f77c21cc78 100644 --- a/flag_test.go +++ b/flag_test.go @@ -439,32 +439,32 @@ func TestFlagStringifying(t *testing.T) { { name: "duration-flag", fl: &DurationFlag{Name: "scream-for"}, - expected: "--scream-for value\t(default: 0s)", + expected: "--scream-for Duration\t(default: 0s)", }, { name: "duration-flag-with-default-text", fl: &DurationFlag{Name: "feels-about", DefaultText: "whimsically"}, - expected: "--feels-about value\t(default: whimsically)", + expected: "--feels-about Duration\t(default: whimsically)", }, { name: "float64-flag", fl: &FloatFlag{Name: "arduous"}, - expected: "--arduous value\t(default: 0)", + expected: "--arduous float64\t(default: 0)", }, { name: "float64-flag-with-default-text", fl: &FloatFlag{Name: "filibuster", DefaultText: "42"}, - expected: "--filibuster value\t(default: 42)", + expected: "--filibuster float64\t(default: 42)", }, { name: "float64-slice-flag", fl: &FloatSliceFlag{Name: "pizzas"}, - expected: "--pizzas value [ --pizzas value ]\t", + expected: "--pizzas []float64 [ --pizzas []float64 ]\t", }, { name: "float64-slice-flag-with-default-text", fl: &FloatSliceFlag{Name: "pepperonis", DefaultText: "shaved"}, - expected: "--pepperonis value [ --pepperonis value ]\t(default: shaved)", + expected: "--pepperonis []float64 [ --pepperonis []float64 ]\t(default: shaved)", }, { name: "generic-flag", @@ -479,102 +479,102 @@ func TestFlagStringifying(t *testing.T) { { name: "int-flag", fl: &IntFlag{Name: "grubs"}, - expected: "--grubs value\t(default: 0)", + expected: "--grubs int64\t(default: 0)", }, { name: "int-flag-with-default-text", fl: &IntFlag{Name: "poisons", DefaultText: "11ty"}, - expected: "--poisons value\t(default: 11ty)", + expected: "--poisons int64\t(default: 11ty)", }, { name: "int-slice-flag", fl: &IntSliceFlag{Name: "pencils"}, - expected: "--pencils value [ --pencils value ]\t", + expected: "--pencils []int64 [ --pencils []int64 ]\t", }, { name: "int-slice-flag-with-default-text", fl: &IntFlag{Name: "pens", DefaultText: "-19"}, - expected: "--pens value\t(default: -19)", + expected: "--pens int64\t(default: -19)", }, { name: "uint-slice-flag", fl: &UintSliceFlag{Name: "pencils"}, - expected: "--pencils value [ --pencils value ]\t", + expected: "--pencils []uint64 [ --pencils []uint64 ]\t", }, { name: "uint-slice-flag-with-default-text", fl: &UintFlag{Name: "pens", DefaultText: "29"}, - expected: "--pens value\t(default: 29)", + expected: "--pens uint64\t(default: 29)", }, { name: "int64-flag", fl: &IntFlag{Name: "flume"}, - expected: "--flume value\t(default: 0)", + expected: "--flume int64\t(default: 0)", }, { name: "int64-flag-with-default-text", fl: &IntFlag{Name: "shattering", DefaultText: "22"}, - expected: "--shattering value\t(default: 22)", + expected: "--shattering int64\t(default: 22)", }, { name: "uint64-slice-flag", fl: &UintSliceFlag{Name: "drawers"}, - expected: "--drawers value [ --drawers value ]\t", + expected: "--drawers []uint64 [ --drawers []uint64 ]\t", }, { name: "uint64-slice-flag-with-default-text", fl: &UintSliceFlag{Name: "handles", DefaultText: "-2"}, - expected: "--handles value [ --handles value ]\t(default: -2)", + expected: "--handles []uint64 [ --handles []uint64 ]\t(default: -2)", }, { name: "string-flag", fl: &StringFlag{Name: "arf-sound"}, - expected: "--arf-sound value\t", + expected: "--arf-sound string\t", }, { name: "string-flag-with-default-text", fl: &StringFlag{Name: "woof-sound", DefaultText: "urp"}, - expected: "--woof-sound value\t(default: urp)", + expected: "--woof-sound string\t(default: urp)", }, { name: "string-slice-flag", fl: &StringSliceFlag{Name: "meow-sounds"}, - expected: "--meow-sounds value [ --meow-sounds value ]\t", + expected: "--meow-sounds []string [ --meow-sounds []string ]\t", }, { name: "string-slice-flag-with-default-text", fl: &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"}, - expected: "--moo-sounds value [ --moo-sounds value ]\t(default: awoo)", + expected: "--moo-sounds []string [ --moo-sounds []string ]\t(default: awoo)", }, { name: "timestamp-flag", fl: &TimestampFlag{Name: "eating"}, - expected: "--eating value\t", + expected: "--eating Time\t", }, { name: "timestamp-flag-with-default-text", fl: &TimestampFlag{Name: "sleeping", DefaultText: "earlier"}, - expected: "--sleeping value\t(default: earlier)", + expected: "--sleeping Time\t(default: earlier)", }, { name: "uint-flag", fl: &UintFlag{Name: "jars"}, - expected: "--jars value\t(default: 0)", + expected: "--jars uint64\t(default: 0)", }, { name: "uint-flag-with-default-text", fl: &UintFlag{Name: "bottles", DefaultText: "99"}, - expected: "--bottles value\t(default: 99)", + expected: "--bottles uint64\t(default: 99)", }, { name: "uint64-flag", fl: &UintFlag{Name: "cans"}, - expected: "--cans value\t(default: 0)", + expected: "--cans uint64\t(default: 0)", }, { name: "uint64-flag-with-default-text", fl: &UintFlag{Name: "tubes", DefaultText: "13"}, - expected: "--tubes value\t(default: 13)", + expected: "--tubes uint64\t(default: 13)", }, { name: "nodoc-flag", @@ -596,10 +596,10 @@ var stringFlagTests = []struct { value string expected string }{ - {"foo", nil, "", "", "--foo value\t"}, - {"f", nil, "", "", "-f value\t"}, + {"foo", nil, "", "", "--foo string\t"}, + {"f", nil, "", "", "-f string\t"}, {"f", nil, "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"}, - {"test", nil, "", "Something", "--test value\t(default: \"Something\")"}, + {"test", nil, "", "Something", "--test string\t(default: \"Something\")"}, {"config", []string{"c"}, "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"}, {"config", []string{"c"}, "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"}, } @@ -724,11 +724,11 @@ var stringSliceFlagTests = []struct { value []string expected string }{ - {"foo", nil, []string{}, "--foo value [ --foo value ]\t"}, - {"f", nil, []string{}, "-f value [ -f value ]\t"}, - {"f", nil, []string{"Lipstick"}, "-f value [ -f value ]\t(default: \"Lipstick\")"}, - {"test", nil, []string{"Something"}, "--test value [ --test value ]\t(default: \"Something\")"}, - {"dee", []string{"d"}, []string{"Inka", "Dinka", "dooo"}, "--dee value, -d value [ --dee value, -d value ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"}, + {"foo", nil, []string{}, "--foo []string [ --foo []string ]\t"}, + {"f", nil, []string{}, "-f []string [ -f []string ]\t"}, + {"f", nil, []string{"Lipstick"}, "-f []string [ -f []string ]\t(default: \"Lipstick\")"}, + {"test", nil, []string{"Something"}, "--test []string [ --test []string ]\t(default: \"Something\")"}, + {"dee", []string{"d"}, []string{"Inka", "Dinka", "dooo"}, "--dee []string, -d []string [ --dee []string, -d []string ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"}, } func TestStringSliceFlagHelpOutput(t *testing.T) { @@ -814,8 +814,8 @@ var intFlagTests = []struct { name string expected string }{ - {"hats", "--hats value\t(default: 9)"}, - {"H", "-H value\t(default: 9)"}, + {"hats", "--hats int64\t(default: 9)"}, + {"H", "-H int64\t(default: 9)"}, } func TestIntFlagHelpOutput(t *testing.T) { @@ -868,8 +868,8 @@ var uintFlagTests = []struct { name string expected string }{ - {"nerfs", "--nerfs value\t(default: 41)"}, - {"N", "-N value\t(default: 41)"}, + {"nerfs", "--nerfs uint64\t(default: 41)"}, + {"N", "-N uint64\t(default: 41)"}, } func TestUintFlagHelpOutput(t *testing.T) { @@ -911,8 +911,8 @@ var uint64FlagTests = []struct { name string expected string }{ - {"gerfs", "--gerfs value\t(default: 8589934582)"}, - {"G", "-G value\t(default: 8589934582)"}, + {"gerfs", "--gerfs uint64\t(default: 8589934582)"}, + {"G", "-G uint64\t(default: 8589934582)"}, } func TestUint64FlagHelpOutput(t *testing.T) { @@ -954,8 +954,8 @@ var durationFlagTests = []struct { name string expected string }{ - {"hooting", "--hooting value\t(default: 1s)"}, - {"H", "-H value\t(default: 1s)"}, + {"hooting", "--hooting Duration\t(default: 1s)"}, + {"H", "-H Duration\t(default: 1s)"}, } func TestDurationFlagHelpOutput(t *testing.T) { @@ -1010,9 +1010,9 @@ var intSliceFlagTests = []struct { value []int64 expected string }{ - {"heads", nil, []int64{}, "--heads value [ --heads value ]\t"}, - {"H", nil, []int64{}, "-H value [ -H value ]\t"}, - {"H", []string{"heads"}, []int64{9, 3}, "-H value, --heads value [ -H value, --heads value ]\t(default: 9, 3)"}, + {"heads", nil, []int64{}, "--heads []int64 [ --heads []int64 ]\t"}, + {"H", nil, []int64{}, "-H []int64 [ -H []int64 ]\t"}, + {"H", []string{"heads"}, []int64{9, 3}, "-H []int64, --heads []int64 [ -H []int64, --heads []int64 ]\t(default: 9, 3)"}, } func TestIntSliceFlagHelpOutput(t *testing.T) { @@ -1131,13 +1131,13 @@ var uintSliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads value [ --heads value ]\t"}, - {"H", nil, []uint64{}, "-H value [ -H value ]\t"}, + {"heads", nil, []uint64{}, "--heads []uint64 [ --heads []uint64 ]\t"}, + {"H", nil, []uint64{}, "-H []uint64 [ -H []uint64 ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)", + "--heads []uint64, -H []uint64 [ --heads []uint64, -H []uint64 ]\t(default: 2, 17179869184)", }, } @@ -1276,13 +1276,13 @@ var uint64SliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads value [ --heads value ]\t"}, - {"H", nil, []uint64{}, "-H value [ -H value ]\t"}, + {"heads", nil, []uint64{}, "--heads []uint64 [ --heads []uint64 ]\t"}, + {"H", nil, []uint64{}, "-H []uint64 [ -H []uint64 ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)", + "--heads []uint64, -H []uint64 [ --heads []uint64, -H []uint64 ]\t(default: 2, 17179869184)", }, } @@ -1415,8 +1415,8 @@ var float64FlagTests = []struct { name string expected string }{ - {"hooting", "--hooting value\t(default: 0.1)"}, - {"H", "-H value\t(default: 0.1)"}, + {"hooting", "--hooting float64\t(default: 0.1)"}, + {"H", "-H float64\t(default: 0.1)"}, } func TestFloat64FlagHelpOutput(t *testing.T) { @@ -1467,13 +1467,13 @@ var float64SliceFlagTests = []struct { value []float64 expected string }{ - {"heads", nil, []float64{}, "--heads value [ --heads value ]\t"}, - {"H", nil, []float64{}, "-H value [ -H value ]\t"}, + {"heads", nil, []float64{}, "--heads []float64 [ --heads []float64 ]\t"}, + {"H", nil, []float64{}, "-H []float64 [ -H []float64 ]\t"}, { "heads", []string{"H"}, []float64{0.1234, -10.5}, - "--heads value, -H value [ --heads value, -H value ]\t(default: 0.1234, -10.5)", + "--heads []float64, -H []float64 [ --heads []float64, -H []float64 ]\t(default: 0.1234, -10.5)", }, } @@ -2664,31 +2664,31 @@ func TestFlagDefaultValue(t *testing.T) { name: "stringSlice", flag: &StringSliceFlag{Name: "flag", Value: []string{"default1", "default2"}}, toParse: []string{"--flag", "parsed"}, - expect: `--flag value [ --flag value ] (default: "default1", "default2")`, + expect: `--flag []string [ --flag []string ] (default: "default1", "default2")`, }, { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}}, toParse: []string{"--flag", "13.3"}, - expect: `--flag value [ --flag value ] (default: 1.1, 2.2)`, + expect: `--flag []float64 [ --flag []float64 ] (default: 1.1, 2.2)`, }, { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag value [ --flag value ] (default: 1, 2)`, + expect: `--flag []int64 [ --flag []int64 ] (default: 1, 2)`, }, { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag value [ --flag value ] (default: 1, 2)`, + expect: `--flag []uint64 [ --flag []uint64 ] (default: 1, 2)`, }, { name: "string", flag: &StringFlag{Name: "flag", Value: "default"}, toParse: []string{"--flag", "parsed"}, - expect: `--flag value (default: "default")`, + expect: `--flag string (default: "default")`, }, { name: "bool", @@ -2700,7 +2700,7 @@ func TestFlagDefaultValue(t *testing.T) { name: "uint64", flag: &UintFlag{Name: "flag", Value: 1}, toParse: []string{"--flag", "13"}, - expect: `--flag value (default: 1)`, + expect: `--flag uint64 (default: 1)`, }, { name: "stringMap", @@ -2737,7 +2737,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "stringSlice", flag: &StringSliceFlag{Name: "flag", Value: []string{"default1", "default2"}, Sources: EnvVars("ssflag")}, toParse: []string{"--flag", "parsed"}, - expect: `--flag value [ --flag value ] (default: "default1", "default2")` + withEnvHint([]string{"ssflag"}, ""), + expect: `--flag []string [ --flag []string ] (default: "default1", "default2")` + withEnvHint([]string{"ssflag"}, ""), environ: map[string]string{ "ssflag": "some-other-env_value", }, @@ -2746,7 +2746,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}, Sources: EnvVars("fsflag")}, toParse: []string{"--flag", "13.3"}, - expect: `--flag value [ --flag value ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), + expect: `--flag []float64 [ --flag []float64 ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), environ: map[string]string{ "fsflag": "20304.222", }, @@ -2755,7 +2755,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}, Sources: EnvVars("isflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value [ --flag value ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), + expect: `--flag []int64 [ --flag []int64 ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), environ: map[string]string{ "isflag": "101", }, @@ -2764,7 +2764,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}, Sources: EnvVars("uisflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value [ --flag value ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), + expect: `--flag []uint64 [ --flag []uint64 ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), environ: map[string]string{ "uisflag": "3", }, @@ -2773,7 +2773,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "string", flag: &StringFlag{Name: "flag", Value: "default", Sources: EnvVars("uflag")}, toParse: []string{"--flag", "parsed"}, - expect: `--flag value (default: "default")` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag string (default: "default")` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "some-other-string", }, @@ -2791,7 +2791,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uint64", flag: &UintFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag uint64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2800,7 +2800,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uint", flag: &UintFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag uint64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2809,7 +2809,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "int64", flag: &IntFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag int64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2818,7 +2818,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "int", flag: &IntFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag value (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag int64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2827,7 +2827,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "duration", flag: &DurationFlag{Name: "flag", Value: time.Second, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "2m"}, - expect: `--flag value (default: 1s)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag Duration (default: 1s)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "2h4m10s", }, @@ -2836,7 +2836,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "timestamp", flag: &TimestampFlag{Name: "flag", Value: ts, Config: TimestampConfig{Layouts: []string{time.RFC3339}}, Sources: EnvVars("tflag")}, toParse: []string{"--flag", "2006-11-02T15:04:05Z"}, - expect: `--flag value (default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{"tflag"}, ""), + expect: `--flag Time (default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{"tflag"}, ""), environ: map[string]string{ "tflag": "2010-01-02T15:04:05Z", }, diff --git a/godoc-current.txt b/godoc-current.txt index 3550ebe1f4..d6ed0ddca6 100644 --- a/godoc-current.txt +++ b/godoc-current.txt @@ -705,6 +705,9 @@ func (f *FlagBase[T, C, V]) GetDefaultText() string func (f *FlagBase[T, C, V]) GetEnvVars() []string GetEnvVars returns the env vars for this flag +func (f *FlagBase[T, C, V]) GetFlagType() string + GetFlagType returns the type of the flag. + func (f *FlagBase[T, C, V]) GetUsage() string GetUsage returns the usage string for the flag @@ -785,6 +788,11 @@ var FlagStringer FlagStringFunc = stringifyFlag FlagStringer converts a flag definition to a string. This is used by help to display a flag. +type FlagType interface { + GetFlagType() string +} + FlagType is an interface to detect if a flag is a string, bool, etc. + type FlagsByName []Flag FlagsByName is a slice of Flag. diff --git a/help_test.go b/help_test.go index 2ac99ab922..6ef9aaed31 100644 --- a/help_test.go +++ b/help_test.go @@ -86,7 +86,7 @@ USAGE: test [global options] [arguments...] GLOBAL OPTIONS: - --foo value, -f value + --foo int64, -f int64 --help, -h show help ` @@ -720,11 +720,11 @@ USAGE: foo frobbly [command [command options]] OPTIONS: - --bar value - --help, -h show help + --bar string + --help, -h show help GLOBAL OPTIONS: - --foo value + --foo string ` assert.Contains(t, output.String(), expected, "expected output to include global options") @@ -1648,7 +1648,7 @@ USAGE: even more OPTIONS: - --test-f value my test + --test-f string my test usage --help, -h show help `, @@ -1723,14 +1723,14 @@ USAGE: cli.test [global options] GLOBAL OPTIONS: - --help, -h show help - --m2 value - --strd value + --help, -h show help + --m2 string + --strd string cat1 - --intd value, --altd1 value, --altd2 value (default: 0) - --m1 value + --intd int64, --altd1 int64, --altd2 int64 (default: 0) + --m1 string `, output.String()) } diff --git a/testdata/godoc-v3.x.txt b/testdata/godoc-v3.x.txt index 3550ebe1f4..d6ed0ddca6 100644 --- a/testdata/godoc-v3.x.txt +++ b/testdata/godoc-v3.x.txt @@ -705,6 +705,9 @@ func (f *FlagBase[T, C, V]) GetDefaultText() string func (f *FlagBase[T, C, V]) GetEnvVars() []string GetEnvVars returns the env vars for this flag +func (f *FlagBase[T, C, V]) GetFlagType() string + GetFlagType returns the type of the flag. + func (f *FlagBase[T, C, V]) GetUsage() string GetUsage returns the usage string for the flag @@ -785,6 +788,11 @@ var FlagStringer FlagStringFunc = stringifyFlag FlagStringer converts a flag definition to a string. This is used by help to display a flag. +type FlagType interface { + GetFlagType() string +} + FlagType is an interface to detect if a flag is a string, bool, etc. + type FlagsByName []Flag FlagsByName is a slice of Flag. From 3043a4706f4cd2210ed421197e99c07f8cd7ad78 Mon Sep 17 00:00:00 2001 From: jokemanfire Date: Mon, 13 Jan 2025 09:51:28 +0800 Subject: [PATCH 2/3] Change slice type's show. deparcated the slice type prefix'[]' Signed-off-by: jokemanfire --- flag_impl.go | 5 ++-- flag_test.go | 66 ++++++++++++++++++++++++++-------------------------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/flag_impl.go b/flag_impl.go index 2cbb7b23cd..bf294b00c9 100644 --- a/flag_impl.go +++ b/flag_impl.go @@ -104,12 +104,11 @@ func (f *FlagBase[T, C, V]) GetFlagType() string { if ty == nil { return "" } - // if it is a Slice, then return the slice type. Will nested slices be used in the future? + // if it is a Slice, then return the slice's inner type. Will nested slices be used in the future? if ty.Kind() == reflect.Slice { elemType := ty.Elem() - return "[]" + elemType.Name() + return elemType.Name() } - // TODO. Hashmap is a bit difficult to judge, it will be fixed in the future return ty.Name() } diff --git a/flag_test.go b/flag_test.go index f77c21cc78..0414e4e154 100644 --- a/flag_test.go +++ b/flag_test.go @@ -459,12 +459,12 @@ func TestFlagStringifying(t *testing.T) { { name: "float64-slice-flag", fl: &FloatSliceFlag{Name: "pizzas"}, - expected: "--pizzas []float64 [ --pizzas []float64 ]\t", + expected: "--pizzas float64 [ --pizzas float64 ]\t", }, { name: "float64-slice-flag-with-default-text", fl: &FloatSliceFlag{Name: "pepperonis", DefaultText: "shaved"}, - expected: "--pepperonis []float64 [ --pepperonis []float64 ]\t(default: shaved)", + expected: "--pepperonis float64 [ --pepperonis float64 ]\t(default: shaved)", }, { name: "generic-flag", @@ -489,7 +489,7 @@ func TestFlagStringifying(t *testing.T) { { name: "int-slice-flag", fl: &IntSliceFlag{Name: "pencils"}, - expected: "--pencils []int64 [ --pencils []int64 ]\t", + expected: "--pencils int64 [ --pencils int64 ]\t", }, { name: "int-slice-flag-with-default-text", @@ -499,7 +499,7 @@ func TestFlagStringifying(t *testing.T) { { name: "uint-slice-flag", fl: &UintSliceFlag{Name: "pencils"}, - expected: "--pencils []uint64 [ --pencils []uint64 ]\t", + expected: "--pencils uint64 [ --pencils uint64 ]\t", }, { name: "uint-slice-flag-with-default-text", @@ -519,12 +519,12 @@ func TestFlagStringifying(t *testing.T) { { name: "uint64-slice-flag", fl: &UintSliceFlag{Name: "drawers"}, - expected: "--drawers []uint64 [ --drawers []uint64 ]\t", + expected: "--drawers uint64 [ --drawers uint64 ]\t", }, { name: "uint64-slice-flag-with-default-text", fl: &UintSliceFlag{Name: "handles", DefaultText: "-2"}, - expected: "--handles []uint64 [ --handles []uint64 ]\t(default: -2)", + expected: "--handles uint64 [ --handles uint64 ]\t(default: -2)", }, { name: "string-flag", @@ -539,12 +539,12 @@ func TestFlagStringifying(t *testing.T) { { name: "string-slice-flag", fl: &StringSliceFlag{Name: "meow-sounds"}, - expected: "--meow-sounds []string [ --meow-sounds []string ]\t", + expected: "--meow-sounds string [ --meow-sounds string ]\t", }, { name: "string-slice-flag-with-default-text", fl: &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"}, - expected: "--moo-sounds []string [ --moo-sounds []string ]\t(default: awoo)", + expected: "--moo-sounds string [ --moo-sounds string ]\t(default: awoo)", }, { name: "timestamp-flag", @@ -724,11 +724,11 @@ var stringSliceFlagTests = []struct { value []string expected string }{ - {"foo", nil, []string{}, "--foo []string [ --foo []string ]\t"}, - {"f", nil, []string{}, "-f []string [ -f []string ]\t"}, - {"f", nil, []string{"Lipstick"}, "-f []string [ -f []string ]\t(default: \"Lipstick\")"}, - {"test", nil, []string{"Something"}, "--test []string [ --test []string ]\t(default: \"Something\")"}, - {"dee", []string{"d"}, []string{"Inka", "Dinka", "dooo"}, "--dee []string, -d []string [ --dee []string, -d []string ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"}, + {"foo", nil, []string{}, "--foo string [ --foo string ]\t"}, + {"f", nil, []string{}, "-f string [ -f string ]\t"}, + {"f", nil, []string{"Lipstick"}, "-f string [ -f string ]\t(default: \"Lipstick\")"}, + {"test", nil, []string{"Something"}, "--test string [ --test string ]\t(default: \"Something\")"}, + {"dee", []string{"d"}, []string{"Inka", "Dinka", "dooo"}, "--dee string, -d string [ --dee string, -d string ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"}, } func TestStringSliceFlagHelpOutput(t *testing.T) { @@ -1010,9 +1010,9 @@ var intSliceFlagTests = []struct { value []int64 expected string }{ - {"heads", nil, []int64{}, "--heads []int64 [ --heads []int64 ]\t"}, - {"H", nil, []int64{}, "-H []int64 [ -H []int64 ]\t"}, - {"H", []string{"heads"}, []int64{9, 3}, "-H []int64, --heads []int64 [ -H []int64, --heads []int64 ]\t(default: 9, 3)"}, + {"heads", nil, []int64{}, "--heads int64 [ --heads int64 ]\t"}, + {"H", nil, []int64{}, "-H int64 [ -H int64 ]\t"}, + {"H", []string{"heads"}, []int64{9, 3}, "-H int64, --heads int64 [ -H int64, --heads int64 ]\t(default: 9, 3)"}, } func TestIntSliceFlagHelpOutput(t *testing.T) { @@ -1131,13 +1131,13 @@ var uintSliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads []uint64 [ --heads []uint64 ]\t"}, - {"H", nil, []uint64{}, "-H []uint64 [ -H []uint64 ]\t"}, + {"heads", nil, []uint64{}, "--heads uint64 [ --heads uint64 ]\t"}, + {"H", nil, []uint64{}, "-H uint64 [ -H uint64 ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads []uint64, -H []uint64 [ --heads []uint64, -H []uint64 ]\t(default: 2, 17179869184)", + "--heads uint64, -H uint64 [ --heads uint64, -H uint64 ]\t(default: 2, 17179869184)", }, } @@ -1276,13 +1276,13 @@ var uint64SliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads []uint64 [ --heads []uint64 ]\t"}, - {"H", nil, []uint64{}, "-H []uint64 [ -H []uint64 ]\t"}, + {"heads", nil, []uint64{}, "--heads uint64 [ --heads uint64 ]\t"}, + {"H", nil, []uint64{}, "-H uint64 [ -H uint64 ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads []uint64, -H []uint64 [ --heads []uint64, -H []uint64 ]\t(default: 2, 17179869184)", + "--heads uint64, -H uint64 [ --heads uint64, -H uint64 ]\t(default: 2, 17179869184)", }, } @@ -1467,13 +1467,13 @@ var float64SliceFlagTests = []struct { value []float64 expected string }{ - {"heads", nil, []float64{}, "--heads []float64 [ --heads []float64 ]\t"}, - {"H", nil, []float64{}, "-H []float64 [ -H []float64 ]\t"}, + {"heads", nil, []float64{}, "--heads float64 [ --heads float64 ]\t"}, + {"H", nil, []float64{}, "-H float64 [ -H float64 ]\t"}, { "heads", []string{"H"}, []float64{0.1234, -10.5}, - "--heads []float64, -H []float64 [ --heads []float64, -H []float64 ]\t(default: 0.1234, -10.5)", + "--heads float64, -H float64 [ --heads float64, -H float64 ]\t(default: 0.1234, -10.5)", }, } @@ -2664,25 +2664,25 @@ func TestFlagDefaultValue(t *testing.T) { name: "stringSlice", flag: &StringSliceFlag{Name: "flag", Value: []string{"default1", "default2"}}, toParse: []string{"--flag", "parsed"}, - expect: `--flag []string [ --flag []string ] (default: "default1", "default2")`, + expect: `--flag string [ --flag string ] (default: "default1", "default2")`, }, { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}}, toParse: []string{"--flag", "13.3"}, - expect: `--flag []float64 [ --flag []float64 ] (default: 1.1, 2.2)`, + expect: `--flag float64 [ --flag float64 ] (default: 1.1, 2.2)`, }, { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag []int64 [ --flag []int64 ] (default: 1, 2)`, + expect: `--flag int64 [ --flag int64 ] (default: 1, 2)`, }, { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag []uint64 [ --flag []uint64 ] (default: 1, 2)`, + expect: `--flag uint64 [ --flag uint64 ] (default: 1, 2)`, }, { name: "string", @@ -2737,7 +2737,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "stringSlice", flag: &StringSliceFlag{Name: "flag", Value: []string{"default1", "default2"}, Sources: EnvVars("ssflag")}, toParse: []string{"--flag", "parsed"}, - expect: `--flag []string [ --flag []string ] (default: "default1", "default2")` + withEnvHint([]string{"ssflag"}, ""), + expect: `--flag string [ --flag string ] (default: "default1", "default2")` + withEnvHint([]string{"ssflag"}, ""), environ: map[string]string{ "ssflag": "some-other-env_value", }, @@ -2746,7 +2746,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}, Sources: EnvVars("fsflag")}, toParse: []string{"--flag", "13.3"}, - expect: `--flag []float64 [ --flag []float64 ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), + expect: `--flag float64 [ --flag float64 ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), environ: map[string]string{ "fsflag": "20304.222", }, @@ -2755,7 +2755,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}, Sources: EnvVars("isflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag []int64 [ --flag []int64 ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), + expect: `--flag int64 [ --flag int64 ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), environ: map[string]string{ "isflag": "101", }, @@ -2764,7 +2764,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}, Sources: EnvVars("uisflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag []uint64 [ --flag []uint64 ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), + expect: `--flag uint64 [ --flag uint64 ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), environ: map[string]string{ "uisflag": "3", }, From 2b084ed2c19168fb4f2b33ab08d60d97cc40d1fd Mon Sep 17 00:00:00 2001 From: jokemanfire Date: Mon, 13 Jan 2025 15:15:59 +0800 Subject: [PATCH 3/3] Add hashmap type show. And fix some print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If flag is StringMapFlag ,it will print `--property string=string [--property string=string]…` Signed-off-by: jokemanfire --- flag.go | 11 ++-- flag_impl.go | 33 +++++++++-- flag_test.go | 128 ++++++++++++++++++++-------------------- godoc-current.txt | 13 ++-- help_test.go | 8 +-- testdata/godoc-v3.x.txt | 13 ++-- 6 files changed, 110 insertions(+), 96 deletions(-) diff --git a/flag.go b/flag.go index c3a96b3018..22a3315de9 100644 --- a/flag.go +++ b/flag.go @@ -142,6 +142,8 @@ type DocGenerationFlag interface { // IsDefaultVisible returns whether the default value should be shown in // help text IsDefaultVisible() bool + // TypeName to detect if a flag is a string, bool, etc. + TypeName() string } // DocGenerationMultiValueFlag extends DocGenerationFlag for slice/map based flags. @@ -180,11 +182,6 @@ type LocalFlag interface { IsLocal() bool } -// FlagType is an interface to detect if a flag is a string, bool, etc. -type FlagType interface { - GetFlagType() string -} - func newFlagSet(name string, flags []Flag) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) @@ -312,8 +309,8 @@ func stringifyFlag(f Flag) string { // if needsPlaceholder is true, placeholder is empty if needsPlaceholder && placeholder == "" { // try to get type from flag - if v1, ok := f.(FlagType); ok && v1.GetFlagType() != "" { - placeholder = v1.GetFlagType() + if tname := df.TypeName(); tname != "" { + placeholder = tname } else { placeholder = defaultPlaceholder } diff --git a/flag_impl.go b/flag_impl.go index bf294b00c9..152dc1fef8 100644 --- a/flag_impl.go +++ b/flag_impl.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "reflect" + "strings" ) // Value represents a value as used by cli. @@ -98,18 +99,40 @@ func (f *FlagBase[T, C, V]) GetValue() string { return fmt.Sprintf("%v", f.Value) } -// GetFlagType returns the type of the flag. -func (f *FlagBase[T, C, V]) GetFlagType() string { +// TypeName returns the type of the flag. +func (f *FlagBase[T, C, V]) TypeName() string { ty := reflect.TypeOf(f.Value) if ty == nil { return "" } + // convert the typename to generic type + convertToGenericType := func(name string) string { + prefixMap := map[string]string{ + "float": "float", + "int": "int", + "uint": "uint", + } + for prefix, genericType := range prefixMap { + if strings.HasPrefix(name, prefix) { + return genericType + } + } + return strings.ToLower(name) + } + + switch ty.Kind() { // if it is a Slice, then return the slice's inner type. Will nested slices be used in the future? - if ty.Kind() == reflect.Slice { + case reflect.Slice: elemType := ty.Elem() - return elemType.Name() + return convertToGenericType(elemType.Name()) + // if it is a Map, then return the map's key and value types. + case reflect.Map: + keyType := ty.Key() + valueType := ty.Elem() + return fmt.Sprintf("%s=%s", convertToGenericType(keyType.Name()), convertToGenericType(valueType.Name())) + default: + return convertToGenericType(ty.Name()) } - return ty.Name() } // Apply populates the flag given the flag set and environment diff --git a/flag_test.go b/flag_test.go index 0414e4e154..7246c209c0 100644 --- a/flag_test.go +++ b/flag_test.go @@ -439,32 +439,32 @@ func TestFlagStringifying(t *testing.T) { { name: "duration-flag", fl: &DurationFlag{Name: "scream-for"}, - expected: "--scream-for Duration\t(default: 0s)", + expected: "--scream-for duration\t(default: 0s)", }, { name: "duration-flag-with-default-text", fl: &DurationFlag{Name: "feels-about", DefaultText: "whimsically"}, - expected: "--feels-about Duration\t(default: whimsically)", + expected: "--feels-about duration\t(default: whimsically)", }, { name: "float64-flag", fl: &FloatFlag{Name: "arduous"}, - expected: "--arduous float64\t(default: 0)", + expected: "--arduous float\t(default: 0)", }, { name: "float64-flag-with-default-text", fl: &FloatFlag{Name: "filibuster", DefaultText: "42"}, - expected: "--filibuster float64\t(default: 42)", + expected: "--filibuster float\t(default: 42)", }, { name: "float64-slice-flag", fl: &FloatSliceFlag{Name: "pizzas"}, - expected: "--pizzas float64 [ --pizzas float64 ]\t", + expected: "--pizzas float [ --pizzas float ]\t", }, { name: "float64-slice-flag-with-default-text", fl: &FloatSliceFlag{Name: "pepperonis", DefaultText: "shaved"}, - expected: "--pepperonis float64 [ --pepperonis float64 ]\t(default: shaved)", + expected: "--pepperonis float [ --pepperonis float ]\t(default: shaved)", }, { name: "generic-flag", @@ -479,52 +479,52 @@ func TestFlagStringifying(t *testing.T) { { name: "int-flag", fl: &IntFlag{Name: "grubs"}, - expected: "--grubs int64\t(default: 0)", + expected: "--grubs int\t(default: 0)", }, { name: "int-flag-with-default-text", fl: &IntFlag{Name: "poisons", DefaultText: "11ty"}, - expected: "--poisons int64\t(default: 11ty)", + expected: "--poisons int\t(default: 11ty)", }, { name: "int-slice-flag", fl: &IntSliceFlag{Name: "pencils"}, - expected: "--pencils int64 [ --pencils int64 ]\t", + expected: "--pencils int [ --pencils int ]\t", }, { name: "int-slice-flag-with-default-text", fl: &IntFlag{Name: "pens", DefaultText: "-19"}, - expected: "--pens int64\t(default: -19)", + expected: "--pens int\t(default: -19)", }, { name: "uint-slice-flag", fl: &UintSliceFlag{Name: "pencils"}, - expected: "--pencils uint64 [ --pencils uint64 ]\t", + expected: "--pencils uint [ --pencils uint ]\t", }, { name: "uint-slice-flag-with-default-text", fl: &UintFlag{Name: "pens", DefaultText: "29"}, - expected: "--pens uint64\t(default: 29)", + expected: "--pens uint\t(default: 29)", }, { name: "int64-flag", fl: &IntFlag{Name: "flume"}, - expected: "--flume int64\t(default: 0)", + expected: "--flume int\t(default: 0)", }, { name: "int64-flag-with-default-text", fl: &IntFlag{Name: "shattering", DefaultText: "22"}, - expected: "--shattering int64\t(default: 22)", + expected: "--shattering int\t(default: 22)", }, { name: "uint64-slice-flag", fl: &UintSliceFlag{Name: "drawers"}, - expected: "--drawers uint64 [ --drawers uint64 ]\t", + expected: "--drawers uint [ --drawers uint ]\t", }, { name: "uint64-slice-flag-with-default-text", fl: &UintSliceFlag{Name: "handles", DefaultText: "-2"}, - expected: "--handles uint64 [ --handles uint64 ]\t(default: -2)", + expected: "--handles uint [ --handles uint ]\t(default: -2)", }, { name: "string-flag", @@ -549,32 +549,32 @@ func TestFlagStringifying(t *testing.T) { { name: "timestamp-flag", fl: &TimestampFlag{Name: "eating"}, - expected: "--eating Time\t", + expected: "--eating time\t", }, { name: "timestamp-flag-with-default-text", fl: &TimestampFlag{Name: "sleeping", DefaultText: "earlier"}, - expected: "--sleeping Time\t(default: earlier)", + expected: "--sleeping time\t(default: earlier)", }, { name: "uint-flag", fl: &UintFlag{Name: "jars"}, - expected: "--jars uint64\t(default: 0)", + expected: "--jars uint\t(default: 0)", }, { name: "uint-flag-with-default-text", fl: &UintFlag{Name: "bottles", DefaultText: "99"}, - expected: "--bottles uint64\t(default: 99)", + expected: "--bottles uint\t(default: 99)", }, { name: "uint64-flag", fl: &UintFlag{Name: "cans"}, - expected: "--cans uint64\t(default: 0)", + expected: "--cans uint\t(default: 0)", }, { name: "uint64-flag-with-default-text", fl: &UintFlag{Name: "tubes", DefaultText: "13"}, - expected: "--tubes uint64\t(default: 13)", + expected: "--tubes uint\t(default: 13)", }, { name: "nodoc-flag", @@ -814,8 +814,8 @@ var intFlagTests = []struct { name string expected string }{ - {"hats", "--hats int64\t(default: 9)"}, - {"H", "-H int64\t(default: 9)"}, + {"hats", "--hats int\t(default: 9)"}, + {"H", "-H int\t(default: 9)"}, } func TestIntFlagHelpOutput(t *testing.T) { @@ -868,8 +868,8 @@ var uintFlagTests = []struct { name string expected string }{ - {"nerfs", "--nerfs uint64\t(default: 41)"}, - {"N", "-N uint64\t(default: 41)"}, + {"nerfs", "--nerfs uint\t(default: 41)"}, + {"N", "-N uint\t(default: 41)"}, } func TestUintFlagHelpOutput(t *testing.T) { @@ -911,8 +911,8 @@ var uint64FlagTests = []struct { name string expected string }{ - {"gerfs", "--gerfs uint64\t(default: 8589934582)"}, - {"G", "-G uint64\t(default: 8589934582)"}, + {"gerfs", "--gerfs uint\t(default: 8589934582)"}, + {"G", "-G uint\t(default: 8589934582)"}, } func TestUint64FlagHelpOutput(t *testing.T) { @@ -954,8 +954,8 @@ var durationFlagTests = []struct { name string expected string }{ - {"hooting", "--hooting Duration\t(default: 1s)"}, - {"H", "-H Duration\t(default: 1s)"}, + {"hooting", "--hooting duration\t(default: 1s)"}, + {"H", "-H duration\t(default: 1s)"}, } func TestDurationFlagHelpOutput(t *testing.T) { @@ -1010,9 +1010,9 @@ var intSliceFlagTests = []struct { value []int64 expected string }{ - {"heads", nil, []int64{}, "--heads int64 [ --heads int64 ]\t"}, - {"H", nil, []int64{}, "-H int64 [ -H int64 ]\t"}, - {"H", []string{"heads"}, []int64{9, 3}, "-H int64, --heads int64 [ -H int64, --heads int64 ]\t(default: 9, 3)"}, + {"heads", nil, []int64{}, "--heads int [ --heads int ]\t"}, + {"H", nil, []int64{}, "-H int [ -H int ]\t"}, + {"H", []string{"heads"}, []int64{9, 3}, "-H int, --heads int [ -H int, --heads int ]\t(default: 9, 3)"}, } func TestIntSliceFlagHelpOutput(t *testing.T) { @@ -1131,13 +1131,13 @@ var uintSliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads uint64 [ --heads uint64 ]\t"}, - {"H", nil, []uint64{}, "-H uint64 [ -H uint64 ]\t"}, + {"heads", nil, []uint64{}, "--heads uint [ --heads uint ]\t"}, + {"H", nil, []uint64{}, "-H uint [ -H uint ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads uint64, -H uint64 [ --heads uint64, -H uint64 ]\t(default: 2, 17179869184)", + "--heads uint, -H uint [ --heads uint, -H uint ]\t(default: 2, 17179869184)", }, } @@ -1276,13 +1276,13 @@ var uint64SliceFlagTests = []struct { value []uint64 expected string }{ - {"heads", nil, []uint64{}, "--heads uint64 [ --heads uint64 ]\t"}, - {"H", nil, []uint64{}, "-H uint64 [ -H uint64 ]\t"}, + {"heads", nil, []uint64{}, "--heads uint [ --heads uint ]\t"}, + {"H", nil, []uint64{}, "-H uint [ -H uint ]\t"}, { "heads", []string{"H"}, []uint64{2, 17179869184}, - "--heads uint64, -H uint64 [ --heads uint64, -H uint64 ]\t(default: 2, 17179869184)", + "--heads uint, -H uint [ --heads uint, -H uint ]\t(default: 2, 17179869184)", }, } @@ -1415,8 +1415,8 @@ var float64FlagTests = []struct { name string expected string }{ - {"hooting", "--hooting float64\t(default: 0.1)"}, - {"H", "-H float64\t(default: 0.1)"}, + {"hooting", "--hooting float\t(default: 0.1)"}, + {"H", "-H float\t(default: 0.1)"}, } func TestFloat64FlagHelpOutput(t *testing.T) { @@ -1467,13 +1467,13 @@ var float64SliceFlagTests = []struct { value []float64 expected string }{ - {"heads", nil, []float64{}, "--heads float64 [ --heads float64 ]\t"}, - {"H", nil, []float64{}, "-H float64 [ -H float64 ]\t"}, + {"heads", nil, []float64{}, "--heads float [ --heads float ]\t"}, + {"H", nil, []float64{}, "-H float [ -H float ]\t"}, { "heads", []string{"H"}, []float64{0.1234, -10.5}, - "--heads float64, -H float64 [ --heads float64, -H float64 ]\t(default: 0.1234, -10.5)", + "--heads float, -H float [ --heads float, -H float ]\t(default: 0.1234, -10.5)", }, } @@ -2670,19 +2670,19 @@ func TestFlagDefaultValue(t *testing.T) { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}}, toParse: []string{"--flag", "13.3"}, - expect: `--flag float64 [ --flag float64 ] (default: 1.1, 2.2)`, + expect: `--flag float [ --flag float ] (default: 1.1, 2.2)`, }, { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag int64 [ --flag int64 ] (default: 1, 2)`, + expect: `--flag int [ --flag int ] (default: 1, 2)`, }, { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}}, toParse: []string{"--flag", "13"}, - expect: `--flag uint64 [ --flag uint64 ] (default: 1, 2)`, + expect: `--flag uint [ --flag uint ] (default: 1, 2)`, }, { name: "string", @@ -2700,13 +2700,13 @@ func TestFlagDefaultValue(t *testing.T) { name: "uint64", flag: &UintFlag{Name: "flag", Value: 1}, toParse: []string{"--flag", "13"}, - expect: `--flag uint64 (default: 1)`, + expect: `--flag uint (default: 1)`, }, { name: "stringMap", flag: &StringMapFlag{Name: "flag", Value: map[string]string{"default1": "default2"}}, toParse: []string{"--flag", "parsed="}, - expect: `--flag value [ --flag value ] (default: default1="default2")`, + expect: `--flag string=string [ --flag string=string ] (default: default1="default2")`, }, } for _, v := range cases { @@ -2746,7 +2746,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "float64Slice", flag: &FloatSliceFlag{Name: "flag", Value: []float64{1.1, 2.2}, Sources: EnvVars("fsflag")}, toParse: []string{"--flag", "13.3"}, - expect: `--flag float64 [ --flag float64 ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), + expect: `--flag float [ --flag float ] (default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""), environ: map[string]string{ "fsflag": "20304.222", }, @@ -2755,7 +2755,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "intSlice", flag: &IntSliceFlag{Name: "flag", Value: []int64{1, 2}, Sources: EnvVars("isflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag int64 [ --flag int64 ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), + expect: `--flag int [ --flag int ] (default: 1, 2)` + withEnvHint([]string{"isflag"}, ""), environ: map[string]string{ "isflag": "101", }, @@ -2764,7 +2764,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uintSlice", flag: &UintSliceFlag{Name: "flag", Value: []uint64{1, 2}, Sources: EnvVars("uisflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag uint64 [ --flag uint64 ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), + expect: `--flag uint [ --flag uint ] (default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""), environ: map[string]string{ "uisflag": "3", }, @@ -2791,7 +2791,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uint64", flag: &UintFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag uint64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag uint (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2800,7 +2800,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "uint", flag: &UintFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag uint64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag uint (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2809,7 +2809,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "int64", flag: &IntFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag int64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag int (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2818,7 +2818,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "int", flag: &IntFlag{Name: "flag", Value: 1, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "13"}, - expect: `--flag int64 (default: 1)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag int (default: 1)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "10", }, @@ -2827,7 +2827,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "duration", flag: &DurationFlag{Name: "flag", Value: time.Second, Sources: EnvVars("uflag")}, toParse: []string{"--flag", "2m"}, - expect: `--flag Duration (default: 1s)` + withEnvHint([]string{"uflag"}, ""), + expect: `--flag duration (default: 1s)` + withEnvHint([]string{"uflag"}, ""), environ: map[string]string{ "uflag": "2h4m10s", }, @@ -2836,7 +2836,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "timestamp", flag: &TimestampFlag{Name: "flag", Value: ts, Config: TimestampConfig{Layouts: []string{time.RFC3339}}, Sources: EnvVars("tflag")}, toParse: []string{"--flag", "2006-11-02T15:04:05Z"}, - expect: `--flag Time (default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{"tflag"}, ""), + expect: `--flag time (default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{"tflag"}, ""), environ: map[string]string{ "tflag": "2010-01-02T15:04:05Z", }, @@ -2845,7 +2845,7 @@ func TestFlagDefaultValueWithEnv(t *testing.T) { name: "stringMap", flag: &StringMapFlag{Name: "flag", Value: map[string]string{"default1": "default2"}, Sources: EnvVars("ssflag")}, toParse: []string{"--flag", "parsed="}, - expect: `--flag value [ --flag value ] (default: default1="default2")` + withEnvHint([]string{"ssflag"}, ""), + expect: `--flag string=string [ --flag string=string ] (default: default1="default2")` + withEnvHint([]string{"ssflag"}, ""), environ: map[string]string{ "ssflag": "some-other-env_value=", }, @@ -3007,11 +3007,11 @@ var stringMapFlagTests = []struct { value map[string]string expected string }{ - {"foo", nil, nil, "--foo value [ --foo value ]\t"}, - {"f", nil, nil, "-f value [ -f value ]\t"}, - {"f", nil, map[string]string{"Lipstick": ""}, "-f value [ -f value ]\t(default: Lipstick=)"}, - {"test", nil, map[string]string{"Something": ""}, "--test value [ --test value ]\t(default: Something=)"}, - {"dee", []string{"d"}, map[string]string{"Inka": "Dinka", "dooo": ""}, "--dee value, -d value [ --dee value, -d value ]\t(default: Inka=\"Dinka\", dooo=)"}, + {"foo", nil, nil, "--foo string=string [ --foo string=string ]\t"}, + {"f", nil, nil, "-f string=string [ -f string=string ]\t"}, + {"f", nil, map[string]string{"Lipstick": ""}, "-f string=string [ -f string=string ]\t(default: Lipstick=)"}, + {"test", nil, map[string]string{"Something": ""}, "--test string=string [ --test string=string ]\t(default: Something=)"}, + {"dee", []string{"d"}, map[string]string{"Inka": "Dinka", "dooo": ""}, "--dee string=string, -d string=string [ --dee string=string, -d string=string ]\t(default: Inka=\"Dinka\", dooo=)"}, } func TestStringMapFlagHelpOutput(t *testing.T) { diff --git a/godoc-current.txt b/godoc-current.txt index d6ed0ddca6..46b227e1e3 100644 --- a/godoc-current.txt +++ b/godoc-current.txt @@ -576,6 +576,8 @@ type DocGenerationFlag interface { // IsDefaultVisible returns whether the default value should be shown in // help text IsDefaultVisible() bool + // TypeName to detect if a flag is a string, bool, etc. + TypeName() string } DocGenerationFlag is an interface that allows documentation generation for the flag @@ -705,9 +707,6 @@ func (f *FlagBase[T, C, V]) GetDefaultText() string func (f *FlagBase[T, C, V]) GetEnvVars() []string GetEnvVars returns the env vars for this flag -func (f *FlagBase[T, C, V]) GetFlagType() string - GetFlagType returns the type of the flag. - func (f *FlagBase[T, C, V]) GetUsage() string GetUsage returns the usage string for the flag @@ -748,6 +747,9 @@ func (f *FlagBase[T, C, V]) String() string func (f *FlagBase[T, C, V]) TakesValue() bool TakesValue returns true if the flag takes a value, otherwise false +func (f *FlagBase[T, C, V]) TypeName() string + TypeName returns the type of the flag. + type FlagCategories interface { // AddFlags adds a flag to a category, creating a new category if necessary. AddFlag(category string, fl Flag) @@ -788,11 +790,6 @@ var FlagStringer FlagStringFunc = stringifyFlag FlagStringer converts a flag definition to a string. This is used by help to display a flag. -type FlagType interface { - GetFlagType() string -} - FlagType is an interface to detect if a flag is a string, bool, etc. - type FlagsByName []Flag FlagsByName is a slice of Flag. diff --git a/help_test.go b/help_test.go index 6ef9aaed31..30467da984 100644 --- a/help_test.go +++ b/help_test.go @@ -86,8 +86,8 @@ USAGE: test [global options] [arguments...] GLOBAL OPTIONS: - --foo int64, -f int64 - --help, -h show help + --foo int, -f int + --help, -h show help ` assert.Contains(t, output.String(), expected, @@ -1729,8 +1729,8 @@ GLOBAL OPTIONS: cat1 - --intd int64, --altd1 int64, --altd2 int64 (default: 0) - --m1 string + --intd int, --altd1 int, --altd2 int (default: 0) + --m1 string `, output.String()) } diff --git a/testdata/godoc-v3.x.txt b/testdata/godoc-v3.x.txt index d6ed0ddca6..46b227e1e3 100644 --- a/testdata/godoc-v3.x.txt +++ b/testdata/godoc-v3.x.txt @@ -576,6 +576,8 @@ type DocGenerationFlag interface { // IsDefaultVisible returns whether the default value should be shown in // help text IsDefaultVisible() bool + // TypeName to detect if a flag is a string, bool, etc. + TypeName() string } DocGenerationFlag is an interface that allows documentation generation for the flag @@ -705,9 +707,6 @@ func (f *FlagBase[T, C, V]) GetDefaultText() string func (f *FlagBase[T, C, V]) GetEnvVars() []string GetEnvVars returns the env vars for this flag -func (f *FlagBase[T, C, V]) GetFlagType() string - GetFlagType returns the type of the flag. - func (f *FlagBase[T, C, V]) GetUsage() string GetUsage returns the usage string for the flag @@ -748,6 +747,9 @@ func (f *FlagBase[T, C, V]) String() string func (f *FlagBase[T, C, V]) TakesValue() bool TakesValue returns true if the flag takes a value, otherwise false +func (f *FlagBase[T, C, V]) TypeName() string + TypeName returns the type of the flag. + type FlagCategories interface { // AddFlags adds a flag to a category, creating a new category if necessary. AddFlag(category string, fl Flag) @@ -788,11 +790,6 @@ var FlagStringer FlagStringFunc = stringifyFlag FlagStringer converts a flag definition to a string. This is used by help to display a flag. -type FlagType interface { - GetFlagType() string -} - FlagType is an interface to detect if a flag is a string, bool, etc. - type FlagsByName []Flag FlagsByName is a slice of Flag.