Allow restricting completion of flags

This PR allows a command to specify that flags should only be completed
when a prefix is present. The motivation behind this is to have the
initial complation to prefer displaying argument completions and only
display flag completions when the user enters "hyphen <tab>".
This commit is contained in:
Alex Dadgar 2017-08-23 13:16:52 -07:00
parent 5075f6d6e6
commit 59e6151c5b
2 changed files with 41 additions and 9 deletions

View File

@ -1,6 +1,10 @@
package complete package complete
import "github.com/posener/complete/match" import (
"strings"
"github.com/posener/complete/match"
)
// Command represents a command line // Command represents a command line
// It holds the data that enables auto completion of command line // It holds the data that enables auto completion of command line
@ -19,6 +23,11 @@ type Command struct {
// Global flags that can appear also after a sub command. // Global flags that can appear also after a sub command.
GlobalFlags Flags GlobalFlags Flags
// FlagsRequirePrefix requires that the prefix is provided before flags are
// autocompleted. This allows completion to only display completions for
// arguments if for example no hypen is provided.
FlagsRequirePrefix string
// Args are extra arguments that the command accepts, those who are // Args are extra arguments that the command accepts, those who are
// given without any flag before. // given without any flag before.
Args Predictor Args Predictor
@ -86,7 +95,9 @@ func (c *Command) predict(a Args) (options []string, only bool) {
return predictor.Predict(a), true return predictor.Predict(a), true
} }
options = append(options, c.GlobalFlags.Predict(a)...) if c.FlagsRequirePrefix == "" || strings.HasPrefix(a.Last, c.FlagsRequirePrefix) {
options = append(options, c.GlobalFlags.Predict(a)...)
}
// if a sub command was entered, we won't add the parent command // if a sub command was entered, we won't add the parent command
// completions and we return here. // completions and we return here.
@ -101,7 +112,9 @@ func (c *Command) predict(a Args) (options []string, only bool) {
} }
options = append(options, c.Sub.Predict(a)...) options = append(options, c.Sub.Predict(a)...)
options = append(options, c.Flags.Predict(a)...) if c.FlagsRequirePrefix == "" || strings.HasPrefix(a.Last, c.FlagsRequirePrefix) {
options = append(options, c.Flags.Predict(a)...)
}
if c.Args != nil { if c.Args != nil {
options = append(options, c.Args.Predict(a)...) options = append(options, c.Args.Predict(a)...)
} }

View File

@ -25,6 +25,13 @@ func TestCompleter_Complete(t *testing.T) {
}, },
Args: PredictFiles("*.md"), Args: PredictFiles("*.md"),
}, },
"sub3": {
Flags: Flags{
"-flag4": PredictAnything,
"-flag5": PredictNothing,
},
FlagsRequirePrefix: "-",
},
}, },
Flags: Flags{ Flags: Flags{
"-o": PredictFiles("*.txt"), "-o": PredictFiles("*.txt"),
@ -41,7 +48,7 @@ func TestCompleter_Complete(t *testing.T) {
}{ }{
{ {
args: "", args: "",
want: []string{"sub1", "sub2", "-h", "-global1", "-o"}, want: []string{"sub1", "sub2", "sub3", "-h", "-global1", "-o"},
}, },
{ {
args: "-", args: "-",
@ -49,7 +56,7 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "-h ", args: "-h ",
want: []string{"sub1", "sub2", "-h", "-global1", "-o"}, want: []string{"sub1", "sub2", "sub3", "-h", "-global1", "-o"},
}, },
{ {
args: "-global1 ", // global1 is known follow flag args: "-global1 ", // global1 is known follow flag
@ -57,7 +64,7 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "sub", args: "sub",
want: []string{"sub1", "sub2"}, want: []string{"sub1", "sub2", "sub3"},
}, },
{ {
args: "sub1", args: "sub1",
@ -67,6 +74,10 @@ func TestCompleter_Complete(t *testing.T) {
args: "sub2", args: "sub2",
want: []string{"sub2"}, want: []string{"sub2"},
}, },
{
args: "sub3",
want: []string{"sub3"},
},
{ {
args: "sub1 ", args: "sub1 ",
want: []string{"-flag1", "-flag2", "-h", "-global1"}, want: []string{"-flag1", "-flag2", "-h", "-global1"},
@ -107,13 +118,21 @@ func TestCompleter_Complete(t *testing.T) {
args: "sub1 -flag2 ", args: "sub1 -flag2 ",
want: []string{"-flag1", "-flag2", "-h", "-global1"}, want: []string{"-flag1", "-flag2", "-h", "-global1"},
}, },
{
args: "sub3 ",
want: []string{"-h", "-global1"},
},
{
args: "sub3 -",
want: []string{"-flag4", "-flag5", "-h", "-global1"},
},
{ {
args: "-no-such-flag", args: "-no-such-flag",
want: []string{}, want: []string{},
}, },
{ {
args: "-no-such-flag ", args: "-no-such-flag ",
want: []string{"sub1", "sub2", "-h", "-global1", "-o"}, want: []string{"sub1", "sub2", "sub3", "-h", "-global1", "-o"},
}, },
{ {
args: "no-such-command", args: "no-such-command",
@ -121,7 +140,7 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "no-such-command ", args: "no-such-command ",
want: []string{"sub1", "sub2", "-h", "-global1", "-o"}, want: []string{"sub1", "sub2", "sub3", "-h", "-global1", "-o"},
}, },
{ {
args: "-o ", args: "-o ",
@ -149,7 +168,7 @@ func TestCompleter_Complete(t *testing.T) {
}, },
{ {
args: "-o ./readme.md ", args: "-o ./readme.md ",
want: []string{"sub1", "sub2", "-h", "-global1", "-o"}, want: []string{"sub1", "sub2", "sub3", "-h", "-global1", "-o"},
}, },
{ {
args: "-o sub2 -flag3 ", args: "-o sub2 -flag3 ",