github.com/vlad2095/complete@v1.1.2/command.go (about) 1 package complete 2 3 // Command represents a command line 4 // It holds the data that enables auto completion of command line 5 // Command can also be a sub command. 6 type Command struct { 7 // Sub is map of sub commands of the current command 8 // The key refer to the sub command name, and the value is it's 9 // Command descriptive struct. 10 Sub Commands 11 12 // Flags is a map of flags that the command accepts. 13 // The key is the flag name, and the value is it's predictions. 14 Flags Flags 15 16 // GlobalFlags is a map of flags that the command accepts. 17 // Global flags that can appear also after a sub command. 18 GlobalFlags Flags 19 20 // Args are extra arguments that the command accepts, those who are 21 // given without any flag before. 22 Args Predictor 23 } 24 25 // Predict returns all possible predictions for args according to the command struct 26 func (c *Command) Predict(a Args) []string { 27 options, _ := c.predict(a) 28 return options 29 } 30 31 // Commands is the type of Sub member, it maps a command name to a command struct 32 type Commands map[string]Command 33 34 // Predict completion of sub command names names according to command line arguments 35 func (c Commands) Predict(a Args) (prediction []string) { 36 for sub := range c { 37 prediction = append(prediction, sub) 38 } 39 return 40 } 41 42 // Flags is the type Flags of the Flags member, it maps a flag name to the flag predictions. 43 type Flags map[string]Predictor 44 45 // Predict completion of flags names according to command line arguments 46 func (f Flags) Predict(a Args) (prediction []string) { 47 for flag := range f { 48 // If the flag starts with a hyphen, we avoid emitting the prediction 49 // unless the last typed arg contains a hyphen as well. 50 flagHyphenStart := len(flag) != 0 && flag[0] == '-' 51 lastHyphenStart := len(a.Last) != 0 && a.Last[0] == '-' 52 if flagHyphenStart && !lastHyphenStart { 53 continue 54 } 55 prediction = append(prediction, flag) 56 } 57 return 58 } 59 60 // predict options 61 // only is set to true if no more options are allowed to be returned 62 // those are in cases of special flag that has specific completion arguments, 63 // and other flags or sub commands can't come after it. 64 func (c *Command) predict(a Args) (options []string, only bool) { 65 66 // search sub commands for predictions first 67 subCommandFound := false 68 for i, arg := range a.Completed { 69 if cmd, ok := c.Sub[arg]; ok { 70 subCommandFound = true 71 72 // recursive call for sub command 73 options, only = cmd.predict(a.from(i)) 74 if only { 75 return 76 } 77 78 // We matched so stop searching. Continuing to search can accidentally 79 // match a subcommand with current set of commands, see issue #46. 80 break 81 } 82 } 83 84 // if last completed word is a global flag that we need to complete 85 if predictor, ok := c.GlobalFlags[a.LastCompleted]; ok && predictor != nil { 86 Log("Predicting according to global flag %s", a.LastCompleted) 87 return predictor.Predict(a), true 88 } 89 90 options = append(options, c.GlobalFlags.Predict(a)...) 91 92 // if a sub command was entered, we won't add the parent command 93 // completions and we return here. 94 if subCommandFound { 95 return 96 } 97 98 // if last completed word is a command flag that we need to complete 99 if predictor, ok := c.Flags[a.LastCompleted]; ok && predictor != nil { 100 Log("Predicting according to flag %s", a.LastCompleted) 101 return predictor.Predict(a), true 102 } 103 104 options = append(options, c.Sub.Predict(a)...) 105 options = append(options, c.Flags.Predict(a)...) 106 if c.Args != nil { 107 options = append(options, c.Args.Predict(a)...) 108 } 109 110 return 111 }