Merge pull request #14216 from Luap99/format-completion

shell completion --format: work with pointer functions
This commit is contained in:
OpenShift Merge Robot 2022-05-12 15:32:58 +02:00 committed by GitHub
commit 45e9f1ff09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 15 deletions

View File

@ -992,13 +992,6 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
fields := strings.Split(field[len(field)-1], ".")
f := reflect.ValueOf(o)
for i := 1; i < len(fields); i++ {
val := getActualStructType(f)
if val == nil {
// no struct return nothing to complete
return nil, cobra.ShellCompDirectiveNoFileComp
}
f = *val
// last field get all names to suggest
if i == len(fields)-1 {
suggestions := getStructFields(f, fields[i])
@ -1008,6 +1001,14 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
toComplete = strings.Join(toCompArr, ".")
return prefixSlice(toComplete, suggestions), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
}
val := getActualStructType(f)
if val == nil {
// no struct return nothing to complete
return nil, cobra.ShellCompDirectiveNoFileComp
}
f = *val
// set the next struct field
f = f.FieldByName(fields[i])
}
@ -1038,12 +1039,15 @@ func getActualStructType(f reflect.Value) *reflect.Value {
// getStructFields reads all struct field names and method names and returns them.
func getStructFields(f reflect.Value, prefix string) []string {
suggestions := []string{}
var suggestions []string
if f.IsValid() {
suggestions = append(suggestions, getMethodNames(f, prefix)...)
}
val := getActualStructType(f)
if val == nil {
// no struct return nothing to complete
return nil
return suggestions
}
f = *val
@ -1069,7 +1073,11 @@ func getStructFields(f reflect.Value, prefix string) []string {
suggestions = append(suggestions, fname+suffix)
}
}
return suggestions
}
func getMethodNames(f reflect.Value, prefix string) []string {
suggestions := make([]string, 0, f.NumMethod())
for j := 0; j < f.NumMethod(); j++ {
fname := f.Type().Method(j).Name
if strings.HasPrefix(fname, prefix) {
@ -1077,7 +1085,6 @@ func getStructFields(f reflect.Value, prefix string) []string {
suggestions = append(suggestions, fname+"}}")
}
}
return suggestions
}

View File

@ -25,7 +25,9 @@ func (c Car) Type() string {
return ""
}
func (c Car) Color() string {
// Note: It is important that this function is *Car and the Type one is just Car.
// The reflect logic behaves differently for these cases so we have to test both.
func (c *Car) Color() string {
return ""
}
@ -94,7 +96,7 @@ func TestAutocompleteFormat(t *testing.T) {
{
"second level struct field name",
"{{ .Car.",
[]string{"{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras}}", "{{ .Car.Color}}", "{{ .Car.Type}}"},
[]string{"{{ .Car.Color}}", "{{ .Car.Type}}", "{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras}}"},
},
{
"second level struct field name",
@ -104,7 +106,7 @@ func TestAutocompleteFormat(t *testing.T) {
{
"second level nil struct field name",
"{{ .Car2.",
[]string{"{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras}}", "{{ .Car2.Color}}", "{{ .Car2.Type}}"},
[]string{"{{ .Car2.Color}}", "{{ .Car2.Type}}", "{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras}}"},
},
{
"three level struct field name",
@ -134,8 +136,8 @@ func TestAutocompleteFormat(t *testing.T) {
{
"two variables struct field name",
"{{ .Car.Brand }} {{ .Car.",
[]string{"{{ .Car.Brand }} {{ .Car.Brand}}", "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}",
"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}"},
[]string{"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}", "{{ .Car.Brand }} {{ .Car.Brand}}",
"{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}"},
},
{
"only dot without variable",