diff options
-rw-r--r-- | cmd/podman/common/completion.go | 27 | ||||
-rw-r--r-- | cmd/podman/common/completion_test.go | 12 |
2 files changed, 24 insertions, 15 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 6149a4465..e07e28dab 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -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 } diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go index ae117a173..13f45a662 100644 --- a/cmd/podman/common/completion_test.go +++ b/cmd/podman/common/completion_test.go @@ -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", |