@@ -117,15 +117,31 @@ type CompletionOptions struct {
117
117
HiddenDefaultCmd bool
118
118
}
119
119
120
+ // Completion is a string that can be used for completions
121
+ //
122
+ // two formats are supported:
123
+ // - the completion choice
124
+ // - the completion choice with a textual description (separated by a TAB).
125
+ //
126
+ // [CompletionWithDesc] can be used to create a completion string with a textual description.
127
+ //
128
+ // Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used.
129
+ type Completion = string
130
+
120
131
// CompletionFunc is a function that provides completion results.
121
- type CompletionFunc func (cmd * Command , args []string , toComplete string ) ([]string , ShellCompDirective )
132
+ type CompletionFunc func (cmd * Command , args []string , toComplete string ) ([]Completion , ShellCompDirective )
133
+
134
+ // CompletionWithDesc returns a [Completion] with a description by using the TAB delimited format.
135
+ func CompletionWithDesc (choice string , description string ) Completion {
136
+ return choice + "\t " + description
137
+ }
122
138
123
139
// NoFileCompletions can be used to disable file completion for commands that should
124
140
// not trigger file completions.
125
141
//
126
142
// This method satisfies [CompletionFunc].
127
143
// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].
128
- func NoFileCompletions (cmd * Command , args []string , toComplete string ) ([]string , ShellCompDirective ) {
144
+ func NoFileCompletions (cmd * Command , args []string , toComplete string ) ([]Completion , ShellCompDirective ) {
129
145
return nil , ShellCompDirectiveNoFileComp
130
146
}
131
147
@@ -134,8 +150,8 @@ func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string
134
150
//
135
151
// This method returns a function that satisfies [CompletionFunc]
136
152
// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].
137
- func FixedCompletions (choices []string , directive ShellCompDirective ) CompletionFunc {
138
- return func (cmd * Command , args []string , toComplete string ) ([]string , ShellCompDirective ) {
153
+ func FixedCompletions (choices []Completion , directive ShellCompDirective ) CompletionFunc {
154
+ return func (cmd * Command , args []string , toComplete string ) ([]Completion , ShellCompDirective ) {
139
155
return choices , directive
140
156
}
141
157
}
@@ -290,7 +306,7 @@ type SliceValue interface {
290
306
GetSlice () []string
291
307
}
292
308
293
- func (c * Command ) getCompletions (args []string ) (* Command , []string , ShellCompDirective , error ) {
309
+ func (c * Command ) getCompletions (args []string ) (* Command , []Completion , ShellCompDirective , error ) {
294
310
// The last argument, which is not completely typed by the user,
295
311
// should not be part of the list of arguments
296
312
toComplete := args [len (args )- 1 ]
@@ -318,7 +334,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
318
334
}
319
335
if err != nil {
320
336
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
321
- return c , []string {}, ShellCompDirectiveDefault , fmt .Errorf ("unable to find a command for arguments: %v" , trimmedArgs )
337
+ return c , []Completion {}, ShellCompDirectiveDefault , fmt .Errorf ("unable to find a command for arguments: %v" , trimmedArgs )
322
338
}
323
339
finalCmd .ctx = c .ctx
324
340
@@ -348,7 +364,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
348
364
349
365
// Parse the flags early so we can check if required flags are set
350
366
if err = finalCmd .ParseFlags (finalArgs ); err != nil {
351
- return finalCmd , []string {}, ShellCompDirectiveDefault , fmt .Errorf ("Error while parsing flags from args %v: %s" , finalArgs , err .Error ())
367
+ return finalCmd , []Completion {}, ShellCompDirectiveDefault , fmt .Errorf ("Error while parsing flags from args %v: %s" , finalArgs , err .Error ())
352
368
}
353
369
354
370
realArgCount := finalCmd .Flags ().NArg ()
@@ -360,14 +376,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
360
376
if flagErr != nil {
361
377
// If error type is flagCompError and we don't want flagCompletion we should ignore the error
362
378
if _ , ok := flagErr .(* flagCompError ); ! (ok && ! flagCompletion ) {
363
- return finalCmd , []string {}, ShellCompDirectiveDefault , flagErr
379
+ return finalCmd , []Completion {}, ShellCompDirectiveDefault , flagErr
364
380
}
365
381
}
366
382
367
383
// Look for the --help or --version flags. If they are present,
368
384
// there should be no further completions.
369
385
if helpOrVersionFlagPresent (finalCmd ) {
370
- return finalCmd , []string {}, ShellCompDirectiveNoFileComp , nil
386
+ return finalCmd , []Completion {}, ShellCompDirectiveNoFileComp , nil
371
387
}
372
388
373
389
// We only remove the flags from the arguments if DisableFlagParsing is not set.
@@ -396,11 +412,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
396
412
return finalCmd , subDir , ShellCompDirectiveFilterDirs , nil
397
413
}
398
414
// Directory completion
399
- return finalCmd , []string {}, ShellCompDirectiveFilterDirs , nil
415
+ return finalCmd , []Completion {}, ShellCompDirectiveFilterDirs , nil
400
416
}
401
417
}
402
418
403
- var completions []string
419
+ var completions []Completion
404
420
var directive ShellCompDirective
405
421
406
422
// Enforce flag groups before doing flag completions
@@ -486,7 +502,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
486
502
for _ , subCmd := range finalCmd .Commands () {
487
503
if subCmd .IsAvailableCommand () || subCmd == finalCmd .helpCommand {
488
504
if strings .HasPrefix (subCmd .Name (), toComplete ) {
489
- completions = append (completions , fmt . Sprintf ( "%s \t %s" , subCmd .Name (), subCmd .Short ))
505
+ completions = append (completions , CompletionWithDesc ( subCmd .Name (), subCmd .Short ))
490
506
}
491
507
directive = ShellCompDirectiveNoFileComp
492
508
}
@@ -542,7 +558,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
542
558
if completionFn != nil {
543
559
// Go custom completion defined for this flag or command.
544
560
// Call the registered completion function to get the completions.
545
- var comps []string
561
+ var comps []Completion
546
562
comps , directive = completionFn (finalCmd , finalArgs , toComplete )
547
563
completions = append (completions , comps ... )
548
564
}
@@ -562,16 +578,16 @@ func helpOrVersionFlagPresent(cmd *Command) bool {
562
578
return false
563
579
}
564
580
565
- func getFlagNameCompletions (flag * pflag.Flag , toComplete string ) []string {
581
+ func getFlagNameCompletions (flag * pflag.Flag , toComplete string ) []Completion {
566
582
if nonCompletableFlag (flag ) {
567
- return []string {}
583
+ return []Completion {}
568
584
}
569
585
570
- var completions []string
586
+ var completions []Completion
571
587
flagName := "--" + flag .Name
572
588
if strings .HasPrefix (flagName , toComplete ) {
573
589
// Flag without the =
574
- completions = append (completions , fmt . Sprintf ( "%s \t %s" , flagName , flag .Usage ))
590
+ completions = append (completions , CompletionWithDesc ( flagName , flag .Usage ))
575
591
576
592
// Why suggest both long forms: --flag and --flag= ?
577
593
// This forces the user to *always* have to type either an = or a space after the flag name.
@@ -583,20 +599,20 @@ func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
583
599
// if len(flag.NoOptDefVal) == 0 {
584
600
// // Flag requires a value, so it can be suffixed with =
585
601
// flagName += "="
586
- // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
602
+ // completions = append(completions, CompletionWithDesc( flagName, flag.Usage))
587
603
// }
588
604
}
589
605
590
606
flagName = "-" + flag .Shorthand
591
607
if len (flag .Shorthand ) > 0 && strings .HasPrefix (flagName , toComplete ) {
592
- completions = append (completions , fmt . Sprintf ( "%s \t %s" , flagName , flag .Usage ))
608
+ completions = append (completions , CompletionWithDesc ( flagName , flag .Usage ))
593
609
}
594
610
595
611
return completions
596
612
}
597
613
598
- func completeRequireFlags (finalCmd * Command , toComplete string ) []string {
599
- var completions []string
614
+ func completeRequireFlags (finalCmd * Command , toComplete string ) []Completion {
615
+ var completions []Completion
600
616
601
617
doCompleteRequiredFlags := func (flag * pflag.Flag ) {
602
618
if _ , present := flag .Annotations [BashCompOneRequiredFlag ]; present {
0 commit comments