diff --git a/build.go b/build.go index ef6798f..d867222 100644 --- a/build.go +++ b/build.go @@ -10,7 +10,7 @@ import ( func build(ast interface{}) (app *Application, err error) { defer func() { msg := recover() - if test, ok := recover().(error); ok { + if test, ok := msg.(error); ok { app = nil err = test } else if msg != nil { @@ -23,13 +23,16 @@ func build(ast interface{}) (app *Application, err error) { return nil, fmt.Errorf("expected a pointer to a struct but got %T", ast) } - return buildNode(iv), nil + return buildNode(iv, true), nil } -func buildNode(v reflect.Value) *Node { +func buildNode(v reflect.Value, cmd bool) *Node { node := &Node{} for i := 0; i < v.NumField(); i++ { ft := v.Type().Field(i) + if strings.ToLower(ft.Name[0:1]) == ft.Name[0:1] { + continue + } fv := v.Field(i) name := ft.Tag.Get("name") @@ -37,10 +40,7 @@ func buildNode(v reflect.Value) *Node { name = strings.ToLower(strings.Join(camelCase(ft.Name), "-")) } decoder := DecoderForField(ft) - help, ok := ft.Tag.Lookup("help") - if !ok { - continue - } + help, _ := ft.Tag.Lookup("help") dflt := ft.Tag.Get("default") placeholder := ft.Tag.Get("placeholder") if placeholder == "" { @@ -55,12 +55,15 @@ func buildNode(v reflect.Value) *Node { _, optional := ft.Tag.Lookup("optional") // Force field to be an argument, not a flag. _, arg := ft.Tag.Lookup("arg") + if !cmd { + _, cmd = ft.Tag.Lookup("cmd") + } env := ft.Tag.Get("env") format := ft.Tag.Get("format") // Nested structs are either commands or args. - if ft.Type.Kind() == reflect.Struct && decoder == nil { - child := buildNode(fv) + if ft.Type.Kind() == reflect.Struct && (cmd || arg) { + child := buildNode(fv, false) child.Help = help // A branching argument. This is a bit hairy, as we let buildNode() do the parsing, then check that diff --git a/kong_test.go b/kong_test.go index 9abbe54..72ec784 100644 --- a/kong_test.go +++ b/kong_test.go @@ -17,11 +17,11 @@ func TestArgumentSequence(t *testing.T) { var cli struct { User struct { Create struct { - ID int `arg:"" help:""` - First string `arg:"" help:""` - Last string `arg:"" help:""` - } `help:""` - } `help:""` + ID int `arg:""` + First string `arg:""` + Last string `arg:""` + } `cmd:""` + } `cmd:""` } p := mustNew(t, &cli) cmd, err := p.Parse([]string{"user", "create", "10", "Alec", "Thomas"}) @@ -39,21 +39,21 @@ func TestBranchingArgument(t *testing.T) { var cli struct { User struct { Create struct { - ID string `arg:"" help:""` - First string `arg:"" help:""` - Last string `arg:"" help:""` - } `help:""` + ID string `arg:""` + First string `arg:""` + Last string `arg:""` + } `cmd:""` // Branching argument. ID struct { - ID int `arg:"" help:""` - Flag int `help:""` - Delete struct{} `help:""` + ID int `arg:""` + Flag int + Delete struct{} `cmd:""` Rename struct { - To string `help:""` - } `help:""` - } `arg:"" help:""` - } `help:"Manage users."` + To string + } `cmd:""` + } `arg:""` + } `cmd:"" help:"User management."` } p := mustNew(t, &cli) cmd, err := p.Parse([]string{"user", "10", "delete"}) @@ -64,8 +64,8 @@ func TestBranchingArgument(t *testing.T) { func TestResetWithDefaults(t *testing.T) { var cli struct { - Flag string `help:""` - FlagWithDefault string `default:"default" help:""` + Flag string + FlagWithDefault string `default:"default" ` } cli.Flag = "BLAH" cli.FlagWithDefault = "BLAH" @@ -78,7 +78,7 @@ func TestResetWithDefaults(t *testing.T) { func TestFlagSlice(t *testing.T) { var cli struct { - Slice []int `help:""` + Slice []int } parser := mustNew(t, &cli) _, err := parser.Parse([]string{"--slice=1,2,3"}) @@ -88,8 +88,8 @@ func TestFlagSlice(t *testing.T) { func TestArgSlice(t *testing.T) { var cli struct { - Slice []int `help:"" arg:""` - Flag bool `help:""` + Slice []int `arg:""` + Flag bool } parser := mustNew(t, &cli) _, err := parser.Parse([]string{"1", "2", "3", "--flag"}) @@ -100,7 +100,8 @@ func TestArgSlice(t *testing.T) { func TestUnsupportedfieldErrors(t *testing.T) { var cli struct { - Keys map[string]string `help:""` + Keys map[string]string } - require.Panics(t, func() { mustNew(t, &cli) }) + _, err := New("", "", &cli) + require.Error(t, err) } diff --git a/model.go b/model.go index 50be9c2..4512d08 100644 --- a/model.go +++ b/model.go @@ -20,6 +20,7 @@ type Node struct { Children []*Branch } +// A Value is either a flag or a variaable positional argument. type Value struct { Flag bool // True if flag, false if positional argument. Name string