@@ -54,7 +54,7 @@ func NewEncoder(w io.Writer) *Encoder {
54
54
// This behavior can be controlled on an individual struct field basis with the
55
55
// inline tag:
56
56
//
57
- // MyField `inline:"true "`
57
+ // MyField `toml:",inline "`
58
58
func (enc * Encoder ) SetTablesInline (inline bool ) * Encoder {
59
59
enc .tablesInline = inline
60
60
return enc
@@ -117,6 +117,19 @@ func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
117
117
// When encoding structs, fields are encoded in order of definition, with their
118
118
// exact name.
119
119
//
120
+ // Tables and array tables are separated by empty lines. However, consecutive
121
+ // subtables definitions are not. For example:
122
+ //
123
+ // [top1]
124
+ //
125
+ // [top2]
126
+ // [top2.child1]
127
+ //
128
+ // [[array]]
129
+ //
130
+ // [[array]]
131
+ // [array.child2]
132
+ //
120
133
// Struct tags
121
134
//
122
135
// The encoding of each public struct field can be customized by the format
@@ -333,13 +346,13 @@ func isNil(v reflect.Value) bool {
333
346
}
334
347
}
335
348
349
+ func shouldOmitEmpty (ctx encoderCtx , options valueOptions , v reflect.Value ) bool {
350
+ return (ctx .options .omitempty || options .omitempty ) && isEmptyValue (v )
351
+ }
352
+
336
353
func (enc * Encoder ) encodeKv (b []byte , ctx encoderCtx , options valueOptions , v reflect.Value ) ([]byte , error ) {
337
354
var err error
338
355
339
- if (ctx .options .omitempty || options .omitempty ) && isEmptyValue (v ) {
340
- return b , nil
341
- }
342
-
343
356
if ! ctx .inline {
344
357
b = enc .encodeComment (ctx .indent , options .comment , b )
345
358
}
@@ -365,6 +378,8 @@ func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v r
365
378
366
379
func isEmptyValue (v reflect.Value ) bool {
367
380
switch v .Kind () {
381
+ case reflect .Struct :
382
+ return isEmptyStruct (v )
368
383
case reflect .Array , reflect .Map , reflect .Slice , reflect .String :
369
384
return v .Len () == 0
370
385
case reflect .Bool :
@@ -381,6 +396,34 @@ func isEmptyValue(v reflect.Value) bool {
381
396
return false
382
397
}
383
398
399
+ func isEmptyStruct (v reflect.Value ) bool {
400
+ // TODO: merge with walkStruct and cache.
401
+ typ := v .Type ()
402
+ for i := 0 ; i < typ .NumField (); i ++ {
403
+ fieldType := typ .Field (i )
404
+
405
+ // only consider exported fields
406
+ if fieldType .PkgPath != "" {
407
+ continue
408
+ }
409
+
410
+ tag := fieldType .Tag .Get ("toml" )
411
+
412
+ // special field name to skip field
413
+ if tag == "-" {
414
+ continue
415
+ }
416
+
417
+ f := v .Field (i )
418
+
419
+ if ! isEmptyValue (f ) {
420
+ return false
421
+ }
422
+ }
423
+
424
+ return true
425
+ }
426
+
384
427
const literalQuote = '\''
385
428
386
429
func (enc * Encoder ) encodeString (b []byte , v string , options valueOptions ) []byte {
@@ -410,7 +453,6 @@ func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
410
453
return b
411
454
}
412
455
413
- //nolint:cyclop
414
456
func (enc * Encoder ) encodeQuotedString (multiline bool , b []byte , v string ) []byte {
415
457
stringQuote := `"`
416
458
@@ -757,7 +799,13 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
757
799
}
758
800
ctx .skipTableHeader = false
759
801
802
+ hasNonEmptyKV := false
760
803
for _ , kv := range t .kvs {
804
+ if shouldOmitEmpty (ctx , kv .Options , kv .Value ) {
805
+ continue
806
+ }
807
+ hasNonEmptyKV = true
808
+
761
809
ctx .setKey (kv .Key )
762
810
763
811
b , err = enc .encodeKv (b , ctx , kv .Options , kv .Value )
@@ -768,7 +816,20 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
768
816
b = append (b , '\n' )
769
817
}
770
818
819
+ first := true
771
820
for _ , table := range t .tables {
821
+ if shouldOmitEmpty (ctx , table .Options , table .Value ) {
822
+ continue
823
+ }
824
+ if first {
825
+ first = false
826
+ if hasNonEmptyKV {
827
+ b = append (b , '\n' )
828
+ }
829
+ } else {
830
+ b = append (b , "\n " ... )
831
+ }
832
+
772
833
ctx .setKey (table .Key )
773
834
774
835
ctx .options = table .Options
@@ -777,8 +838,6 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
777
838
if err != nil {
778
839
return nil , err
779
840
}
780
-
781
- b = append (b , '\n' )
782
841
}
783
842
784
843
return b , nil
@@ -791,6 +850,10 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte
791
850
792
851
first := true
793
852
for _ , kv := range t .kvs {
853
+ if shouldOmitEmpty (ctx , kv .Options , kv .Value ) {
854
+ continue
855
+ }
856
+
794
857
if first {
795
858
first = false
796
859
} else {
@@ -806,7 +869,7 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte
806
869
}
807
870
808
871
if len (t .tables ) > 0 {
809
- panic ("inline table cannot contain nested tables, online key-values" )
872
+ panic ("inline table cannot contain nested tables, only key-values" )
810
873
}
811
874
812
875
b = append (b , "}" ... )
@@ -905,6 +968,10 @@ func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.
905
968
b = enc .encodeComment (ctx .indent , ctx .options .comment , b )
906
969
907
970
for i := 0 ; i < v .Len (); i ++ {
971
+ if i != 0 {
972
+ b = append (b , "\n " ... )
973
+ }
974
+
908
975
b = append (b , scratch ... )
909
976
910
977
var err error
0 commit comments