-
Notifications
You must be signed in to change notification settings - Fork 1
Completions
For those who have followed the documentation in order, we now get to the comfort-of-life aspects of this library: completions and validations. This page focuses on completions.
Note that the completions provided are not those of the cobra library, although you could still use cobra-provided ones would you want to.
As mentionned in the README, the flags library uses the carapace completion engine to generate completions for all components of a given command/tree (commands/flags/arguments).
The package provided to generate completions is github.com/reeflective/flags/gen/completions
.
Out of the box, generating completions with this package (and given carapace
is installed)
will provide cross-shell completions for:
- commands
- flags (interspersed, optional ones, and with much attention for their types/requirements)
- Arguments for flags, when those have a list of valid choices.
The following call is enough to generate completions for the entire command tree:
package main
import (
"github.com/reeflective/flags/gen/flags"
"github.com/reeflective/flags/gen/completions"
)
func main() {
structData := Root{}
// Generate the command tree
rootCmd := flags.Generate(&structData)
// Generate the completions
// This has added a hidden completion command to our cobra command root.
comps := completions.Generate(rootCmd, structData, nil)
// Call to this method will hide the hidden cobra completion command.
comps.Standalone()
// And run the binary, either for execution or completion.
rootCmd.Execute()
}
Some basic completers can be specified with struct tags, on either positional or flags fields.
See the godoc file for a list of the valid complete
tag directives and their effect.
type Create struct {
Args struct {
Directory string `complete:"Dir"`
Files []string `complete:"Files"`
} `positional-args:"yes" required:"true"`
// Flags
NoFail bool `flag:"n no-fail"`
Extensions []string `short:"p" long:"perms" complete:"FilterExt,json,go`
APIKey string `flag:"k key" desc:"API key to authenticate" required:"yes"`
}
Note that if a given type implements the Completer
below, but that a complete
tag directive
is specified on the field where this type is used, the tagged directive will have precedence.
(This might change in the future, with possibility to combine both)
Types can also implement completers. Note that for flags (not positionals), this incurs a caveat:
the type must implement the flag.Value
interface, explained in the flags page.
For positional arguments, there are no special requirements; the fields' types just have to implement
the following interface:
type Completer interface {
Complete(ctx carapace.Context) carapace.Action
}
This interface might seem deliberately complex, but is so on purpose:
- If you import the
completions
generation package, you will needcarapace
anyway. - It allows to use a single completion signature for all completers, regardless of their complexity.
- For the most advanced cases (and please be assured that they will be rare), the
carapace.Context
object gives full access to the current command line words, split-args, current prefix, etc. In 95% of cases, however, you won't need to use it, even when providing completion for slices/maps.
The following is a type implementing the completer. It is used in the example binary as a positional argument in several commands:
func (p *Host) Complete(ctx carapace.Context) carapace.Action {
action := carapace.ActionStyledValuesDescribed(
"192.168.1.1", "A first ip address", style.BgBlue,
"192.168.3.12", "a second address", style.BrightGreen,
"10.203.23.45", "and a third one", style.BrightCyan,
"127.0.0.1", "and a third one", style.BrightCyan,
"219.293.91.10", "", style.Blue,
).Tag("IPv4 addresses").Invoke(ctx).Filter(ctx.Args).ToA()
return action
}
A few explanations:
-
Tag("IPv4 addresses")
is used by certain shells with grouping support. -
Invoke(ctx).Filter(ctx.Args)
is a safety call to ensure that (as a positional) values cannot be repeated. - Both of those calls are not strictly necessary (for instance, the second one is automatic when completing flags with array/map containers.)
Please see the relevant carapace documentation for writing completers. This link is also provided in the godoc file for quick access from you editor.
You might make use of either individual or slice/map types for your positional slots or flags.
Therefore, you could potentially implement the Completer
interface either around the list as type,
or around the indivual reflect.Elem
type of this slice/map.
It is strongly advised to implement the completer around the individual Elem
, for several reasons:
- You can reuse this type more easily in several commands/positional/flags fields.
- The completion library will automatically adapt its completion behavior when
Elem
is part of a slice/map.
Therefore, implementing the Completer
around a list type should only ever be done if you really wish
to provide the entire list completion by yourself, which I personally see absolutely no valid reason for.
The completions
package, regardless, will always:
- Adapt its completion logic based where is implemented the completer.
- Will always use the completer implemented by an array type rather than the one provided by its
Elems
.