Support completion of positional "rest" (slice/array) args
Given a command with a positional "rest" arg (`Filename []Filename`
here):
AddMultiCommand struct {
Positional struct {
Filename []Filename
} `positional-args:"yes"`
} `command:"add-multi"`
This PR implements completion for the rest arg using the element
type of the "rest" arg value (here, `Filename`).
Adds the test AddMultiCommand to TestCompletion to test the new
behavior.
Adds a sentence describing this new behavior in the flags.go package
documentation (previously, the docs did not clearly define whether
this behavior was present).
diff --git a/completion.go b/completion.go
index 2f730d9..97ad524 100644
--- a/completion.go
+++ b/completion.go
@@ -122,6 +122,12 @@
}
func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
+ // For slices/arrays in positional args (that take the rest of the args),
+ // complete based on the element type.
+ if typ := value.Type(); typ.Kind() == reflect.Array || typ.Kind() == reflect.Slice {
+ value = reflect.New(typ.Elem())
+ }
+
i := value.Interface()
var ret []Completion
@@ -205,7 +211,11 @@
}
} else {
if len(s.positional) > 0 {
- s.positional = s.positional[1:]
+ if t := s.positional[0].value.Type(); t.Kind() != reflect.Array && t.Kind() != reflect.Slice {
+ // Don't advance beyond a slice/array positional (because
+ // they consume all subsequent args).
+ s.positional = s.positional[1:]
+ }
} else if cmd, ok := s.lookup.commands[arg]; ok {
cmd.fillParseState(s)
}
diff --git a/completion_test.go b/completion_test.go
index f51949e..908e421 100644
--- a/completion_test.go
+++ b/completion_test.go
@@ -43,6 +43,12 @@
} `positional-args:"yes"`
} `command:"add"`
+ AddMultiCommand struct {
+ Positional struct {
+ Filename []Filename
+ } `positional-args:"yes"`
+ } `command:"add-multi"`
+
RemoveCommand struct {
Other bool `short:"o"`
File Filename `short:"f" long:"filename"`
@@ -90,7 +96,7 @@
{
// Commands
[]string{""},
- []string{"add", "rename", "rm"},
+ []string{"add", "add-multi", "rename", "rm"},
},
{
@@ -106,6 +112,22 @@
},
{
+ // Multiple positional filename (1 arg)
+ []string{"add-multi", filepath.Join(sourcedir, "completion")},
+ excompl,
+ },
+ {
+ // Multiple positional filename (2 args)
+ []string{"add-multi", filepath.Join(sourcedir, "completion.go"), filepath.Join(sourcedir, "completion")},
+ excompl,
+ },
+ {
+ // Multiple positional filename (3 args)
+ []string{"add-multi", filepath.Join(sourcedir, "completion.go"), filepath.Join(sourcedir, "completion.go"), filepath.Join(sourcedir, "completion")},
+ excompl,
+ },
+
+ {
// Flag filename
[]string{"rm", "-f", path.Join(sourcedir, "completion")},
excompl,
diff --git a/flags.go b/flags.go
index 68173e7..830b1f7 100644
--- a/flags.go
+++ b/flags.go
@@ -222,6 +222,7 @@
Customized completion for argument values is supported by implementing
the flags.Completer interface for the argument value type. An example
of a type which does so is the flags.Filename type, an alias of string
-allowing simple filename completion.
+allowing simple filename completion. A slice or array argument value
+whose element type implements flags.Completer will also be completed.
*/
package flags