Skip to content

Commit

Permalink
Merge pull request #684 from baude/shortOptionHandling
Browse files Browse the repository at this point in the history
Combine bool short names
  • Loading branch information
jszwedko committed Nov 16, 2017
2 parents 44cb242 + fd5382e commit 7ace96b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 18 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ applications in an expressive way.
* [Version Flag](#version-flag)
+ [Customization](#customization-2)
+ [Full API Example](#full-api-example)
* [Combining short Bool options](#combining-short-bool-options)
- [Contribution Guidelines](#contribution-guidelines)

<!-- tocstop -->
Expand Down Expand Up @@ -1410,6 +1411,26 @@ func wopAction(c *cli.Context) error {
}
```

### Combining short Bool options

Traditional use of boolean options using their shortnames look like this:
```
# cmd foobar -s -o
```

Suppose you want users to be able to combine your bool options with their shortname. This
can be done using the **UseShortOptionHandling** bool in your commands. Suppose your program
has a two bool flags such as *serve* and *option* with the short options of *-o* and
*-s* respectively. With **UseShortOptionHandling** set to *true*, a user can use a syntax
like:
```
# cmd foobar -so
```

If you enable the **UseShortOptionHandling*, then you must not use any flags that have a single
leading *-* or this will result in failures. For example, **-option** can no longer be used. Flags
with two leading dashes (such as **--options**) are still valid.

## Contribution Guidelines

Feel free to put up a pull request to fix a bug or maybe add a feature. I will
Expand Down
22 changes: 20 additions & 2 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type Command struct {
HideHelp bool
// Boolean to hide this command from help or completion
Hidden bool
// Boolean to enable short-option handling so user can combine several
// single-character bool arguements into one
// i.e. foobar -o -v -> foobar -ov
UseShortOptionHandling bool

// Full name of command for help, defaults to full command name, including parent commands.
HelpName string
Expand Down Expand Up @@ -141,8 +145,22 @@ func (c Command) Run(ctx *Context) (err error) {
} else {
flagArgs = args[firstFlagIndex:]
}

err = set.Parse(append(flagArgs, regularArgs...))
// separate combined flags
if c.UseShortOptionHandling {
var flagArgsSeparated []string
for _, flagArg := range flagArgs {
if strings.HasPrefix(flagArg, "-") && strings.HasPrefix(flagArg, "--") == false && len(flagArg) > 2 {
for _, flagChar := range flagArg[1:] {
flagArgsSeparated = append(flagArgsSeparated, "-"+string(flagChar))
}
} else {
flagArgsSeparated = append(flagArgsSeparated, flagArg)
}
}
err = set.Parse(append(flagArgsSeparated, regularArgs...))
} else {
err = set.Parse(append(flagArgs, regularArgs...))
}
} else {
err = set.Parse(ctx.Args().Tail())
}
Expand Down
36 changes: 20 additions & 16 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import (

func TestCommandFlagParsing(t *testing.T) {
cases := []struct {
testArgs []string
skipFlagParsing bool
skipArgReorder bool
expectedErr error
testArgs []string
skipFlagParsing bool
skipArgReorder bool
expectedErr error
UseShortOptionHandling bool
}{
// Test normal "not ignoring flags" flow
{[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break")},
{[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break"), false},

// Test no arg reorder
{[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil},
{[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil, false},

{[]string{"test-cmd", "blah", "blah"}, true, false, nil, false}, // Test SkipFlagParsing without any args that look like flags
{[]string{"test-cmd", "blah", "-break"}, true, false, nil, false}, // Test SkipFlagParsing with random flag arg
{[]string{"test-cmd", "blah", "-help"}, true, false, nil, false}, // Test SkipFlagParsing with "special" help flag arg
{[]string{"test-cmd", "blah"}, false, false, nil, true}, // Test UseShortOptionHandling

{[]string{"test-cmd", "blah", "blah"}, true, false, nil}, // Test SkipFlagParsing without any args that look like flags
{[]string{"test-cmd", "blah", "-break"}, true, false, nil}, // Test SkipFlagParsing with random flag arg
{[]string{"test-cmd", "blah", "-help"}, true, false, nil}, // Test SkipFlagParsing with "special" help flag arg
}

for _, c := range cases {
Expand All @@ -36,13 +39,14 @@ func TestCommandFlagParsing(t *testing.T) {
context := NewContext(app, set, nil)

command := Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *Context) error { return nil },
SkipFlagParsing: c.skipFlagParsing,
SkipArgReorder: c.skipArgReorder,
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *Context) error { return nil },
SkipFlagParsing: c.skipFlagParsing,
SkipArgReorder: c.skipArgReorder,
UseShortOptionHandling: c.UseShortOptionHandling,
}

err := command.Run(context)
Expand Down
25 changes: 25 additions & 0 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,31 @@ func TestParseMultiBool(t *testing.T) {
a.Run([]string{"run", "--serve"})
}

func TestParseBoolShortOptionHandle(t *testing.T) {
a := App{
Commands: []Command{
{
Name: "foobar",
UseShortOptionHandling: true,
Action: func(ctx *Context) error {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("option") != true {
t.Errorf("short name not set")
}
return nil
},
Flags: []Flag{
BoolFlag{Name: "serve, s"},
BoolFlag{Name: "option, o"},
},
},
},
}
a.Run([]string{"run", "foobar", "-so"})
}

func TestParseDestinationBool(t *testing.T) {
var dest bool
a := App{
Expand Down

0 comments on commit 7ace96b

Please sign in to comment.