encoder: support indentation (#525)
This commit is contained in:
+25
-5
@@ -37,6 +37,7 @@ type Encoder struct {
|
|||||||
tablesInline bool
|
tablesInline bool
|
||||||
arraysMultiline bool
|
arraysMultiline bool
|
||||||
indentSymbol string
|
indentSymbol string
|
||||||
|
indentTables bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder returns a new Encoder that writes to w.
|
// NewEncoder returns a new Encoder that writes to w.
|
||||||
@@ -64,6 +65,18 @@ func (enc *Encoder) SetArraysMultiline(multiline bool) {
|
|||||||
enc.arraysMultiline = multiline
|
enc.arraysMultiline = multiline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndentSymbol defines the string that should be used for indentation. The
|
||||||
|
// provided string is repeated for each indentation level. Defaults to two
|
||||||
|
// spaces.
|
||||||
|
func (enc *Encoder) SetIndentSymbol(s string) {
|
||||||
|
enc.indentSymbol = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIndentTables forces the encoder to intent tables and array tables.
|
||||||
|
func (enc *Encoder) SetIndentTables(indent bool) {
|
||||||
|
enc.indentTables = indent
|
||||||
|
}
|
||||||
|
|
||||||
// Encode writes a TOML representation of v to the stream.
|
// Encode writes a TOML representation of v to the stream.
|
||||||
//
|
//
|
||||||
// If v cannot be represented to TOML it returns an error.
|
// If v cannot be represented to TOML it returns an error.
|
||||||
@@ -257,6 +270,8 @@ func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v r
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b = enc.indent(ctx.indent, b)
|
||||||
|
|
||||||
b, err = enc.encodeKey(b, ctx.key)
|
b, err = enc.encodeKey(b, ctx.key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -367,21 +382,23 @@ func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
|
|||||||
return append(b, v...)
|
return append(b, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) encodeTableHeader(b []byte, key []string) ([]byte, error) {
|
func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
|
||||||
if len(key) == 0 {
|
if len(ctx.parentKey) == 0 {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b = enc.indent(ctx.indent, b)
|
||||||
|
|
||||||
b = append(b, '[')
|
b = append(b, '[')
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
b, err = enc.encodeKey(b, key[0])
|
b, err = enc.encodeKey(b, ctx.parentKey[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range key[1:] {
|
for _, k := range ctx.parentKey[1:] {
|
||||||
b = append(b, '.')
|
b = append(b, '.')
|
||||||
|
|
||||||
b, err = enc.encodeKey(b, k)
|
b, err = enc.encodeKey(b, k)
|
||||||
@@ -559,10 +576,13 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.skipTableHeader {
|
if !ctx.skipTableHeader {
|
||||||
b, err = enc.encodeTableHeader(b, ctx.parentKey)
|
b, err = enc.encodeTableHeader(ctx, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if enc.indentTables && len(ctx.parentKey) > 0 {
|
||||||
|
ctx.indent++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.skipTableHeader = false
|
ctx.skipTableHeader = false
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ type flagsSetters []struct {
|
|||||||
var allFlags = flagsSetters{
|
var allFlags = flagsSetters{
|
||||||
{"arrays-multiline", (*toml.Encoder).SetArraysMultiline},
|
{"arrays-multiline", (*toml.Encoder).SetArraysMultiline},
|
||||||
{"tables-inline", (*toml.Encoder).SetTablesInline},
|
{"tables-inline", (*toml.Encoder).SetTablesInline},
|
||||||
|
{"indent-tables", (*toml.Encoder).SetIndentTables},
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFlags(enc *toml.Encoder, flags int) {
|
func setFlags(enc *toml.Encoder, flags int) {
|
||||||
@@ -393,6 +394,66 @@ func equalStringsIgnoreNewlines(t *testing.T, expected string, actual string) {
|
|||||||
assert.Equal(t, strings.Trim(expected, cutset), strings.Trim(actual, cutset))
|
assert.Equal(t, strings.Trim(expected, cutset), strings.Trim(actual, cutset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMarshalIndentTables(t *testing.T) {
|
||||||
|
examples := []struct {
|
||||||
|
desc string
|
||||||
|
v interface{}
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "one kv",
|
||||||
|
v: map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
expected: `foo = 'bar'`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "one level table",
|
||||||
|
v: map[string]map[string]string{
|
||||||
|
"foo": {
|
||||||
|
"one": "value1",
|
||||||
|
"two": "value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `
|
||||||
|
[foo]
|
||||||
|
one = 'value1'
|
||||||
|
two = 'value2'
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "two levels table",
|
||||||
|
v: map[string]interface{}{
|
||||||
|
"root": "value0",
|
||||||
|
"level1": map[string]interface{}{
|
||||||
|
"one": "value1",
|
||||||
|
"level2": map[string]interface{}{
|
||||||
|
"two": "value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `
|
||||||
|
root = 'value0'
|
||||||
|
[level1]
|
||||||
|
one = 'value1'
|
||||||
|
[level1.level2]
|
||||||
|
two = 'value2'
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range examples {
|
||||||
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
var buf strings.Builder
|
||||||
|
enc := toml.NewEncoder(&buf)
|
||||||
|
enc.SetIndentTables(true)
|
||||||
|
err := enc.Encode(e.v)
|
||||||
|
require.NoError(t, err)
|
||||||
|
equalStringsIgnoreNewlines(t, e.expected, buf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssue436(t *testing.T) {
|
func TestIssue436(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user