From b1ece673038af041f3ecaac4b1accd6bcf6fc94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Furga=C5=82a?= <83299832+00200200@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:32:28 +0200 Subject: [PATCH] Show count flags as optional in usage. Count flags use NoOptDefVal, so --foo 2 leaves 2 as a positional argument while --foo=2 sets the value. Printing "count" as a required argument made the space-separated form look valid. --- count_test.go | 30 ++++++++++++++++++++++++++++++ flag.go | 8 ++++++-- flag_test.go | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/count_test.go b/count_test.go index 3785d375..00f39cba 100644 --- a/count_test.go +++ b/count_test.go @@ -2,6 +2,7 @@ package pflag import ( "os" + "strings" "testing" ) @@ -54,3 +55,32 @@ func TestCount(t *testing.T) { } } } + +// Count flags take an optional --flag=N value (NoOptDefVal), so --foo 2 +// treats "2" as a positional argument. Help used to print a required-looking +// "count" argument, which implied the space-separated form would work (#267). +func TestCountUsageShowsOptionalValue(t *testing.T) { + f := NewFlagSet("test", ContinueOnError) + var n int + f.CountVar(&n, "foo", "increment") + usage := f.FlagUsages() + if strings.Contains(usage, "--foo count") { + t.Fatalf("usage presents count as a required argument:\n%s", usage) + } + if !strings.Contains(usage, "--foo[=count]") { + t.Fatalf("usage should show optional --foo[=count], got:\n%s", usage) + } + + f2 := NewFlagSet("test", ContinueOnError) + var n2 int + f2.CountVar(&n2, "foo", "increment") + if err := f2.Parse([]string{"--foo", "2"}); err != nil { + t.Fatal(err) + } + if n2 != 1 { + t.Fatalf("space-separated --foo 2 should increment once, got %d", n2) + } + if got := f2.Args(); len(got) != 1 || got[0] != "2" { + t.Fatalf("space-separated 2 should remain a positional arg, got %v", got) + } +} diff --git a/flag.go b/flag.go index a4affd48..f9d88646 100644 --- a/flag.go +++ b/flag.go @@ -793,7 +793,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { varname, usage := UnquoteUsage(flag) if isNoOptBoolValue(flag.Value) && flag.Value.Type() == "bool" { line += "[=true|false]" - } else if varname != "" { + } else if varname != "" && !(flag.Value.Type() == "count" && flag.NoOptDefVal != "") { + // Count flags with NoOptDefVal treat a following token as a + // positional argument, so don't print a required-looking type name. line += " " + varname } @@ -806,7 +808,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } case "count": - if flag.NoOptDefVal != "+1" { + if flag.NoOptDefVal == "+1" { + line += "[=count]" + } else { line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) } default: diff --git a/flag_test.go b/flag_test.go index 1e26d190..0ffd87cb 100644 --- a/flag_test.go +++ b/flag_test.go @@ -1477,7 +1477,7 @@ const defaultOutput = ` --A[=true|false] for bootstrapping, a --custom-with-val custom custom value which has been set from command line while help is shown --customP custom a VarP with default (default 10) --maxT timeout set timeout for dial - -v, --verbose count verbosity + -v, --verbose[=count] verbosity ` // Custom value that satisfies the Value interface.