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

View File

@ -25,7 +25,9 @@ func (c Car) Type() string {
return "" 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 "" return ""
} }
@ -94,7 +96,7 @@ func TestAutocompleteFormat(t *testing.T) {
{ {
"second level struct field name", "second level struct field name",
"{{ .Car.", "{{ .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", "second level struct field name",
@ -104,7 +106,7 @@ func TestAutocompleteFormat(t *testing.T) {
{ {
"second level nil struct field name", "second level nil struct field name",
"{{ .Car2.", "{{ .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", "three level struct field name",
@ -134,8 +136,8 @@ func TestAutocompleteFormat(t *testing.T) {
{ {
"two variables struct field name", "two variables struct field name",
"{{ .Car.Brand }} {{ .Car.", "{{ .Car.Brand }} {{ .Car.",
[]string{"{{ .Car.Brand }} {{ .Car.Brand}}", "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}", []string{"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}", "{{ .Car.Brand }} {{ .Car.Brand}}",
"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}"}, "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}"},
}, },
{ {
"only dot without variable", "only dot without variable",