Skip to content

Commit 0a4a98c

Browse files
committed
🐛 fix: gflag - fix type name error on render help
1 parent 1dd8c1e commit 0a4a98c

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

gflag/args_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,51 @@ func TestArgument_SetValue(t *testing.T) {
134134
assert.NoErr(t, err)
135135
assert.Eq(t, 12, arg.Val())
136136
}
137+
138+
func TestCliArgs_AddArg_panic(t *testing.T) {
139+
is := assert.New(t)
140+
c := gflag.Arguments{}
141+
c.SetName("test")
142+
143+
arg := c.AddArg("arg0", "arg desc", true)
144+
is.Eq(0, arg.Index())
145+
146+
ret := c.ArgByIndex(0)
147+
is.Eq(ret, arg)
148+
149+
assert.PanicsMsg(t, func() {
150+
c.ArgByIndex(1)
151+
}, "gflag: get not exists argument #1")
152+
153+
arg = c.AddArg("arg1", "arg1 desc")
154+
is.Eq(1, arg.Index())
155+
156+
ret = c.Arg("arg1")
157+
is.Eq(ret, arg)
158+
159+
is.PanicsMsg(func() {
160+
c.Arg("not-exist")
161+
}, "gflag: get not exists argument 'not-exist'")
162+
163+
is.Len(c.Args(), 2)
164+
165+
is.PanicsMsg(func() {
166+
c.AddArg("", "desc")
167+
}, "gflag: the command argument name cannot be empty")
168+
169+
is.PanicsMsg(func() {
170+
c.AddArg(":)&dfd", "desc")
171+
}, "gflag: the argument name ':)&dfd' is invalid, must match: ^[a-zA-Z][\\w-]*$")
172+
173+
is.PanicsMsg(func() {
174+
c.AddArg("arg1", "desc")
175+
}, "gflag: the argument name 'arg1' already exists in command 'test'")
176+
is.PanicsMsg(func() {
177+
c.AddArg("arg2", "arg2 desc", true)
178+
}, "gflag: required argument 'arg2' cannot be defined after optional argument")
179+
180+
c.AddArg("arg3", "arg3 desc", false, true)
181+
is.PanicsMsg(func() {
182+
c.AddArg("argN", "desc", true)
183+
}, "gflag: have defined an array argument, you cannot add argument 'argN'")
184+
}

gflag/gflag.go

+6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ type Config struct {
5858
DisableArg bool
5959
// IndentLongOpt indent long option name on print help
6060
IndentLongOpt bool
61+
// EnhanceShort enhance short option parse. TODO
62+
//
63+
// 0 - none
64+
// 1 - multi short bool options. eg: `-aux` = `-a -u -x`
65+
// 2 - allow name with value as one node. eg: `-Ostdout` = `-O stdout`
66+
EnhanceShort uint8
6167
}
6268

6369
// GetTagName get tag name, default is FlagTagName

gflag/help.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package gflag
22

33
import (
44
"bytes"
5-
"flag"
65
"fmt"
76
"strings"
87

@@ -102,7 +101,7 @@ func (p *Parser) formatOneFlag(f *Flag) (s string) {
102101
s = fmt.Sprintf(" <info>%s</>", fullName)
103102

104103
// - build flag type info
105-
typeName, desc := flag.UnquoteUsage(f)
104+
typeName, desc := UnquoteUsage(f)
106105
// typeName: option value data type: int, string, ..., bool value will return ""
107106
if !p.cfg.WithoutType && len(typeName) > 0 {
108107
typeLen := len(typeName) + 1

gflag/util.go

+44
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,47 @@ func parseSimpleRule(rule string) (mp map[string]string) {
8484
}
8585
return arrutil.CombineToSMap(flagTagKeys1, ss)
8686
}
87+
88+
// UnquoteUsage extracts a back-quoted name from the usage
89+
// string for a flag and returns it and the un-quoted usage.
90+
// Given "a `name` to show" it returns ("name", "a name to show").
91+
// If there are no back quotes, the name is an educated guess of the
92+
// type of the flag's value, or the empty string if the flag is boolean.
93+
//
94+
// Note: from go flag.UnquoteUsage()
95+
func UnquoteUsage(flag *Flag) (name string, usage string) {
96+
// Look for a back-quoted name, but avoid the strings package.
97+
usage = flag.Usage
98+
for i := 0; i < len(usage); i++ {
99+
if usage[i] == '`' {
100+
for j := i + 1; j < len(usage); j++ {
101+
if usage[j] == '`' {
102+
name = usage[i+1 : j]
103+
usage = usage[:i] + name + usage[j+1:]
104+
return name, usage
105+
}
106+
}
107+
break // Only one back quote; use type name.
108+
}
109+
}
110+
111+
// No explicit name, so use type if we can find one.
112+
name = "value"
113+
switch fv := flag.Value.(type) {
114+
case boolFlag:
115+
if fv.IsBoolFlag() {
116+
name = ""
117+
}
118+
case *durationValue:
119+
name = "duration"
120+
case *float64Value:
121+
name = "float"
122+
case *intValue, *int64Value:
123+
name = "int"
124+
case *stringValue:
125+
name = "string"
126+
case *uintValue, *uint64Value:
127+
name = "uint"
128+
}
129+
return
130+
}

0 commit comments

Comments
 (0)