@@ -188,32 +188,39 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
188188// returned. If the table tag is malformed, an error is returned.
189189//
190190// The returned name is transformed from "snake_case" to "normal text".
191- func parseTableStructTag (field reflect.StructField ) (name string , defaultSort , recursive bool , err error ) {
191+ func parseTableStructTag (field reflect.StructField ) (name string , defaultSort , recursive bool , skipParentName bool , err error ) {
192192 tags , err := structtag .Parse (string (field .Tag ))
193193 if err != nil {
194- return "" , false , false , xerrors .Errorf ("parse struct field tag %q: %w" , string (field .Tag ), err )
194+ return "" , false , false , false , xerrors .Errorf ("parse struct field tag %q: %w" , string (field .Tag ), err )
195195 }
196196
197197 tag , err := tags .Get ("table" )
198198 if err != nil || tag .Name == "-" {
199199 // tags.Get only returns an error if the tag is not found.
200- return "" , false , false , nil
200+ return "" , false , false , false , nil
201201 }
202202
203203 defaultSortOpt := false
204204 recursiveOpt := false
205+ skipParentNameOpt := false
205206 for _ , opt := range tag .Options {
206207 switch opt {
207208 case "default_sort" :
208209 defaultSortOpt = true
209210 case "recursive" :
210211 recursiveOpt = true
212+ case "recursive_inline" :
213+ // recursive_inline is a helper to make recursive tables look nicer.
214+ // It skips prefixing the parent name to the child name. If you do this,
215+ // make sure the child name is unique across all nested structs in the parent.
216+ recursiveOpt = true
217+ skipParentNameOpt = true
211218 default :
212- return "" , false , false , xerrors .Errorf ("unknown option %q in struct field tag" , opt )
219+ return "" , false , false , false , xerrors .Errorf ("unknown option %q in struct field tag" , opt )
213220 }
214221 }
215222
216- return strings .ReplaceAll (tag .Name , "_" , " " ), defaultSortOpt , recursiveOpt , nil
223+ return strings .ReplaceAll (tag .Name , "_" , " " ), defaultSortOpt , recursiveOpt , skipParentNameOpt , nil
217224}
218225
219226func isStructOrStructPointer (t reflect.Type ) bool {
@@ -235,7 +242,7 @@ func typeToTableHeaders(t reflect.Type) ([]string, string, error) {
235242 defaultSortName := ""
236243 for i := 0 ; i < t .NumField (); i ++ {
237244 field := t .Field (i )
238- name , defaultSort , recursive , err := parseTableStructTag (field )
245+ name , defaultSort , recursive , skip , err := parseTableStructTag (field )
239246 if err != nil {
240247 return nil , "" , xerrors .Errorf ("parse struct tags for field %q in type %q: %w" , field .Name , t .String (), err )
241248 }
@@ -260,7 +267,11 @@ func typeToTableHeaders(t reflect.Type) ([]string, string, error) {
260267 return nil , "" , xerrors .Errorf ("get child field header names for field %q in type %q: %w" , field .Name , fieldType .String (), err )
261268 }
262269 for _ , childName := range childNames {
263- headers = append (headers , fmt .Sprintf ("%s %s" , name , childName ))
270+ fullName := fmt .Sprintf ("%s %s" , name , childName )
271+ if skip {
272+ fullName = childName
273+ }
274+ headers = append (headers , fullName )
264275 }
265276 continue
266277 }
@@ -296,7 +307,7 @@ func valueToTableMap(val reflect.Value) (map[string]any, error) {
296307 for i := 0 ; i < val .NumField (); i ++ {
297308 field := val .Type ().Field (i )
298309 fieldVal := val .Field (i )
299- name , _ , recursive , err := parseTableStructTag (field )
310+ name , _ , recursive , skip , err := parseTableStructTag (field )
300311 if err != nil {
301312 return nil , xerrors .Errorf ("parse struct tags for field %q in type %T: %w" , field .Name , val , err )
302313 }
@@ -318,7 +329,11 @@ func valueToTableMap(val reflect.Value) (map[string]any, error) {
318329 return nil , xerrors .Errorf ("get child field values for field %q in type %q: %w" , field .Name , fieldType .String (), err )
319330 }
320331 for childName , childValue := range childMap {
321- row [fmt .Sprintf ("%s %s" , name , childName )] = childValue
332+ fullName := fmt .Sprintf ("%s %s" , name , childName )
333+ if skip {
334+ fullName = childName
335+ }
336+ row [fullName ] = childValue
322337 }
323338 continue
324339 }
0 commit comments