1package commands
2
3import (
4 "sort"
5 "strings"
6
7 "github.com/spf13/cobra"
8
9 "github.com/MichaelMure/git-bug/bridge"
10 "github.com/MichaelMure/git-bug/bridge/core/auth"
11 "github.com/MichaelMure/git-bug/bug"
12 "github.com/MichaelMure/git-bug/cache"
13 _select "github.com/MichaelMure/git-bug/commands/select"
14)
15
16type validArgsFunction func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective)
17
18func completionHandlerError(err error) (completions []string, directives cobra.ShellCompDirective) {
19 return nil, cobra.ShellCompDirectiveError
20}
21
22func completeBridge(env *Env) validArgsFunction {
23 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
24 if len(args) > 0 {
25 return nil, cobra.ShellCompDirectiveNoFileComp
26 }
27 if err := loadBackend(env)(cmd, args); err != nil {
28 return completionHandlerError(err)
29 }
30 defer func() {
31 _ = env.backend.Close()
32 }()
33
34 bridges, err := bridge.ConfiguredBridges(env.backend)
35 if err != nil {
36 return completionHandlerError(err)
37 }
38
39 completions = make([]string, len(bridges))
40 for i, bridge := range bridges {
41 completions[i] = bridge + "\t" + "Bridge"
42 }
43
44 return completions, cobra.ShellCompDirectiveDefault
45 }
46}
47
48func completeBridgeAuth(env *Env) validArgsFunction {
49 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
50 if len(args) > 0 {
51 return nil, cobra.ShellCompDirectiveNoFileComp
52 }
53 if err := loadBackend(env)(cmd, args); err != nil {
54 return completionHandlerError(err)
55 }
56 defer func() {
57 _ = env.backend.Close()
58 }()
59
60 creds, err := auth.List(env.backend)
61 if err != nil {
62 return completionHandlerError(err)
63 }
64
65 completions = make([]string, len(creds))
66 for i, cred := range creds {
67 meta := make([]string, 0, len(cred.Metadata()))
68 for k, v := range cred.Metadata() {
69 meta = append(meta, k+":"+v)
70 }
71 sort.Strings(meta)
72 metaFmt := strings.Join(meta, ",")
73
74 completions[i] = cred.ID().Human() + "\t" + cred.Target() + " " + string(cred.Kind()) + " " + metaFmt
75 }
76
77 return completions, cobra.ShellCompDirectiveDefault
78 }
79}
80
81func completeBug(env *Env) validArgsFunction {
82 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
83 if len(args) > 0 {
84 return nil, cobra.ShellCompDirectiveNoFileComp
85 }
86 if err := loadBackend(env)(cmd, args); err != nil {
87 return completionHandlerError(err)
88 }
89 defer func() {
90 _ = env.backend.Close()
91 }()
92
93 allIds := env.backend.AllBugsIds()
94 bugExcerpt := make([]*cache.BugExcerpt, len(allIds))
95 for i, id := range allIds {
96 var err error
97 bugExcerpt[i], err = env.backend.ResolveBugExcerpt(id)
98 if err != nil {
99 return completionHandlerError(err)
100 }
101 }
102
103 completions = make([]string, len(allIds))
104 for i, id := range allIds {
105 completions[i] = id.Human() + "\t" + bugExcerpt[i].Title
106 }
107 return completions, cobra.ShellCompDirectiveDefault
108 }
109}
110
111func completeBugAndLabels(env *Env, addOrRemove bool) validArgsFunction {
112 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
113 if len(args) == 0 {
114 return completeBug(env)(cmd, args, toComplete)
115 }
116
117 if err := loadBackend(env)(cmd, args); err != nil {
118 return completionHandlerError(err)
119 }
120 defer func() {
121 _ = env.backend.Close()
122 }()
123
124 b, args, err := _select.ResolveBug(env.backend, args)
125 if err != nil {
126 return completionHandlerError(err)
127 }
128
129 snap := b.Snapshot()
130
131 seenLabels := map[bug.Label]bool{}
132 for _, label := range args {
133 seenLabels[bug.Label(label)] = addOrRemove
134 }
135
136 var labels []bug.Label
137 if addOrRemove {
138 for _, label := range snap.Labels {
139 seenLabels[label] = true
140 }
141
142 allLabels := env.backend.ValidLabels()
143 labels = make([]bug.Label, 0, len(allLabels))
144 for _, label := range allLabels {
145 if !seenLabels[label] {
146 labels = append(labels, label)
147 }
148 }
149 } else {
150 labels = make([]bug.Label, 0, len(snap.Labels))
151 for _, label := range snap.Labels {
152 if seenLabels[label] {
153 labels = append(labels, label)
154 }
155 }
156 }
157
158 completions = make([]string, len(labels))
159 for i, label := range labels {
160 completions[i] = string(label) + "\t" + "Label"
161 }
162
163 return completions, cobra.ShellCompDirectiveDefault
164 }
165}
166
167func completeFrom(choices []string) validArgsFunction {
168 return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
169 return choices, cobra.ShellCompDirectiveDefault
170 }
171}
172
173func completeGitRemote(env *Env) validArgsFunction {
174 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
175 if len(args) > 0 {
176 return nil, cobra.ShellCompDirectiveNoFileComp
177 }
178 if err := loadBackend(env)(cmd, args); err != nil {
179 return completionHandlerError(err)
180 }
181 defer func() {
182 _ = env.backend.Close()
183 }()
184
185 remoteMap, err := env.backend.GetRemotes()
186 if err != nil {
187 return completionHandlerError(err)
188 }
189 completions = make([]string, 0, len(remoteMap))
190 for remote, url := range remoteMap {
191 completions = append(completions, remote+"\t"+"Remote: "+url)
192 }
193 sort.Strings(completions)
194 return completions, cobra.ShellCompDirectiveDefault
195 }
196}
197
198func completeLabel(env *Env) validArgsFunction {
199 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
200 if len(args) > 0 {
201 return nil, cobra.ShellCompDirectiveNoFileComp
202 }
203 if err := loadBackend(env)(cmd, args); err != nil {
204 return completionHandlerError(err)
205 }
206 defer func() {
207 _ = env.backend.Close()
208 }()
209
210 labels := env.backend.ValidLabels()
211 completions = make([]string, len(labels))
212 for i, label := range labels {
213 completions[i] = string(label) + "\t" + "Label"
214 }
215 return completions, cobra.ShellCompDirectiveDefault
216 }
217}
218
219func completeLs(env *Env) validArgsFunction {
220 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
221 if strings.HasPrefix(toComplete, "status:") {
222 completions = append(completions, "status:open\tOpen bugs")
223 completions = append(completions, "status:closed\tClosed bugs")
224 return completions, cobra.ShellCompDirectiveDefault
225 }
226
227 byPerson := []string{"author:", "participant:", "actor:"}
228 byLabel := []string{"label:", "no:"}
229 needBackend := false
230 for _, key := range append(byPerson, byLabel...) {
231 if strings.HasPrefix(toComplete, key) {
232 needBackend = true
233 }
234 }
235
236 if needBackend {
237 if err := loadBackend(env)(cmd, args); err != nil {
238 return completionHandlerError(err)
239 }
240 defer func() {
241 _ = env.backend.Close()
242 }()
243 }
244
245 for _, key := range byPerson {
246 if !strings.HasPrefix(toComplete, key) {
247 continue
248 }
249 ids := env.backend.AllIdentityIds()
250 completions = make([]string, len(ids))
251 for i, id := range ids {
252 user, err := env.backend.ResolveIdentityExcerpt(id)
253 if err != nil {
254 return completionHandlerError(err)
255 }
256 var handle string
257 if user.Login != "" {
258 handle = user.Login
259 } else {
260 // "author:John Doe" does not work yet, so use the first name.
261 handle = strings.Split(user.Name, " ")[0]
262 }
263 completions[i] = key + handle + "\t" + user.DisplayName()
264 }
265 return completions, cobra.ShellCompDirectiveDefault
266 }
267
268 for _, key := range byLabel {
269 if !strings.HasPrefix(toComplete, key) {
270 continue
271 }
272 labels := env.backend.ValidLabels()
273 completions = make([]string, len(labels))
274 for i, label := range labels {
275 completions[i] = key + string(label)
276 }
277 return completions, cobra.ShellCompDirectiveDefault
278 }
279
280 completions = []string{
281 "actor:\tFilter by actor",
282 "author:\tFilter by author",
283 "label:\tFilter by label",
284 "no:\tExclude bugs by label",
285 "participant:\tFilter by participant",
286 "status:\tFilter by open/close status",
287 "title:\tFilter by title",
288 }
289 return completions, cobra.ShellCompDirectiveNoSpace
290 }
291}
292
293func completeUser(env *Env) validArgsFunction {
294 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
295 if len(args) > 0 {
296 return nil, cobra.ShellCompDirectiveNoFileComp
297 }
298
299 if err := loadBackend(env)(cmd, args); err != nil {
300 return completionHandlerError(err)
301 }
302 defer func() {
303 _ = env.backend.Close()
304 }()
305
306 ids := env.backend.AllIdentityIds()
307 completions = make([]string, len(ids))
308 for i, id := range ids {
309 user, err := env.backend.ResolveIdentityExcerpt(id)
310 if err != nil {
311 return completionHandlerError(err)
312 }
313 completions[i] = user.Id.Human() + "\t" + user.DisplayName()
314 }
315 return completions, cobra.ShellCompDirectiveDefault
316 }
317}
318
319func completeUserForQuery(env *Env) validArgsFunction {
320 return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
321 if len(args) > 0 {
322 return nil, cobra.ShellCompDirectiveNoFileComp
323 }
324
325 if err := loadBackend(env)(cmd, args); err != nil {
326 return completionHandlerError(err)
327 }
328 defer func() {
329 _ = env.backend.Close()
330 }()
331
332 ids := env.backend.AllIdentityIds()
333 completions = make([]string, len(ids))
334 for i, id := range ids {
335 user, err := env.backend.ResolveIdentityExcerpt(id)
336 if err != nil {
337 return completionHandlerError(err)
338 }
339 var handle string
340 if user.Login != "" {
341 handle = user.Login
342 } else {
343 // "author:John Doe" does not work yet, so use the first name.
344 handle = strings.Split(user.Name, " ")[0]
345 }
346 completions[i] = handle + "\t" + user.DisplayName()
347 }
348 return completions, cobra.ShellCompDirectiveDefault
349 }
350}