435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
// 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"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/posener/complete/cmd"
|
|
"github.com/posener/complete/match"
|
|
)
|
|
|
|
const (
|
|
envLine = "COMP_LINE"
|
|
envPoint = "COMP_POINT"
|
|
envDebug = "COMP_DEBUG"
|
|
)
|
|
|
|
// Complete structs define completion for a command with CLI options
|
|
type Complete struct {
|
|
Command Command
|
|
cmd.CLI
|
|
Out io.Writer
|
|
}
|
|
|
|
// 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},
|
|
Out: os.Stdout,
|
|
}
|
|
}
|
|
|
|
// 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, point, ok := getEnv()
|
|
if !ok {
|
|
// make sure flags parsed,
|
|
// in case they were not added in the main program
|
|
return c.CLI.Run()
|
|
}
|
|
|
|
if point >= 0 && point < len(line) {
|
|
line = line[:point]
|
|
}
|
|
|
|
Log("Completing phrase: %s", line)
|
|
a := newArgs(line)
|
|
Log("Completing last field: %s", a.Last)
|
|
options := c.Command.Predict(a)
|
|
Log("Options: %s", options)
|
|
|
|
// 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)
|
|
return true
|
|
}
|
|
|
|
func getEnv() (line string, point int, ok bool) {
|
|
line = os.Getenv(envLine)
|
|
if line == "" {
|
|
return
|
|
}
|
|
point, err := strconv.Atoi(os.Getenv(envPoint))
|
|
if err != nil {
|
|
// If failed parsing point for some reason, set it to point
|
|
// on the end of the line.
|
|
Log("Failed parsing point %s: %v", os.Getenv(envPoint), err)
|
|
point = len(line)
|
|
}
|
|
return line, point, true
|
|
}
|
|
|
|
func (c *Complete) output(options []string) {
|
|
// stdout of program defines the complete options
|
|
for _, option := range options {
|
|
fmt.Fprintln(c.Out, option)
|
|
}
|
|
}
|