helper_completion.go

  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}