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