Fix a logic lookup bug that was kind enough to surface at the good

moment.
This commit is contained in:
maxlandon 2023-11-02 17:43:35 +01:00
parent f5848b646b
commit 5aadb0d2bd
No known key found for this signature in database
GPG key ID: 2DE5C14975A86900
2 changed files with 30 additions and 7 deletions

View file

@ -167,13 +167,27 @@ func (c *Command) GetFlagCompletionFunc(flag *pflag.Flag) (func(cmd *Command, ar
} }
// GetFlagCompletionByName returns the completion function for the given flag in the command by name, if available. // GetFlagCompletionByName returns the completion function for the given flag in the command by name, if available.
// If the flag is not found in the command's local flags, it looks into the persistent flags, which might belong to one of the command's parents.
func (c *Command) GetFlagCompletionFuncByName(flagName string) (func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective), bool) { func (c *Command) GetFlagCompletionFuncByName(flagName string) (func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective), bool) {
flag := c.Flags().Lookup(flagName) // Attempt to find it in the local flags.
if flag == nil { if flag := c.Flags().Lookup(flagName); flag != nil {
return nil, false return c.GetFlagCompletionFunc(flag)
} }
return c.GetFlagCompletionFunc(flag) // Or try to find it in the "command-specific" persistent flags.
if flag := c.PersistentFlags().Lookup(flagName); flag != nil {
return c.GetFlagCompletionFunc(flag)
}
// Else, check all persistent flags belonging to one of the parents.
// This ensures that we won't return the completion function of a
// parent's LOCAL flag.
if flag := c.InheritedFlags().Lookup(flagName); flag != nil {
return c.GetFlagCompletionFunc(flag)
}
// No flag exists either locally, or as one of the parent persistent flags.
return nil, false
} }
// initializeCompletionStorage is (and should be) called in all // initializeCompletionStorage is (and should be) called in all

View file

@ -3581,21 +3581,30 @@ func TestGetFlagCompletion(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun} rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.Flags().String("rootflag", "", "root flag") rootCmd.Flags().String("rootflag", "", "root flag")
_ = rootCmd.RegisterFlagCompletionFunc("rootflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { err := rootCmd.RegisterFlagCompletionFunc("rootflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return []string{"rootvalue"}, ShellCompDirectiveKeepOrder return []string{"rootvalue"}, ShellCompDirectiveKeepOrder
}) })
if err != nil {
t.Error(err)
}
rootCmd.PersistentFlags().String("persistentflag", "", "persistent flag") rootCmd.PersistentFlags().String("persistentflag", "", "persistent flag")
_ = rootCmd.RegisterFlagCompletionFunc("persistentflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { err = rootCmd.RegisterFlagCompletionFunc("persistentflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return []string{"persistentvalue"}, ShellCompDirectiveDefault return []string{"persistentvalue"}, ShellCompDirectiveDefault
}) })
if err != nil {
t.Error(err)
}
childCmd := &Command{Use: "child", Run: emptyRun} childCmd := &Command{Use: "child", Run: emptyRun}
childCmd.Flags().String("childflag", "", "child flag") childCmd.Flags().String("childflag", "", "child flag")
_ = childCmd.RegisterFlagCompletionFunc("childflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { err = childCmd.RegisterFlagCompletionFunc("childflag", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return []string{"childvalue"}, ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace return []string{"childvalue"}, ShellCompDirectiveNoFileComp | ShellCompDirectiveNoSpace
}) })
if err != nil {
t.Error(err)
}
rootCmd.AddCommand(childCmd) rootCmd.AddCommand(childCmd)