github.com/alexandrestein/complete@v1.1.2-0.20180313112007-cc6c1c3aa2ce/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 }