parent
e00c0546bc
commit
096b79324e
38
command.go
38
command.go
|
@ -15,6 +15,10 @@ type Command struct {
|
||||||
// The key is the flag name, and the value is it's predictions.
|
// The key is the flag name, and the value is it's predictions.
|
||||||
Flags Flags
|
Flags Flags
|
||||||
|
|
||||||
|
// GlobalFlags is a map of flags that the command accepts.
|
||||||
|
// Global flags that can appear also after a sub command.
|
||||||
|
GlobalFlags Flags
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -58,14 +62,7 @@ func (f Flags) Predict(a Args) (prediction []string) {
|
||||||
// and other flags or sub commands can't come after it.
|
// and other flags or sub commands can't come after it.
|
||||||
func (c *Command) predict(a Args) (options []string, only bool) {
|
func (c *Command) predict(a Args) (options []string, only bool) {
|
||||||
|
|
||||||
// if wordCompleted has something that needs to follow it,
|
// search sub commands for predictions first
|
||||||
// it is the most relevant completion
|
|
||||||
if predictor, ok := c.Flags[a.LastCompleted]; ok && predictor != nil {
|
|
||||||
Log("Predicting according to flag %s", a.Last)
|
|
||||||
return predictor.Predict(a), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// search sub commands for predictions
|
|
||||||
subCommandFound := false
|
subCommandFound := false
|
||||||
for i, arg := range a.Completed {
|
for i, arg := range a.Completed {
|
||||||
if cmd, ok := c.Sub[arg]; ok {
|
if cmd, ok := c.Sub[arg]; ok {
|
||||||
|
@ -79,15 +76,28 @@ func (c *Command) predict(a Args) (options []string, only bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no sub command was found, return a list of the sub commands
|
// if last completed word is a global flag that we need to complete
|
||||||
if !subCommandFound {
|
if predictor, ok := c.GlobalFlags[a.LastCompleted]; ok && predictor != nil {
|
||||||
options = append(options, c.Sub.Predict(a)...)
|
Log("Predicting according to global flag %s", a.LastCompleted)
|
||||||
|
return predictor.Predict(a), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// add global available complete options
|
options = append(options, c.GlobalFlags.Predict(a)...)
|
||||||
options = append(options, c.Flags.Predict(a)...)
|
|
||||||
|
|
||||||
// add additional expected argument of the command
|
// if a sub command was entered, we won't add the parent command
|
||||||
|
// completions and we return here.
|
||||||
|
if subCommandFound {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if last completed word is a command flag that we need to complete
|
||||||
|
if predictor, ok := c.Flags[a.LastCompleted]; ok && predictor != nil {
|
||||||
|
Log("Predicting according to flag %s", a.LastCompleted)
|
||||||
|
return predictor.Predict(a), true
|
||||||
|
}
|
||||||
|
|
||||||
|
options = append(options, c.Sub.Predict(a)...)
|
||||||
|
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)...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,34 +11,28 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
initTests()
|
initTests()
|
||||||
|
|
||||||
c := Command{
|
c := Command{
|
||||||
Sub: map[string]Command{
|
Sub: Commands{
|
||||||
"sub1": {
|
"sub1": {
|
||||||
Flags: map[string]Predictor{
|
Flags: Flags{
|
||||||
"-flag1": PredictAnything,
|
"-flag1": PredictAnything,
|
||||||
"-flag2": PredictNothing,
|
"-flag2": PredictNothing,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sub2": {
|
"sub2": {
|
||||||
Flags: map[string]Predictor{
|
Flags: Flags{
|
||||||
"-flag2": PredictNothing,
|
"-flag2": PredictNothing,
|
||||||
"-flag3": PredictSet("opt1", "opt2", "opt12"),
|
"-flag3": PredictSet("opt1", "opt2", "opt12"),
|
||||||
},
|
},
|
||||||
Args: PredictFiles("*.md"),
|
Args: PredictFiles("*.md"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Flags: map[string]Predictor{
|
Flags: Flags{
|
||||||
"-h": PredictNothing,
|
|
||||||
"-global1": PredictAnything,
|
|
||||||
"-o": PredictFiles("*.txt"),
|
"-o": PredictFiles("*.txt"),
|
||||||
},
|
},
|
||||||
}
|
GlobalFlags: Flags{
|
||||||
|
"-h": PredictNothing,
|
||||||
allGlobals := []string{}
|
"-global1": PredictAnything,
|
||||||
for sub := range c.Sub {
|
},
|
||||||
allGlobals = append(allGlobals, sub)
|
|
||||||
}
|
|
||||||
for flag := range c.Flags {
|
|
||||||
allGlobals = append(allGlobals, flag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testTXTFiles := []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt"}
|
testTXTFiles := []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt"}
|
||||||
|
@ -49,7 +43,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
args: "",
|
args: "",
|
||||||
want: allGlobals,
|
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-",
|
args: "-",
|
||||||
|
@ -57,7 +51,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-h ",
|
args: "-h ",
|
||||||
want: allGlobals,
|
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-global1 ", // global1 is known follow flag
|
args: "-global1 ", // global1 is known follow flag
|
||||||
|
@ -77,11 +71,11 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub1 ",
|
args: "sub1 ",
|
||||||
want: []string{"-flag1", "-flag2", "-h", "-global1", "-o"},
|
want: []string{"-flag1", "-flag2", "-h", "-global1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub2 ",
|
args: "sub2 ",
|
||||||
want: []string{"./", "./dir/", "./outer/", "./readme.md", "-flag2", "-flag3", "-h", "-global1", "-o"},
|
want: []string{"./", "./dir/", "./outer/", "./readme.md", "-flag2", "-flag3", "-h", "-global1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub2 ./",
|
args: "sub2 ./",
|
||||||
|
@ -93,7 +87,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub2 -flag2 ",
|
args: "sub2 -flag2 ",
|
||||||
want: []string{"./", "./dir/", "./outer/", "./readme.md", "-flag2", "-flag3", "-h", "-global1", "-o"},
|
want: []string{"./", "./dir/", "./outer/", "./readme.md", "-flag2", "-flag3", "-h", "-global1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub1 -fl",
|
args: "sub1 -fl",
|
||||||
|
@ -109,7 +103,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "sub1 -flag2 ",
|
args: "sub1 -flag2 ",
|
||||||
want: []string{"-flag1", "-flag2", "-h", "-global1", "-o"},
|
want: []string{"-flag1", "-flag2", "-h", "-global1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-no-such-flag",
|
args: "-no-such-flag",
|
||||||
|
@ -117,7 +111,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-no-such-flag ",
|
args: "-no-such-flag ",
|
||||||
want: allGlobals,
|
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "no-such-command",
|
args: "no-such-command",
|
||||||
|
@ -125,7 +119,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "no-such-command ",
|
args: "no-such-command ",
|
||||||
want: allGlobals,
|
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-o ",
|
args: "-o ",
|
||||||
|
@ -149,7 +143,7 @@ func TestCompleter_Complete(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-o ./readme.md ",
|
args: "-o ./readme.md ",
|
||||||
want: allGlobals,
|
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
args: "-o sub2 -flag3 ",
|
args: "-o sub2 -flag3 ",
|
||||||
|
|
|
@ -181,7 +181,7 @@ func main() {
|
||||||
"fix": fix,
|
"fix": fix,
|
||||||
"version": version,
|
"version": version,
|
||||||
},
|
},
|
||||||
Flags: complete.Flags{
|
GlobalFlags: complete.Flags{
|
||||||
"-h": complete.PredictNothing,
|
"-h": complete.PredictNothing,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
13
readme.md
13
readme.md
|
@ -85,15 +85,20 @@ func main() {
|
||||||
|
|
||||||
// define flags of the 'run' main command
|
// define flags of the 'run' main command
|
||||||
Flags: complete.Flags{
|
Flags: complete.Flags{
|
||||||
|
|
||||||
// a flag '-h' which does not expects anything after it
|
|
||||||
"-h": complete.PredictNothing,
|
|
||||||
|
|
||||||
// a flag -o, which expects a file ending with .out after
|
// a flag -o, which expects a file ending with .out after
|
||||||
// it, the tab completion will auto complete for files matching
|
// it, the tab completion will auto complete for files matching
|
||||||
// the given pattern.
|
// the given pattern.
|
||||||
"-o": complete.PredictFiles("*.out"),
|
"-o": complete.PredictFiles("*.out"),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// define gloabl flags of the 'run' main command
|
||||||
|
// those will show up also when a sub command was entered in the
|
||||||
|
// command line
|
||||||
|
Flags: complete.Flags{
|
||||||
|
|
||||||
|
// a flag '-h' which does not expects anything after it
|
||||||
|
"-h": complete.PredictNothing,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the command completion, as part of the main() function.
|
// run the command completion, as part of the main() function.
|
||||||
|
|
Loading…
Reference in New Issue