Implementing value capture for short flags

and ensuring all unknown ident/stdin nodes are retained
This commit is contained in:
Dan Buch 2022-05-25 22:24:12 -04:00
parent 03edacc8ec
commit 3ea30a997a
Signed by: meatballhat
GPG Key ID: A12F782281063434
2 changed files with 164 additions and 101 deletions

View File

@ -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
}
func (p *parser2) parseLongFlag(flCfgMap map[string]FlagConfig) Node {
node := &Flag{Name: string(p.lit[2:])}
values := map[string]string{}
nodes := []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:])}
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++ {

View File

@ -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: "b"},
argh.Flag{Name: "l"},
argh.Flag{Name: "o"},
argh.Flag{Name: "l"},
&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"},
},
},
},
},
},
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"},
&argh.Command{
Name: "pizzas",
Nodes: []argh.Node{
&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"},
},
},
},
},
},
},
},
},
{