Skip to content

Commit

Permalink
feat(printer)!: nil Indentation means no identation and no newlines
Browse files Browse the repository at this point in the history
Similar to encoding/json behaviour and JSON.stringify in JS.
  • Loading branch information
rvagg committed Jan 7, 2025
1 parent 543fe8a commit ee92d33
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 70 deletions.
49 changes: 23 additions & 26 deletions printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
}

Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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("}")
Expand Down
131 changes: 87 additions & 44 deletions printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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}
}
}`,
))
Expand Down Expand Up @@ -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<FooBar>{
foo: string<String>{"x"},
bar: string<String>{"y"},
baz: bytes<Bytes>{7a6564},
jazz: link<Link>{bafkqabiaaebagba}
foo:string<String>{"x"},
bar:string<String>{"y"},
baz:bytes<Bytes>{7a6564},
jazz:link<Link>{bafkqabiaaebagba}
}`,
))
})
Expand Down Expand Up @@ -145,8 +186,8 @@ func TestTypedData(t *testing.T) {
}, ts.TypeByName("WowMap"))
qt.Check(t, Sprint(n), qt.CmpEquals(), testutil.Dedent(`
map<WowMap>{
struct<FooBar>{foo: string<String>{"x"}, bar: string<String>{"y"}}: string<String>{"a"},
struct<FooBar>{foo: string<String>{"z"}, bar: string<String>{"z"}}: string<String>{"b"}
struct<FooBar>{foo:string<String>{"x"},bar:string<String>{"y"}}:string<String>{"a"},
struct<FooBar>{foo:string<String>{"z"},bar:string<String>{"z"}}:string<String>{"b"}
}`,
))
})
Expand Down Expand Up @@ -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<WowMap>{
struct<FooBar>{
foo: string<String>{"x"},
bar: struct<Baz>{
baz: string<String>{"y"}
foo:string<String>{"x"},
bar:struct<Baz>{
baz:string<String>{"y"}
},
baz: struct<Baz>{
baz: string<String>{"y"}
baz:struct<Baz>{
baz:string<String>{"y"}
}
}: struct<Baz>{
baz: string<String>{"a"}
}:struct<Baz>{
baz:string<String>{"a"}
},
struct<FooBar>{
foo: string<String>{"z"},
bar: struct<Baz>{
baz: string<String>{"z"}
foo:string<String>{"z"},
bar:struct<Baz>{
baz:string<String>{"z"}
},
baz: struct<Baz>{
baz: string<String>{"z"}
baz:struct<Baz>{
baz:string<String>{"z"}
}
}: struct<Baz>{
baz: string<String>{"b"}
}:struct<Baz>{
baz:string<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<WowMap>{
struct<FooBar>{foo: string<String>{"x"}, bar: struct<Baz>{baz: string<String>{"y"}}, baz: struct<Baz>{baz: string<String>{"y"}}}: struct<Baz>{
baz: string<String>{"a"}
struct<FooBar>{foo:string<String>{"x"},bar:struct<Baz>{baz:string<String>{"y"}},baz:struct<Baz>{baz:string<String>{"y"}}}:struct<Baz>{
baz:string<String>{"a"}
},
struct<FooBar>{foo: string<String>{"z"}, bar: struct<Baz>{baz: string<String>{"z"}}, baz: struct<Baz>{baz: string<String>{"z"}}}: struct<Baz>{
baz: string<String>{"b"}
struct<FooBar>{foo:string<String>{"z"},bar:struct<Baz>{baz:string<String>{"z"}},baz:struct<Baz>{baz:string<String>{"z"}}}:struct<Baz>{
baz:string<String>{"b"}
}
}`,
))
Expand Down

0 comments on commit ee92d33

Please sign in to comment.