diff --git a/argh/parser2.go b/argh/parser2.go index 9aab14d..8d35ffa 100644 --- a/argh/parser2.go +++ b/argh/parser2.go @@ -116,29 +116,32 @@ func (p *parser2) parseCommand(cCfg *CommandConfig) Node { case IDENT, STDIN_FLAG: tracef("parseCommand(...) handling %s", p.tok) - if !cCfg.NValue.Contains(identIndex) { - tracef("parseCommand(...) identIndex=%d exceeds expected=%s; breaking", identIndex, cCfg.NValue) - break + if cCfg.NValue.Contains(identIndex) { + name := fmt.Sprintf("%d", identIndex) + + tracef("parseCommand(...) checking for name of identIndex=%d", identIndex) + + if len(cCfg.ValueNames) > identIndex { + name = cCfg.ValueNames[identIndex] + tracef("parseCommand(...) setting name=%s from config value names", name) + } else if len(cCfg.ValueNames) == 1 && (cCfg.NValue == OneOrMoreValue || cCfg.NValue == ZeroOrMoreValue) { + name = fmt.Sprintf("%s.%d", cCfg.ValueNames[0], identIndex) + tracef("parseCommand(...) setting name=%s from repeating value name", name) + } + + if node.Values == nil { + node.Values = map[string]string{} + } + + node.Values[name] = p.lit + } else { + if p.tok == STDIN_FLAG { + nodes = append(nodes, &StdinFlag{}) + } else { + nodes = append(nodes, &Ident{Literal: p.lit}) + } } - name := fmt.Sprintf("%d", identIndex) - - tracef("parseCommand(...) checking for name of identIndex=%d", identIndex) - - if len(cCfg.ValueNames) > identIndex { - name = cCfg.ValueNames[identIndex] - tracef("parseCommand(...) setting name=%s from config value names", name) - } else if len(cCfg.ValueNames) == 1 && (cCfg.NValue == OneOrMoreValue || cCfg.NValue == ZeroOrMoreValue) { - name = fmt.Sprintf("%s.%d", cCfg.ValueNames[0], identIndex) - tracef("parseCommand(...) setting name=%s from repeating value name", name) - } - - if node.Values == nil { - node.Values = map[string]string{} - } - - node.Values[name] = p.lit - identIndex++ case LONG_FLAG, SHORT_FLAG, COMPOUND_SHORT_FLAG: tok := p.tok @@ -185,22 +188,31 @@ func (p *parser2) parseFlag(flCfgMap map[string]FlagConfig) Node { } func (p *parser2) parseShortFlag(flCfgMap map[string]FlagConfig) Node { - name := string(p.lit[1]) - node := &Flag{Name: name} - tracef("parseShortFlag(...) TODO capture flag value(s)") - return node + node := &Flag{Name: string(p.lit[1])} + + flCfg, ok := flCfgMap[node.Name] + if !ok { + return node + } + + return p.parseConfiguredFlag(node, flCfg) } func (p *parser2) parseLongFlag(flCfgMap map[string]FlagConfig) Node { node := &Flag{Name: string(p.lit[2:])} - values := map[string]string{} - nodes := []Node{} flCfg, ok := flCfgMap[node.Name] if !ok { return node } + return p.parseConfiguredFlag(node, flCfg) +} + +func (p *parser2) parseConfiguredFlag(node *Flag, flCfg FlagConfig) Node { + values := map[string]string{} + nodes := []Node{} + identIndex := 0 for i := 0; p.tok != EOL; i++ { diff --git a/argh/parser2_test.go b/argh/parser2_test.go index 83742a2..cfa0837 100644 --- a/argh/parser2_test.go +++ b/argh/parser2_test.go @@ -243,65 +243,75 @@ func TestParser2(t *testing.T) { }, }, { - skip: true, - name: "short value-less flags", args: []string{"pizzas", "-t", "-f", "-s"}, expPT: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "t"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "f"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "s"}, + &argh.Command{ + Name: "pizzas", + Nodes: []argh.Node{ + &argh.ArgDelimiter{}, + &argh.Flag{Name: "t"}, + &argh.ArgDelimiter{}, + &argh.Flag{Name: "f"}, + &argh.ArgDelimiter{}, + &argh.Flag{Name: "s"}, + }, + }, }, expAST: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.Flag{Name: "t"}, - argh.Flag{Name: "f"}, - argh.Flag{Name: "s"}, + &argh.Command{ + Name: "pizzas", + Nodes: []argh.Node{ + &argh.Flag{Name: "t"}, + &argh.Flag{Name: "f"}, + &argh.Flag{Name: "s"}, + }, + }, }, }, { - skip: true, - name: "compound short flags", args: []string{"pizzas", "-aca", "-blol"}, expPT: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.ArgDelimiter{}, - argh.CompoundShortFlag{ + &argh.Command{ + Name: "pizzas", Nodes: []argh.Node{ - argh.Flag{Name: "a"}, - argh.Flag{Name: "c"}, - argh.Flag{Name: "a"}, + &argh.ArgDelimiter{}, + &argh.CompoundShortFlag{ + Nodes: []argh.Node{ + &argh.Flag{Name: "a"}, + &argh.Flag{Name: "c"}, + &argh.Flag{Name: "a"}, + }, + }, + &argh.ArgDelimiter{}, + &argh.CompoundShortFlag{ + Nodes: []argh.Node{ + &argh.Flag{Name: "b"}, + &argh.Flag{Name: "l"}, + &argh.Flag{Name: "o"}, + &argh.Flag{Name: "l"}, + }, + }, }, }, - argh.ArgDelimiter{}, - argh.CompoundShortFlag{ + }, + expAST: []argh.Node{ + &argh.Command{ + Name: "pizzas", Nodes: []argh.Node{ - argh.Flag{Name: "b"}, - argh.Flag{Name: "l"}, - argh.Flag{Name: "o"}, - argh.Flag{Name: "l"}, + &argh.Flag{Name: "a"}, + &argh.Flag{Name: "c"}, + &argh.Flag{Name: "a"}, + &argh.Flag{Name: "b"}, + &argh.Flag{Name: "l"}, + &argh.Flag{Name: "o"}, + &argh.Flag{Name: "l"}, }, }, }, - expAST: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.Flag{Name: "a"}, - argh.Flag{Name: "c"}, - argh.Flag{Name: "a"}, - argh.Flag{Name: "b"}, - argh.Flag{Name: "l"}, - argh.Flag{Name: "o"}, - argh.Flag{Name: "l"}, - }, }, { - skip: true, - name: "mixed long short value flags", args: []string{"pizzas", "-a", "--ca", "-b", "1312", "-lol"}, cfg: &argh.ParserConfig{ @@ -313,52 +323,93 @@ func TestParser2(t *testing.T) { }, }, expPT: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "a"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "ca"}, - argh.ArgDelimiter{}, - argh.Flag{Name: "b", Values: map[string]string{"0": "1312"}}, - argh.ArgDelimiter{}, - argh.CompoundShortFlag{ + &argh.Command{ + Name: "pizzas", Nodes: []argh.Node{ - argh.Flag{Name: "l"}, - argh.Flag{Name: "o"}, - argh.Flag{Name: "l"}, + &argh.ArgDelimiter{}, + &argh.Flag{Name: "a"}, + &argh.ArgDelimiter{}, + &argh.Flag{Name: "ca"}, + &argh.ArgDelimiter{}, + &argh.Flag{ + Name: "b", + Values: map[string]string{"0": "1312"}, + Nodes: []argh.Node{ + &argh.ArgDelimiter{}, + }, + }, + &argh.ArgDelimiter{}, + &argh.CompoundShortFlag{ + Nodes: []argh.Node{ + &argh.Flag{Name: "l"}, + &argh.Flag{Name: "o"}, + &argh.Flag{Name: "l"}, + }, + }, }, }, }, expAST: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.Flag{Name: "a"}, - argh.Flag{Name: "ca"}, - argh.Flag{Name: "b", Values: map[string]string{"0": "1312"}}, - argh.Flag{Name: "l"}, - argh.Flag{Name: "o"}, - argh.Flag{Name: "l"}, + &argh.Command{ + Name: "pizzas", + Nodes: []argh.Node{ + &argh.Flag{Name: "a"}, + &argh.Flag{Name: "ca"}, + &argh.Flag{Name: "b", Values: map[string]string{"0": "1312"}}, + &argh.Flag{Name: "l"}, + &argh.Flag{Name: "o"}, + &argh.Flag{Name: "l"}, + }, + }, }, }, { - skip: true, - - name: "commands", - args: []string{"pizzas", "fly", "fry"}, + name: "nested commands with positional args", + args: []string{"pizzas", "fly", "freely", "sometimes", "and", "other", "times", "fry", "deeply", "--forever"}, cfg: &argh.ParserConfig{ Prog: argh.CommandConfig{ Commands: map[string]argh.CommandConfig{ - "fly": argh.CommandConfig{}, - "fry": argh.CommandConfig{}, + "fly": argh.CommandConfig{ + Commands: map[string]argh.CommandConfig{ + "fry": argh.CommandConfig{}, + }, + }, }, Flags: map[string]argh.FlagConfig{}, }, }, expPT: []argh.Node{ - argh.Command{Name: "pizzas"}, - argh.ArgDelimiter{}, - argh.Command{Name: "fly"}, - argh.ArgDelimiter{}, - argh.Command{Name: "fry"}, + &argh.Command{ + Name: "pizzas", + Nodes: []argh.Node{ + &argh.ArgDelimiter{}, + &argh.Command{ + Name: "fly", + Nodes: []argh.Node{ + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "freely"}, + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "sometimes"}, + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "and"}, + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "other"}, + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "times"}, + &argh.ArgDelimiter{}, + &argh.Command{ + Name: "fry", + Nodes: []argh.Node{ + &argh.ArgDelimiter{}, + &argh.Ident{Literal: "deeply"}, + &argh.ArgDelimiter{}, + &argh.Flag{Name: "forever"}, + }, + }, + }, + }, + }, + }, }, }, {