Support for flag prefixing.
This commit is contained in:
@@ -395,7 +395,9 @@ Both can coexist with standard Tag parsing.
|
|||||||
| `hidden` | If present, command or flag is hidden. |
|
| `hidden` | If present, command or flag is hidden. |
|
||||||
| `format:"X"` | Format for parsing input, if supported. |
|
| `format:"X"` | Format for parsing input, if supported. |
|
||||||
| `sep:"X"` | Separator for sequences (defaults to ","). May be `none` to disable splitting. |
|
| `sep:"X"` | Separator for sequences (defaults to ","). May be `none` to disable splitting. |
|
||||||
| `enum:"X,Y,..."` |
|
| `enum:"X,Y,..."` | Set of valid values allowed for this flag. |
|
||||||
|
| `group:"X"` | Logical group for a flag or command. |
|
||||||
|
| `prefix:"X"` | Prefix for all sub-flags. |
|
||||||
|
|
||||||
## Variable interpolation
|
## Variable interpolation
|
||||||
|
|
||||||
|
|||||||
@@ -38,20 +38,30 @@ func dashedString(s string) string {
|
|||||||
type flattenedField struct {
|
type flattenedField struct {
|
||||||
field reflect.StructField
|
field reflect.StructField
|
||||||
value reflect.Value
|
value reflect.Value
|
||||||
|
tag *Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenedFields(v reflect.Value) (out []flattenedField) {
|
func flattenedFields(v reflect.Value) (out []flattenedField) {
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
ft := v.Type().Field(i)
|
ft := v.Type().Field(i)
|
||||||
fv := v.Field(i)
|
fv := v.Field(i)
|
||||||
|
tag := parseTag(fv, ft)
|
||||||
if ft.Anonymous {
|
if ft.Anonymous {
|
||||||
out = append(out, flattenedFields(fv)...)
|
sub := flattenedFields(fv)
|
||||||
|
// Assign parent group to children, if they're not otherwise set.
|
||||||
|
for _, subf := range sub {
|
||||||
|
if subf.tag.Group == "" {
|
||||||
|
subf.tag.Group = tag.Group
|
||||||
|
}
|
||||||
|
subf.tag.Prefix = tag.Prefix + subf.tag.Prefix
|
||||||
|
}
|
||||||
|
out = append(out, sub...)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !fv.CanSet() {
|
if !fv.CanSet() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out = append(out, flattenedField{field: ft, value: fv})
|
out = append(out, flattenedField{field: ft, value: fv, tag: tag})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -65,11 +75,12 @@ func buildNode(k *Kong, v reflect.Value, typ NodeType, seenFlags map[string]bool
|
|||||||
ft := field.field
|
ft := field.field
|
||||||
fv := field.value
|
fv := field.value
|
||||||
|
|
||||||
tag := parseTag(fv, ft)
|
tag := field.tag
|
||||||
|
|
||||||
name := tag.Name
|
name := tag.Name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = strings.ToLower(dashedString(ft.Name))
|
name = tag.Prefix + strings.ToLower(dashedString(ft.Name))
|
||||||
|
} else {
|
||||||
|
name = tag.Prefix + name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nested structs are either commands or args, unless they implement the Mapper interface.
|
// Nested structs are either commands or args, unless they implement the Mapper interface.
|
||||||
@@ -108,6 +119,7 @@ func buildChild(k *Kong, node *Node, typ NodeType, v reflect.Value, ft reflect.S
|
|||||||
child.Parent = node
|
child.Parent = node
|
||||||
child.Help = tag.Help
|
child.Help = tag.Help
|
||||||
child.Hidden = tag.Hidden
|
child.Hidden = tag.Hidden
|
||||||
|
child.Group = tag.Group
|
||||||
|
|
||||||
if fv.Type().Implements(helpProviderType) {
|
if fv.Type().Implements(helpProviderType) {
|
||||||
child.Detail = fv.Interface().(HelpProvider).Help()
|
child.Detail = fv.Interface().(HelpProvider).Help()
|
||||||
@@ -176,6 +188,7 @@ func buildField(k *Kong, node *Node, v reflect.Value, ft reflect.StructField, fv
|
|||||||
Short: tag.Short,
|
Short: tag.Short,
|
||||||
PlaceHolder: tag.PlaceHolder,
|
PlaceHolder: tag.PlaceHolder,
|
||||||
Env: tag.Env,
|
Env: tag.Env,
|
||||||
|
Group: tag.Group,
|
||||||
}
|
}
|
||||||
value.Flag = flag
|
value.Flag = flag
|
||||||
node.Flags = append(node.Flags, flag)
|
node.Flags = append(node.Flags, flag)
|
||||||
|
|||||||
@@ -577,3 +577,16 @@ func TestBoolOverride(t *testing.T) {
|
|||||||
_, err = p.Parse([]string{"--flag", "false"})
|
_, err = p.Parse([]string{"--flag", "false"})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAnonymousPrefix(t *testing.T) {
|
||||||
|
type Anonymous struct {
|
||||||
|
Flag string
|
||||||
|
}
|
||||||
|
var cli struct {
|
||||||
|
Anonymous `prefix:"anon-"`
|
||||||
|
}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse([]string{"--anon-flag=moo"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "moo", cli.Flag)
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type Node struct {
|
|||||||
Name string
|
Name string
|
||||||
Help string // Short help displayed in summaries.
|
Help string // Short help displayed in summaries.
|
||||||
Detail string // Detailed help displayed when describing command/arg alone.
|
Detail string // Detailed help displayed when describing command/arg alone.
|
||||||
|
Group string
|
||||||
Hidden bool
|
Hidden bool
|
||||||
Flags []*Flag
|
Flags []*Flag
|
||||||
Positional []*Positional
|
Positional []*Positional
|
||||||
@@ -284,6 +285,7 @@ type Positional = Value
|
|||||||
// A Flag represents a command-line flag.
|
// A Flag represents a command-line flag.
|
||||||
type Flag struct {
|
type Flag struct {
|
||||||
*Value
|
*Value
|
||||||
|
Group string // Logical grouping when displaying. May also be used by configuration loaders to group options logically.
|
||||||
PlaceHolder string
|
PlaceHolder string
|
||||||
Env string
|
Env string
|
||||||
Short rune
|
Short rune
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ type Tag struct {
|
|||||||
Hidden bool
|
Hidden bool
|
||||||
Sep rune
|
Sep rune
|
||||||
Enum string
|
Enum string
|
||||||
|
Group string
|
||||||
|
Prefix string // Optional prefix on anonymous structs. All sub-flags will have this prefix.
|
||||||
|
|
||||||
// Storage for all tag keys for arbitrary lookups.
|
// Storage for all tag keys for arbitrary lookups.
|
||||||
items map[string]string
|
items map[string]string
|
||||||
@@ -137,6 +139,8 @@ func parseTag(fv reflect.Value, ft reflect.StructField) *Tag {
|
|||||||
t.Hidden = t.Has("hidden")
|
t.Hidden = t.Has("hidden")
|
||||||
t.Format = t.Get("format")
|
t.Format = t.Get("format")
|
||||||
t.Sep, _ = t.GetRune("sep")
|
t.Sep, _ = t.GetRune("sep")
|
||||||
|
t.Group = t.Get("group")
|
||||||
|
t.Prefix = t.Get("prefix")
|
||||||
if t.Sep == 0 {
|
if t.Sep == 0 {
|
||||||
if t.Get("sep") == "none" {
|
if t.Get("sep") == "none" {
|
||||||
t.Sep = -1
|
t.Sep = -1
|
||||||
|
|||||||
Reference in New Issue
Block a user