github.com/Arneball/complete@v1.1.2/complete.go (about)

     1  // Package complete provides a tool for bash writing bash completion in go.
     2  //
     3  // Writing bash completion scripts is a hard work. This package provides an easy way
     4  // to create bash completion scripts for any command, and also an easy way to install/uninstall
     5  // the completion of the command.
     6  package complete
     7  
     8  import (
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  
    14  	"github.com/posener/complete/cmd"
    15  	"github.com/posener/complete/match"
    16  )
    17  
    18  const (
    19  	envComplete = "COMP_LINE"
    20  	envDebug    = "COMP_DEBUG"
    21  )
    22  
    23  // Complete structs define completion for a command with CLI options
    24  type Complete struct {
    25  	Command Command
    26  	cmd.CLI
    27  	Out io.Writer
    28  }
    29  
    30  // New creates a new complete command.
    31  // name is the name of command we want to auto complete.
    32  // IMPORTANT: it must be the same name - if the auto complete
    33  // completes the 'go' command, name must be equal to "go".
    34  // command is the struct of the command completion.
    35  func New(name string, command Command) *Complete {
    36  	return &Complete{
    37  		Command: command,
    38  		CLI:     cmd.CLI{Name: name},
    39  		Out:     os.Stdout,
    40  	}
    41  }
    42  
    43  // Run runs the completion and add installation flags beforehand.
    44  // The flags are added to the main flag CommandLine variable.
    45  func (c *Complete) Run() bool {
    46  	c.AddFlags(nil)
    47  	flag.Parse()
    48  	return c.Complete()
    49  }
    50  
    51  // Complete a command from completion line in environment variable,
    52  // and print out the complete options.
    53  // returns success if the completion ran or if the cli matched
    54  // any of the given flags, false otherwise
    55  // For installation: it assumes that flags were added and parsed before
    56  // it was called.
    57  func (c *Complete) Complete() bool {
    58  	line, ok := getLine()
    59  	if !ok {
    60  		// make sure flags parsed,
    61  		// in case they were not added in the main program
    62  		return c.CLI.Run()
    63  	}
    64  	Log("Completing line: %s", line)
    65  	a := newArgs(line)
    66  	Log("Completing last field: %s", a.Last)
    67  	options := c.Command.Predict(a)
    68  	Log("Options: %s", options)
    69  
    70  	// filter only options that match the last argument
    71  	matches := []string{}
    72  	for _, option := range options {
    73  		if match.Prefix(option, a.Last) {
    74  			matches = append(matches, option)
    75  		}
    76  	}
    77  	Log("Matches: %s", matches)
    78  	c.output(matches)
    79  	return true
    80  }
    81  
    82  func getLine() (string, bool) {
    83  	line := os.Getenv(envComplete)
    84  	if line == "" {
    85  		return "", false
    86  	}
    87  	return line, true
    88  }
    89  
    90  func (c *Complete) output(options []string) {
    91  	// stdout of program defines the complete options
    92  	for _, option := range options {
    93  		fmt.Fprintln(c.Out, option)
    94  	}
    95  }