complete

This package provides a library for writing shell-agnostic tab completion.
(bash, zsh, fish)
While completion for any program can be written with the library, it's targeted for
self-completing Go programs. This is a program that doesn't need to distribute, or
maintain, any complex bash/zsh/fish script alongside their normal CLI.
It was originally forked from posener/complete,
which has went in a different direction. See "Motivation for Forking".
Features
- Describe the skeleton of your CLI and get tab-completion for free
- Write custom predictors to enrich suggestions using your existing business logic
- Dynamic, contextual suggestions based on what the user has typed.
- A flag may need different values depending on a positional argument's value.
- Helpers to generate skeletons from well-known CLI frameworks.
cobra
is automatic
- Seamless helpers for
flags
and urfavecli
is planned.
Self Completion
Shells can query external binaries to get tab suggestions.
They provide a few environment variables to the program, and this package parses them.
It notes what has been typed in the prompt, the cursor position where the user has
pressed TAB, and returns relevant suggestions.
By writing custom predictors, tools can hook into this and enrich the user's
experience. Use existing logic in your code without duplicating it to a shell script.
Installation
While developers don't need to distribute complicated shell programs for completion,
a bit of configuration is still needed.
Bash is one command and zsh is two, fish is a bit more. Any program that uses this
package can be installed by setting COMP_INSTALL=1
and running the program.
COMP_INSTALL=1 mycli
COMP_INSTALL=1 COMP_YES=1 mycli
COMP_UNINSTALL=1 mycli
If you prefer the manual way:
complete -C /path/to/mycli mycli
autoload -U +X bashcompinit && bashcompinit
complete -C /path/to/mycli mycli
Examples
If you want to jump into an example, here they are:
Predictors
A Predictor
is any type that implements Predict(args.Args) []string
.
args.Args
contains a few fields:
type Args struct {
All []string
Completed []string
Last string
LastCompleted string
ParsedRoot any
}
Each Predictor
is mapped to a flag or command to generate suggestions depending on
where the user presses TAB. If no predictor is set for a command, it's sub-commands are
used. Otherwise it defaults to predict.Files
.
There are a few canonical predictors to help you get started:
predict.Anything
predict.Cached
predict.Dirs
predict.Files
predict.Func
predict.Nothing
predict.Or
predict.ScopedCache
predict.Set
Testing
To make testing easy, the cmptest
package provides two functions:
func Suggestions(t testing.TB, cp complete.CommandParser, prompt string) []string
func Assert(t *testing.T, cp complete.CommandParser, prompt string, want []string)
A basic example using cobra
would look like:
func TestBasic(t *testing.T) {
cmd := &cobra.Command{
Use: "count",
ValidArgs: []string{"one", "two", "three"},
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: true,
},
}
cmptest.Assert(t, cmpcobra.New(cmd), "count <TAB>", []string{"one", "two", "three"})
}
Troubleshooting
Running your program with COMP_DEBUG=1
will output any logs written with
cmplog.Log("some msg: %v", val)
.
The internal functions use this quite a bit, and you can include your own diagnostic
messages for live troubleshooting.
export COMP_DEBUG=1
mycli <TAB>
complete 2024/09/04 17:19:30 Completing phrase: mycli
complete 2024/09/04 17:19:30 Completing last field:
complete 2024/09/04 17:19:30 Options: [one two three]
complete 2024/09/04 17:19:30 Matches: [one two three]
Motivation for Forking
First, much thanks and credit to posener/complete. It was the first library that
demonstrated self-completion to me many years ago.
I've been using it ever sincce until recently, mostly due to it's v2
version making
decisions that make dynamic, contextual completion hard.
-
Assumptions around certain flags always existing (--help
, and -h
)
- While I agree every CLI should define these, it's not the completion engine's
place to assert.
-
Predictors only having access to their token
- Tab completion should enrich a user's experience, and sometimes this means making
different decisions depending on other parts of the prompt.
As such, this is a fork from v1
. I've had to change a few core ways in how the
library works, and decided to publish the results going forward. You should be able to
use this library by simply changing the import - all of the exported symbols have been
aliased.
Changes
- Removal of
cmd install
in favor of v2's COMP_INSTALL
semantics
New2
and New2F
functions as primary entrypoints
- The concept of a
Parser
that can give wider context to each Predictor
- The concept of a
Commander
that can return a Command
- Enables framework-aware helpers to generate a completion skeleton
- New packages
args
and predict
for scoping and import cycle issues
args.Args.ParsedRoot
contains the result of Parser.Parse()
predict.Cached
to re-use values that may need a network or expensive call to
generate
- New packages
cmptest
and cmplog
for easier testing
- New package
cmpcobra
for generating completion from cobra
programs