@@ -117,15 +117,31 @@ type CompletionOptions struct {
117117 HiddenDefaultCmd bool
118118}
119119
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+
120131// 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+ }
122138
123139// NoFileCompletions can be used to disable file completion for commands that should
124140// not trigger file completions.
125141//
126142// This method satisfies [CompletionFunc].
127143// 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 ) {
129145 return nil , ShellCompDirectiveNoFileComp
130146}
131147
@@ -134,8 +150,8 @@ func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string
134150//
135151// This method returns a function that satisfies [CompletionFunc]
136152// 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 ) {
139155 return choices , directive
140156 }
141157}
@@ -290,7 +306,7 @@ type SliceValue interface {
290306 GetSlice () []string
291307}
292308
293- func (c * Command ) getCompletions (args []string ) (* Command , []string , ShellCompDirective , error ) {
309+ func (c * Command ) getCompletions (args []string ) (* Command , []Completion , ShellCompDirective , error ) {
294310 // The last argument, which is not completely typed by the user,
295311 // should not be part of the list of arguments
296312 toComplete := args [len (args )- 1 ]
@@ -318,7 +334,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
318334 }
319335 if err != nil {
320336 // 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 )
322338 }
323339 finalCmd .ctx = c .ctx
324340
@@ -348,7 +364,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
348364
349365 // Parse the flags early so we can check if required flags are set
350366 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 ())
352368 }
353369
354370 realArgCount := finalCmd .Flags ().NArg ()
@@ -360,14 +376,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
360376 if flagErr != nil {
361377 // If error type is flagCompError and we don't want flagCompletion we should ignore the error
362378 if _ , ok := flagErr .(* flagCompError ); ! (ok && ! flagCompletion ) {
363- return finalCmd , []string {}, ShellCompDirectiveDefault , flagErr
379+ return finalCmd , []Completion {}, ShellCompDirectiveDefault , flagErr
364380 }
365381 }
366382
367383 // Look for the --help or --version flags. If they are present,
368384 // there should be no further completions.
369385 if helpOrVersionFlagPresent (finalCmd ) {
370- return finalCmd , []string {}, ShellCompDirectiveNoFileComp , nil
386+ return finalCmd , []Completion {}, ShellCompDirectiveNoFileComp , nil
371387 }
372388
373389 // 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
396412 return finalCmd , subDir , ShellCompDirectiveFilterDirs , nil
397413 }
398414 // Directory completion
399- return finalCmd , []string {}, ShellCompDirectiveFilterDirs , nil
415+ return finalCmd , []Completion {}, ShellCompDirectiveFilterDirs , nil
400416 }
401417 }
402418
403- var completions []string
419+ var completions []Completion
404420 var directive ShellCompDirective
405421
406422 // Enforce flag groups before doing flag completions
@@ -486,7 +502,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
486502 for _ , subCmd := range finalCmd .Commands () {
487503 if subCmd .IsAvailableCommand () || subCmd == finalCmd .helpCommand {
488504 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 ))
490506 }
491507 directive = ShellCompDirectiveNoFileComp
492508 }
@@ -542,7 +558,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
542558 if completionFn != nil {
543559 // Go custom completion defined for this flag or command.
544560 // Call the registered completion function to get the completions.
545- var comps []string
561+ var comps []Completion
546562 comps , directive = completionFn (finalCmd , finalArgs , toComplete )
547563 completions = append (completions , comps ... )
548564 }
@@ -562,16 +578,16 @@ func helpOrVersionFlagPresent(cmd *Command) bool {
562578 return false
563579}
564580
565- func getFlagNameCompletions (flag * pflag.Flag , toComplete string ) []string {
581+ func getFlagNameCompletions (flag * pflag.Flag , toComplete string ) []Completion {
566582 if nonCompletableFlag (flag ) {
567- return []string {}
583+ return []Completion {}
568584 }
569585
570- var completions []string
586+ var completions []Completion
571587 flagName := "--" + flag .Name
572588 if strings .HasPrefix (flagName , toComplete ) {
573589 // Flag without the =
574- completions = append (completions , fmt . Sprintf ( "%s \t %s" , flagName , flag .Usage ))
590+ completions = append (completions , CompletionWithDesc ( flagName , flag .Usage ))
575591
576592 // Why suggest both long forms: --flag and --flag= ?
577593 // 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 {
583599 // if len(flag.NoOptDefVal) == 0 {
584600 // // Flag requires a value, so it can be suffixed with =
585601 // flagName += "="
586- // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
602+ // completions = append(completions, CompletionWithDesc( flagName, flag.Usage))
587603 // }
588604 }
589605
590606 flagName = "-" + flag .Shorthand
591607 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 ))
593609 }
594610
595611 return completions
596612}
597613
598- func completeRequireFlags (finalCmd * Command , toComplete string ) []string {
599- var completions []string
614+ func completeRequireFlags (finalCmd * Command , toComplete string ) []Completion {
615+ var completions []Completion
600616
601617 doCompleteRequiredFlags := func (flag * pflag.Flag ) {
602618 if _ , present := flag .Annotations [BashCompOneRequiredFlag ]; present {
0 commit comments