2017-07-18 14:15:54 +00:00
|
|
|
// Package complete provides a tool for bash writing bash completion in go.
|
|
|
|
//
|
|
|
|
// Writing bash completion scripts is a hard work. This package provides an easy way
|
|
|
|
// to create bash completion scripts for any command, and also an easy way to install/uninstall
|
|
|
|
// the completion of the command.
|
|
|
|
package complete
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2017-11-07 16:57:05 +00:00
|
|
|
"io"
|
2017-07-18 14:15:54 +00:00
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/posener/complete/cmd"
|
2017-11-07 16:57:05 +00:00
|
|
|
"github.com/posener/complete/match"
|
2017-07-18 14:15:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
envComplete = "COMP_LINE"
|
|
|
|
envDebug = "COMP_DEBUG"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Complete structs define completion for a command with CLI options
|
|
|
|
type Complete struct {
|
|
|
|
Command Command
|
|
|
|
cmd.CLI
|
2017-11-07 16:57:05 +00:00
|
|
|
Out io.Writer
|
2017-07-18 14:15:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new complete command.
|
|
|
|
// name is the name of command we want to auto complete.
|
|
|
|
// IMPORTANT: it must be the same name - if the auto complete
|
|
|
|
// completes the 'go' command, name must be equal to "go".
|
|
|
|
// command is the struct of the command completion.
|
|
|
|
func New(name string, command Command) *Complete {
|
|
|
|
return &Complete{
|
|
|
|
Command: command,
|
|
|
|
CLI: cmd.CLI{Name: name},
|
2017-11-07 16:57:05 +00:00
|
|
|
Out: os.Stdout,
|
2017-07-18 14:15:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run runs the completion and add installation flags beforehand.
|
|
|
|
// The flags are added to the main flag CommandLine variable.
|
|
|
|
func (c *Complete) Run() bool {
|
|
|
|
c.AddFlags(nil)
|
|
|
|
flag.Parse()
|
|
|
|
return c.Complete()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Complete a command from completion line in environment variable,
|
|
|
|
// and print out the complete options.
|
|
|
|
// returns success if the completion ran or if the cli matched
|
|
|
|
// any of the given flags, false otherwise
|
|
|
|
// For installation: it assumes that flags were added and parsed before
|
|
|
|
// it was called.
|
|
|
|
func (c *Complete) Complete() bool {
|
|
|
|
line, ok := getLine()
|
|
|
|
if !ok {
|
|
|
|
// make sure flags parsed,
|
|
|
|
// in case they were not added in the main program
|
|
|
|
return c.CLI.Run()
|
|
|
|
}
|
|
|
|
Log("Completing line: %s", line)
|
|
|
|
a := newArgs(line)
|
2017-11-07 16:57:05 +00:00
|
|
|
Log("Completing last field: %s", a.Last)
|
2017-07-18 14:15:54 +00:00
|
|
|
options := c.Command.Predict(a)
|
2017-11-07 16:57:05 +00:00
|
|
|
Log("Options: %s", options)
|
2017-07-18 14:15:54 +00:00
|
|
|
|
2017-11-07 16:57:05 +00:00
|
|
|
// filter only options that match the last argument
|
|
|
|
matches := []string{}
|
|
|
|
for _, option := range options {
|
|
|
|
if match.Prefix(option, a.Last) {
|
|
|
|
matches = append(matches, option)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Log("Matches: %s", matches)
|
|
|
|
c.output(matches)
|
2017-07-18 14:15:54 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2017-11-07 16:57:05 +00:00
|
|
|
func getLine() (string, bool) {
|
2017-07-18 14:15:54 +00:00
|
|
|
line := os.Getenv(envComplete)
|
|
|
|
if line == "" {
|
2017-11-07 16:57:05 +00:00
|
|
|
return "", false
|
2017-07-18 14:15:54 +00:00
|
|
|
}
|
2017-11-07 16:57:05 +00:00
|
|
|
return line, true
|
2017-07-18 14:15:54 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 16:57:05 +00:00
|
|
|
func (c *Complete) output(options []string) {
|
2017-07-18 14:15:54 +00:00
|
|
|
// stdout of program defines the complete options
|
|
|
|
for _, option := range options {
|
2017-11-07 16:57:05 +00:00
|
|
|
fmt.Fprintln(c.Out, option)
|
2017-07-18 14:15:54 +00:00
|
|
|
}
|
|
|
|
}
|