@@ -188,32 +188,39 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
188
188
// returned. If the table tag is malformed, an error is returned.
189
189
//
190
190
// 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 ) {
192
192
tags , err := structtag .Parse (string (field .Tag ))
193
193
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 )
195
195
}
196
196
197
197
tag , err := tags .Get ("table" )
198
198
if err != nil || tag .Name == "-" {
199
199
// tags.Get only returns an error if the tag is not found.
200
- return "" , false , false , nil
200
+ return "" , false , false , false , nil
201
201
}
202
202
203
203
defaultSortOpt := false
204
204
recursiveOpt := false
205
+ skipParentNameOpt := false
205
206
for _ , opt := range tag .Options {
206
207
switch opt {
207
208
case "default_sort" :
208
209
defaultSortOpt = true
209
210
case "recursive" :
210
211
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
211
218
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 )
213
220
}
214
221
}
215
222
216
- return strings .ReplaceAll (tag .Name , "_" , " " ), defaultSortOpt , recursiveOpt , nil
223
+ return strings .ReplaceAll (tag .Name , "_" , " " ), defaultSortOpt , recursiveOpt , skipParentNameOpt , nil
217
224
}
218
225
219
226
func isStructOrStructPointer (t reflect.Type ) bool {
@@ -235,7 +242,7 @@ func typeToTableHeaders(t reflect.Type) ([]string, string, error) {
235
242
defaultSortName := ""
236
243
for i := 0 ; i < t .NumField (); i ++ {
237
244
field := t .Field (i )
238
- name , defaultSort , recursive , err := parseTableStructTag (field )
245
+ name , defaultSort , recursive , skip , err := parseTableStructTag (field )
239
246
if err != nil {
240
247
return nil , "" , xerrors .Errorf ("parse struct tags for field %q in type %q: %w" , field .Name , t .String (), err )
241
248
}
@@ -260,7 +267,11 @@ func typeToTableHeaders(t reflect.Type) ([]string, string, error) {
260
267
return nil , "" , xerrors .Errorf ("get child field header names for field %q in type %q: %w" , field .Name , fieldType .String (), err )
261
268
}
262
269
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 )
264
275
}
265
276
continue
266
277
}
@@ -296,7 +307,7 @@ func valueToTableMap(val reflect.Value) (map[string]any, error) {
296
307
for i := 0 ; i < val .NumField (); i ++ {
297
308
field := val .Type ().Field (i )
298
309
fieldVal := val .Field (i )
299
- name , _ , recursive , err := parseTableStructTag (field )
310
+ name , _ , recursive , skip , err := parseTableStructTag (field )
300
311
if err != nil {
301
312
return nil , xerrors .Errorf ("parse struct tags for field %q in type %T: %w" , field .Name , val , err )
302
313
}
@@ -318,7 +329,11 @@ func valueToTableMap(val reflect.Value) (map[string]any, error) {
318
329
return nil , xerrors .Errorf ("get child field values for field %q in type %q: %w" , field .Name , fieldType .String (), err )
319
330
}
320
331
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
322
337
}
323
338
continue
324
339
}
0 commit comments