Started working on Unified API for the various shell completions:
- Moved some general function to a more generic shell_completions file. - Added functions to mark flag as directory completion. - Started making the global functions docs more generic (not bash specific) and added compatibility matrix.
This commit is contained in:
		
				
					committed by
					
						
						Steve Francia
					
				
			
			
				
	
			
			
			
						parent
						
							601d83077b
						
					
				
				
					commit
					e2c45ac9eb
				
			@ -545,51 +545,3 @@ func (c *Command) GenBashCompletionFile(filename string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return c.GenBashCompletion(outFile)
 | 
						return c.GenBashCompletion(outFile)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
 | 
					 | 
				
			||||||
// and causes your command to report an error if invoked without the flag.
 | 
					 | 
				
			||||||
func (c *Command) MarkFlagRequired(name string) error {
 | 
					 | 
				
			||||||
	return MarkFlagRequired(c.Flags(), name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
 | 
					 | 
				
			||||||
// and causes your command to report an error if invoked without the flag.
 | 
					 | 
				
			||||||
func (c *Command) MarkPersistentFlagRequired(name string) error {
 | 
					 | 
				
			||||||
	return MarkFlagRequired(c.PersistentFlags(), name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
 | 
					 | 
				
			||||||
// and causes your command to report an error if invoked without the flag.
 | 
					 | 
				
			||||||
func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
 | 
					 | 
				
			||||||
	return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
 | 
					 | 
				
			||||||
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
 | 
					 | 
				
			||||||
func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
 | 
					 | 
				
			||||||
	return MarkFlagFilename(c.Flags(), name, extensions...)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
 | 
					 | 
				
			||||||
// Generated bash autocompletion will call the bash function f for the flag.
 | 
					 | 
				
			||||||
func (c *Command) MarkFlagCustom(name string, f string) error {
 | 
					 | 
				
			||||||
	return MarkFlagCustom(c.Flags(), name, f)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
 | 
					 | 
				
			||||||
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
 | 
					 | 
				
			||||||
func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
 | 
					 | 
				
			||||||
	return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists.
 | 
					 | 
				
			||||||
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
 | 
					 | 
				
			||||||
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
 | 
					 | 
				
			||||||
	return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists.
 | 
					 | 
				
			||||||
// Generated bash autocompletion will call the bash function f for the flag.
 | 
					 | 
				
			||||||
func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
 | 
					 | 
				
			||||||
	return flags.SetAnnotation(name, BashCompCustom, []string{f})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										85
									
								
								shell_completions.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								shell_completions.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					package cobra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/spf13/pflag"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
 | 
				
			||||||
 | 
					// and causes your command to report an error if invoked without the flag.
 | 
				
			||||||
 | 
					func (c *Command) MarkFlagRequired(name string) error {
 | 
				
			||||||
 | 
						return MarkFlagRequired(c.Flags(), name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
 | 
				
			||||||
 | 
					// and causes your command to report an error if invoked without the flag.
 | 
				
			||||||
 | 
					func (c *Command) MarkPersistentFlagRequired(name string) error {
 | 
				
			||||||
 | 
						return MarkFlagRequired(c.PersistentFlags(), name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
 | 
				
			||||||
 | 
					// and causes your command to report an error if invoked without the flag.
 | 
				
			||||||
 | 
					func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
 | 
				
			||||||
 | 
						return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
 | 
				
			||||||
 | 
					// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
 | 
				
			||||||
 | 
					func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
 | 
				
			||||||
 | 
						return MarkFlagFilename(c.Flags(), name, extensions...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
 | 
				
			||||||
 | 
					// Generated bash autocompletion will call the bash function f for the flag.
 | 
				
			||||||
 | 
					func (c *Command) MarkFlagCustom(name string, f string) error {
 | 
				
			||||||
 | 
						return MarkFlagCustom(c.Flags(), name, f)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkPersistentFlagFilename instructs the various shell completion
 | 
				
			||||||
 | 
					// implementations to limit completions for this persistent flag to the
 | 
				
			||||||
 | 
					// specified extensions (patterns).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: bash, zsh
 | 
				
			||||||
 | 
					func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
 | 
				
			||||||
 | 
						return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagFilename instructs the various shell completion implementations to
 | 
				
			||||||
 | 
					// limit completions for this flag to the specified extensions (patterns).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: bash, zsh
 | 
				
			||||||
 | 
					func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
 | 
				
			||||||
 | 
						return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagCustom instructs the various shell completion implementations to
 | 
				
			||||||
 | 
					// limit completions for this flag to the specified extensions (patterns).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: bash, zsh
 | 
				
			||||||
 | 
					func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
 | 
				
			||||||
 | 
						return flags.SetAnnotation(name, BashCompCustom, []string{f})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagDirname instructs the various shell completion implementations to
 | 
				
			||||||
 | 
					// complete only directories with this named flag.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: zsh
 | 
				
			||||||
 | 
					func (c *Command) MarkFlagDirname(name string) error {
 | 
				
			||||||
 | 
						return MarkFlagDirname(c.Flags(), name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkPersistentFlagDirname instructs the various shell completion
 | 
				
			||||||
 | 
					// implementations to complete only directories with this persistent named flag.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: zsh
 | 
				
			||||||
 | 
					func (c *Command) MarkPersistentFlagDirname(name string) error {
 | 
				
			||||||
 | 
						return MarkFlagDirname(c.PersistentFlags(), name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarkFlagDirname instructs the various shell completion implementations to
 | 
				
			||||||
 | 
					// complete only directories with this specified flag.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Shell Completion compatibility matrix: zsh
 | 
				
			||||||
 | 
					func MarkFlagDirname(flags *pflag.FlagSet, name string) error {
 | 
				
			||||||
 | 
						zshPattern := "-(/)"
 | 
				
			||||||
 | 
						return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -16,6 +16,7 @@ const (
 | 
				
			|||||||
	zshCompArgumentAnnotation   = "cobra_annotations_zsh_completion_argument_annotation"
 | 
						zshCompArgumentAnnotation   = "cobra_annotations_zsh_completion_argument_annotation"
 | 
				
			||||||
	zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion"
 | 
						zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion"
 | 
				
			||||||
	zshCompArgumentWordComp     = "cobra_annotations_zsh_completion_argument_word_completion"
 | 
						zshCompArgumentWordComp     = "cobra_annotations_zsh_completion_argument_word_completion"
 | 
				
			||||||
 | 
						zshCompDirname              = "cobra_annotations_zsh_dirname"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@ -305,16 +306,21 @@ func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func zshCompGenFlagEntryExtras(f *pflag.Flag) string {
 | 
					func zshCompGenFlagEntryExtras(f *pflag.Flag) string {
 | 
				
			||||||
	var extras string
 | 
						if f.NoOptDefVal != "" {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
	globs, pathSpecified := f.Annotations[BashCompFilenameExt]
 | 
						}
 | 
				
			||||||
	if pathSpecified {
 | 
					
 | 
				
			||||||
		extras = ":filename:_files"
 | 
						extras := ":" // allow options for flag (even without assistance)
 | 
				
			||||||
		for _, g := range globs {
 | 
						for key, values := range f.Annotations {
 | 
				
			||||||
			extras = extras + fmt.Sprintf(` -g "%s"`, g)
 | 
							switch key {
 | 
				
			||||||
 | 
							case zshCompDirname:
 | 
				
			||||||
 | 
								extras = fmt.Sprintf(":filename:_files -g %q", values[0])
 | 
				
			||||||
 | 
							case BashCompFilenameExt:
 | 
				
			||||||
 | 
								extras = ":filename:_files"
 | 
				
			||||||
 | 
								for _, pattern := range values {
 | 
				
			||||||
 | 
									extras = extras + fmt.Sprintf(` -g "%s"`, pattern)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if f.NoOptDefVal == "" {
 | 
					 | 
				
			||||||
		extras = ":" // allow option variable without assisting
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return extras
 | 
						return extras
 | 
				
			||||||
 | 
				
			|||||||
@ -214,6 +214,21 @@ func TestGenZshCompletion(t *testing.T) {
 | 
				
			|||||||
				`'1: :\("word1" "word2"\)' \\`,
 | 
									`'1: :\("word1" "word2"\)' \\`,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "directory completion for flag",
 | 
				
			||||||
 | 
								root: func() *Command {
 | 
				
			||||||
 | 
									r := genTestCommand("root", true)
 | 
				
			||||||
 | 
									r.Flags().String("test", "", "test")
 | 
				
			||||||
 | 
									r.PersistentFlags().String("ptest", "", "ptest")
 | 
				
			||||||
 | 
									r.MarkFlagDirname("test")
 | 
				
			||||||
 | 
									r.MarkPersistentFlagDirname("ptest")
 | 
				
			||||||
 | 
									return r
 | 
				
			||||||
 | 
								}(),
 | 
				
			||||||
 | 
								expectedExpressions: []string{
 | 
				
			||||||
 | 
									`--test\[test]:filename:_files -g "-\(/\)"`,
 | 
				
			||||||
 | 
									`--ptest\[ptest]:filename:_files -g "-\(/\)"`,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range tcs {
 | 
						for _, tc := range tcs {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user