]>
Commit | Line | Data |
---|---|---|
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 | } |