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.
|
||||
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
|
||||
// given without any flag before.
|
||||
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.
|
||||
func (c *Command) predict(a Args) (options []string, only bool) {
|
||||
|
||||
// if wordCompleted has something that needs to follow it,
|
||||
// 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
|
||||
// search sub commands for predictions first
|
||||
subCommandFound := false
|
||||
for i, arg := range a.Completed {
|
||||
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 !subCommandFound {
|
||||
options = append(options, c.Sub.Predict(a)...)
|
||||
// if last completed word is a global flag that we need to complete
|
||||
if predictor, ok := c.GlobalFlags[a.LastCompleted]; ok && predictor != nil {
|
||||
Log("Predicting according to global flag %s", a.LastCompleted)
|
||||
return predictor.Predict(a), true
|
||||
}
|
||||
|
||||
// add global available complete options
|
||||
options = append(options, c.Flags.Predict(a)...)
|
||||
options = append(options, c.GlobalFlags.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 {
|
||||
options = append(options, c.Args.Predict(a)...)
|
||||
}
|
||||
|
|
|
@ -11,36 +11,30 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
initTests()
|
||||
|
||||
c := Command{
|
||||
Sub: map[string]Command{
|
||||
Sub: Commands{
|
||||
"sub1": {
|
||||
Flags: map[string]Predictor{
|
||||
Flags: Flags{
|
||||
"-flag1": PredictAnything,
|
||||
"-flag2": PredictNothing,
|
||||
},
|
||||
},
|
||||
"sub2": {
|
||||
Flags: map[string]Predictor{
|
||||
Flags: Flags{
|
||||
"-flag2": PredictNothing,
|
||||
"-flag3": PredictSet("opt1", "opt2", "opt12"),
|
||||
},
|
||||
Args: PredictFiles("*.md"),
|
||||
},
|
||||
},
|
||||
Flags: map[string]Predictor{
|
||||
Flags: Flags{
|
||||
"-o": PredictFiles("*.txt"),
|
||||
},
|
||||
GlobalFlags: Flags{
|
||||
"-h": PredictNothing,
|
||||
"-global1": PredictAnything,
|
||||
"-o": PredictFiles("*.txt"),
|
||||
},
|
||||
}
|
||||
|
||||
allGlobals := []string{}
|
||||
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"}
|
||||
|
||||
tests := []struct {
|
||||
|
@ -49,7 +43,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
args: "",
|
||||
want: allGlobals,
|
||||
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||
},
|
||||
{
|
||||
args: "-",
|
||||
|
@ -57,7 +51,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "-h ",
|
||||
want: allGlobals,
|
||||
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||
},
|
||||
{
|
||||
args: "-global1 ", // global1 is known follow flag
|
||||
|
@ -77,11 +71,11 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "sub1 ",
|
||||
want: []string{"-flag1", "-flag2", "-h", "-global1", "-o"},
|
||||
want: []string{"-flag1", "-flag2", "-h", "-global1"},
|
||||
},
|
||||
{
|
||||
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 ./",
|
||||
|
@ -93,7 +87,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
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",
|
||||
|
@ -109,7 +103,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "sub1 -flag2 ",
|
||||
want: []string{"-flag1", "-flag2", "-h", "-global1", "-o"},
|
||||
want: []string{"-flag1", "-flag2", "-h", "-global1"},
|
||||
},
|
||||
{
|
||||
args: "-no-such-flag",
|
||||
|
@ -117,7 +111,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "-no-such-flag ",
|
||||
want: allGlobals,
|
||||
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||
},
|
||||
{
|
||||
args: "no-such-command",
|
||||
|
@ -125,7 +119,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "no-such-command ",
|
||||
want: allGlobals,
|
||||
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||
},
|
||||
{
|
||||
args: "-o ",
|
||||
|
@ -149,7 +143,7 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
},
|
||||
{
|
||||
args: "-o ./readme.md ",
|
||||
want: allGlobals,
|
||||
want: []string{"sub1", "sub2", "-h", "-global1", "-o"},
|
||||
},
|
||||
{
|
||||
args: "-o sub2 -flag3 ",
|
||||
|
|
|
@ -181,7 +181,7 @@ func main() {
|
|||
"fix": fix,
|
||||
"version": version,
|
||||
},
|
||||
Flags: complete.Flags{
|
||||
GlobalFlags: complete.Flags{
|
||||
"-h": complete.PredictNothing,
|
||||
},
|
||||
}
|
||||
|
|
13
readme.md
13
readme.md
|
@ -85,15 +85,20 @@ func main() {
|
|||
|
||||
// define flags of the 'run' main command
|
||||
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
|
||||
// it, the tab completion will auto complete for files matching
|
||||
// the given pattern.
|
||||
"-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.
|
||||
|
|
Loading…
Reference in New Issue