diff --git a/printer/printer.go b/printer/printer.go index 4117a9c7..f5e4824c 100644 --- a/printer/printer.go +++ b/printer/printer.go @@ -15,21 +15,21 @@ import ( // All printer configuration will be the default; // links will be printed, and will not be traversed. func Print(n datamodel.Node) { - Config{}.Print(n) + Config{Indentation: []byte{'\t'}}.Print(n) } // Sprint returns a textual description of the node tree. // All printer configuration will be the default; // links will be printed, and will not be traversed. func Sprint(n datamodel.Node) string { - return Config{}.Sprint(n) + return Config{Indentation: []byte{'\t'}}.Sprint(n) } // Fprint accepts an io.Writer to which a textual description of the node tree will be written. // All printer configuration will be the default; // links will be printed, and will not be traversed. func Fprint(w io.Writer, n datamodel.Node) { - Config{}.Fprint(w, n) + Config{Indentation: []byte{'\t'}}.Fprint(w, n) } // Print emits a textual description of the node tree straight to stdout. @@ -50,7 +50,6 @@ func (cfg Config) Sprint(n datamodel.Node) string { // The configuration structure this method is attached to can be used to specified details for how the printout will be formatted. func (cfg Config) Fprint(w io.Writer, n datamodel.Node) { pr := printBuf{w, cfg} - pr.Config.init() pr.doString(0, printState_normal, n) } @@ -61,10 +60,11 @@ type Config struct { Abbreviate bool // If set, the indentation to use. - // If nil, it will be treated as a default "\t". + // If nil, no indentation will be used and newlines will be omitted. If set to an empty slice, + // newlines will be used but no indentation. Setting to `[]byte{'\t'}` is a common choice. Indentation []byte - // Probably does exactly what you think it does. + // If set, the string to use for the start of each line. StartingIndent []byte // Set to true if you like verbosity, I guess. @@ -93,12 +93,6 @@ type Config struct { UseMapComplexStyleOnType map[schema.TypeName]bool } -func (cfg *Config) init() { - if cfg.Indentation == nil { - cfg.Indentation = []byte{'\t'} - } -} - // oneline decides if a value should be flatted into printing on a single, // or if it's allowed to spread out over multiple lines. // Note that this will not be asked if something outside of a value has already declared it's @@ -163,6 +157,12 @@ func (z *printBuf) doIndent(indentLevel int) { } } +func (z *printBuf) doNewline() { + if z.Config.Indentation != nil { + z.wr.Write([]byte{'\n'}) + } +} + const ( printState_normal uint8 = iota printState_isKey // may sometimes entersen or stringify things harder. @@ -233,7 +233,7 @@ func (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) } z.writeString("{") if !oneline && n.Length() > 0 { - z.writeString("\n") + z.doNewline() } for itr := n.MapIterator(); !itr.Done(); { k, v, _ := itr.Next() @@ -242,16 +242,13 @@ func (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) } fn, _ := k.AsString() z.writeString(fn) - z.writeString(": ") + z.writeString(":") z.doString(indentLevel+deepen, childState, v) if !itr.Done() { z.writeString(",") - if oneline { - z.writeString(" ") - } } if !oneline { - z.writeString("\n") + z.doNewline() } } if !oneline { @@ -296,7 +293,7 @@ func (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) } z.writeString("{") if n.Length() > 0 { - z.writeString("\n") + z.doNewline() } else { z.writeString("}") return @@ -307,23 +304,23 @@ func (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) z.doIndent(indentLevel + 1) z.writeString("!! map iteration step yielded error: ") z.writeString(err.Error()) - z.writeString("\n") + z.doNewline() break } z.doString(indentLevel+1, childKeyState, k) - z.writeString(": ") + z.writeString(":") z.doString(indentLevel+1, printState_isValue, v) if !itr.Done() { z.writeString(",") } - z.writeString("\n") + z.doNewline() } z.doIndent(indentLevel) z.writeString("}") case datamodel.Kind_List: z.writeString("{") if n.Length() > 0 { - z.writeString("\n") + z.doNewline() } else { z.writeString("}") return @@ -334,17 +331,17 @@ func (z *printBuf) doString(indentLevel int, printState uint8, n datamodel.Node) z.doIndent(indentLevel + 1) z.writeString("!! list iteration step yielded error: ") z.writeString(err.Error()) - z.writeString("\n") + z.doNewline() break } z.doIndent(indentLevel + 1) z.writeString(strconv.FormatInt(idx, 10)) - z.writeString(": ") + z.writeString(":") z.doString(indentLevel+1, printState_isValue, v) if !itr.Done() { z.writeString(",") } - z.writeString("\n") + z.doNewline() } z.doIndent(indentLevel) z.writeString("}") diff --git a/printer/printer_test.go b/printer/printer_test.go index 056f2f37..f41aefb3 100644 --- a/printer/printer_test.go +++ b/printer/printer_test.go @@ -39,21 +39,62 @@ func TestSimpleData(t *testing.T) { }) qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(` map{ - string{"some key"}: string{"some value"}, - string{"another key"}: string{"another value"}, - string{"nested map"}: map{ - string{"deeper entries"}: string{"deeper values"}, - string{"more deeper entries"}: string{"more deeper values"} + string{"some key"}:string{"some value"}, + string{"another key"}:string{"another value"}, + string{"nested map"}:map{ + string{"deeper entries"}:string{"deeper values"}, + string{"more deeper entries"}:string{"more deeper values"} }, - string{"nested list"}: list{ - 0: int{1}, - 1: int{2} + string{"nested list"}:list{ + 0:int{1}, + 1:int{2} }, - string{"list with float"}: list{ - 0: float{3.4} + string{"list with float"}:list{ + 0:float{3.4} } }`, )) + t.Run("compact-form", func(t *testing.T) { + qt.Check(t, Config{}.Sprint(n), qt.CmpEquals(), `map{string{"some key"}:string{"some value"},string{"another key"}:string{"another value"},string{"nested map"}:map{string{"deeper entries"}:string{"deeper values"},string{"more deeper entries"}:string{"more deeper values"}},string{"nested list"}:list{0:int{1},1:int{2}},string{"list with float"}:list{0:float{3.4}}}`) + }) + t.Run("custom-indentation", func(t *testing.T) { + qt.Check(t, Config{Indentation: []byte("==>")}.Sprint(n), qt.CmpEquals(), testutil.Dedent(` + map{ + ==>string{"some key"}:string{"some value"}, + ==>string{"another key"}:string{"another value"}, + ==>string{"nested map"}:map{ + ==>==>string{"deeper entries"}:string{"deeper values"}, + ==>==>string{"more deeper entries"}:string{"more deeper values"} + ==>}, + ==>string{"nested list"}:list{ + ==>==>0:int{1}, + ==>==>1:int{2} + ==>}, + ==>string{"list with float"}:list{ + ==>==>0:float{3.4} + ==>} + }`, + )) + }) + t.Run("line-prefix-indentation", func(t *testing.T) { + qt.Check(t, Config{StartingIndent: []byte("->"), Indentation: []byte{'*'}}.Sprint(n), qt.CmpEquals(), testutil.Dedent(` + ->map{ + ->*string{"some key"}:string{"some value"}, + ->*string{"another key"}:string{"another value"}, + ->*string{"nested map"}:map{ + ->**string{"deeper entries"}:string{"deeper values"}, + ->**string{"more deeper entries"}:string{"more deeper values"} + ->*}, + ->*string{"nested list"}:list{ + ->**0:int{1}, + ->**1:int{2} + ->*}, + ->*string{"list with float"}:list{ + ->**0:float{3.4} + ->*} + ->}`, + )) + }) }) t.Run("map-with-link-and-bytes", func(t *testing.T) { @@ -73,17 +114,17 @@ func TestSimpleData(t *testing.T) { }) qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(` map{ - string{"some key"}: link{bafkqabiaaebagba}, - string{"another key"}: string{"another value"}, - string{"nested map"}: map{ - string{"deeper entries"}: string{"deeper values"}, - string{"more deeper entries"}: link{bafkqabiaaebagba}, - string{"yet another deeper entries"}: bytes{66697368} + string{"some key"}:link{bafkqabiaaebagba}, + string{"another key"}:string{"another value"}, + string{"nested map"}:map{ + string{"deeper entries"}:string{"deeper values"}, + string{"more deeper entries"}:link{bafkqabiaaebagba}, + string{"yet another deeper entries"}:bytes{66697368} }, - string{"nested list"}: list{ - 0: bytes{67686f7469}, - 1: int{1}, - 2: link{bafkqabiaaebagba} + string{"nested list"}:list{ + 0:bytes{67686f7469}, + 1:int{1}, + 2:link{bafkqabiaaebagba} } }`, )) @@ -112,10 +153,10 @@ func TestTypedData(t *testing.T) { n := bindnode.Wrap(&FooBar{"x", "y", []byte("zed"), testLink}, ts.TypeByName("FooBar")) qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(` struct{ - foo: string{"x"}, - bar: string{"y"}, - baz: bytes{7a6564}, - jazz: link{bafkqabiaaebagba} + foo:string{"x"}, + bar:string{"y"}, + baz:bytes{7a6564}, + jazz:link{bafkqabiaaebagba} }`, )) }) @@ -145,8 +186,8 @@ func TestTypedData(t *testing.T) { }, ts.TypeByName("WowMap")) qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(` map{ - struct{foo: string{"x"}, bar: string{"y"}}: string{"a"}, - struct{foo: string{"z"}, bar: string{"z"}}: string{"b"} + struct{foo:string{"x"},bar:string{"y"}}:string{"a"}, + struct{foo:string{"z"},bar:string{"z"}}:string{"b"} }`, )) }) @@ -184,48 +225,50 @@ func TestTypedData(t *testing.T) { }, ts.TypeByName("WowMap")) t.Run("complex-keys-in-effect", func(t *testing.T) { cfg := Config{ + Indentation: []byte{'\t'}, UseMapComplexStyleAlways: true, } qt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(` map{ struct{ - foo: string{"x"}, - bar: struct{ - baz: string{"y"} + foo:string{"x"}, + bar:struct{ + baz:string{"y"} }, - baz: struct{ - baz: string{"y"} + baz:struct{ + baz:string{"y"} } - }: struct{ - baz: string{"a"} + }:struct{ + baz:string{"a"} }, struct{ - foo: string{"z"}, - bar: struct{ - baz: string{"z"} + foo:string{"z"}, + bar:struct{ + baz:string{"z"} }, - baz: struct{ - baz: string{"z"} + baz:struct{ + baz:string{"z"} } - }: struct{ - baz: string{"b"} + }:struct{ + baz:string{"b"} } }`, )) }) t.Run("complex-keys-in-disabled", func(t *testing.T) { cfg := Config{ + Indentation: []byte{'\t'}, UseMapComplexStyleOnType: map[schema.TypeName]bool{ "WowMap": false, }, } qt.Check(t, cfg.Sprint(n), qt.CmpEquals(), testutil.Dedent(` map{ - struct{foo: string{"x"}, bar: struct{baz: string{"y"}}, baz: struct{baz: string{"y"}}}: struct{ - baz: string{"a"} + struct{foo:string{"x"},bar:struct{baz:string{"y"}},baz:struct{baz:string{"y"}}}:struct{ + baz:string{"a"} }, - struct{foo: string{"z"}, bar: struct{baz: string{"z"}}, baz: struct{baz: string{"z"}}}: struct{ - baz: string{"b"} + struct{foo:string{"z"},bar:struct{baz:string{"z"}},baz:struct{baz:string{"z"}}}:struct{ + baz:string{"b"} } }`, ))