Merge pull request #11337 from Luap99/anon-template
Shell completion for --format with anonymous fields
This commit is contained in:
commit
6f61ef87af
|
|
@ -985,40 +985,14 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
|
|||
f = f.Elem()
|
||||
}
|
||||
|
||||
// // the only supported type is struct
|
||||
// the only supported type is struct
|
||||
if f.Kind() != reflect.Struct {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
// last field get all names to suggest
|
||||
if i == len(fields)-1 {
|
||||
suggestions := []string{}
|
||||
for j := 0; j < f.NumField(); j++ {
|
||||
fname := f.Type().Field(j).Name
|
||||
suffix := "}}"
|
||||
kind := f.Type().Field(j).Type.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
// make sure to read the actual type when it is a pointer
|
||||
kind = f.Type().Field(j).Type.Elem().Kind()
|
||||
}
|
||||
// when we have a nested struct do not append braces instead append a dot
|
||||
if kind == reflect.Struct {
|
||||
suffix = "."
|
||||
}
|
||||
if strings.HasPrefix(fname, fields[i]) {
|
||||
// add field name with closing braces
|
||||
suggestions = append(suggestions, fname+suffix)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j < f.NumMethod(); j++ {
|
||||
fname := f.Type().Method(j).Name
|
||||
if strings.HasPrefix(fname, fields[i]) {
|
||||
// add method name with closing braces
|
||||
suggestions = append(suggestions, fname+"}}")
|
||||
}
|
||||
}
|
||||
|
||||
suggestions := getStructFields(f, fields[i])
|
||||
// add the current toComplete value in front so that the shell can complete this correctly
|
||||
toCompArr := strings.Split(toComplete, ".")
|
||||
toCompArr[len(toCompArr)-1] = ""
|
||||
|
|
@ -1032,6 +1006,52 @@ func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, t
|
|||
}
|
||||
}
|
||||
|
||||
// getStructFields reads all struct field names and method names and returns them.
|
||||
func getStructFields(f reflect.Value, prefix string) []string {
|
||||
suggestions := []string{}
|
||||
// follow the pointer first
|
||||
if f.Kind() == reflect.Ptr {
|
||||
f = f.Elem()
|
||||
}
|
||||
// we only support structs
|
||||
if f.Kind() != reflect.Struct {
|
||||
return nil
|
||||
}
|
||||
// loop over all field names
|
||||
for j := 0; j < f.NumField(); j++ {
|
||||
field := f.Type().Field(j)
|
||||
fname := field.Name
|
||||
suffix := "}}"
|
||||
kind := field.Type.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
// make sure to read the actual type when it is a pointer
|
||||
kind = field.Type.Elem().Kind()
|
||||
}
|
||||
// when we have a nested struct do not append braces instead append a dot
|
||||
if kind == reflect.Struct {
|
||||
suffix = "."
|
||||
}
|
||||
if strings.HasPrefix(fname, prefix) {
|
||||
// add field name with suffix
|
||||
suggestions = append(suggestions, fname+suffix)
|
||||
}
|
||||
// if field is anonymous add the child fields as well
|
||||
if field.Anonymous {
|
||||
suggestions = append(suggestions, getStructFields(f.FieldByIndex([]int{j}), prefix)...)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j < f.NumMethod(); j++ {
|
||||
fname := f.Type().Method(j).Name
|
||||
if strings.HasPrefix(fname, prefix) {
|
||||
// add method name with closing braces
|
||||
suggestions = append(suggestions, fname+"}}")
|
||||
}
|
||||
}
|
||||
|
||||
return suggestions
|
||||
}
|
||||
|
||||
// AutocompleteEventFilter - Autocomplete event filter flag options.
|
||||
// -> "container=", "event=", "image=", "pod=", "volume=", "type="
|
||||
func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ type Car struct {
|
|||
Extras map[string]string
|
||||
}
|
||||
|
||||
type Anonymous struct {
|
||||
Hello string
|
||||
}
|
||||
|
||||
func (c Car) Type() string {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -30,7 +34,10 @@ func TestAutocompleteFormat(t *testing.T) {
|
|||
Name string
|
||||
Age int
|
||||
Car *Car
|
||||
}{}
|
||||
*Anonymous
|
||||
}{
|
||||
Anonymous: &Anonymous{},
|
||||
}
|
||||
|
||||
testStruct.Car = &Car{}
|
||||
testStruct.Car.Extras = map[string]string{"test": "1"}
|
||||
|
|
@ -73,12 +80,12 @@ func TestAutocompleteFormat(t *testing.T) {
|
|||
{
|
||||
"fist level struct field name",
|
||||
"{{.",
|
||||
[]string{"{{.Name}}", "{{.Age}}", "{{.Car."},
|
||||
[]string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Anonymous.", "{{.Hello}}"},
|
||||
},
|
||||
{
|
||||
"fist level struct field name",
|
||||
"{{ .",
|
||||
[]string{"{{ .Name}}", "{{ .Age}}", "{{ .Car."},
|
||||
[]string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Anonymous.", "{{ .Hello}}"},
|
||||
},
|
||||
{
|
||||
"fist level struct field name",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func init() {
|
|||
|
||||
formatFlagName := "format"
|
||||
flags.StringVar(&psInput.Format, formatFlagName, "", "Pretty-print pods to JSON or using a Go template")
|
||||
_ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{}))
|
||||
_ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{ListPodsReport: &entities.ListPodsReport{}}))
|
||||
|
||||
flags.Bool("noheading", false, "Do not print headers")
|
||||
flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")
|
||||
|
|
|
|||
Loading…
Reference in New Issue