Documentation
¶
Overview ¶
Package pprint is a library to typeset output with auto-width padding. It's implemented using a tree and has directory-like context. Supports typesetting or sorting per directory context.
Example (DefaultUsage) ¶
var (
pt = func(date string) time.Time {
t, _ := time.Parse("2006-01-02", date)
return t
}
data = [][]interface{}{
{21196, "Keep On Truckin'", pt("1999-05-17"), "ahote glowtusks", 9.75},
{-1162, "Cry Wolf", pt("2007-10-16"), "adahy windshot", 4.22},
{-1248, "Needle In a Haystack", pt("1988-09-06"), "shikpa longmoon", 0.7},
{50994, "Greased Lightning", pt("1989-06-04"), "helushka emberhair", 2.72},
{80640, "Let Her Rip", pt("1981-01-13"), "geashkoo grassdream", 1.6},
{50997, "Up In Arms", pt("1981-01-13"), "oonnak hardrage", 0.58},
}
)
n := NewNode()
for _, row := range data {
_, err := n.Push(row...)
if err != nil {
panic(err)
}
}
// All push are auto-width by default
Print(n)
fmt.Println("===")
// Or using a customized a typeset
n = NewNode(
WithColumns(
NewColumn(),
NewColumn(WithLeftAlignment()),
NewColumn(),
NewColumn(WithWidth(24)),
// Width 0 means no padding
NewColumn(WithWidth(0)),
),
)
for _, row := range data {
n.Push(row...)
}
Print(n, WithColSep("|"))
fmt.Println("===")
// Use with a folder-like context
n = NewNode()
// Data 0, 1, 2 are under node n
n.Push(data[0]...)
m, _ := n.Push(data[1]...)
n.Push(data[2]...)
// Data 3, 4, 5 are under node m, which is the position of data 1
m.Push(data[3]...)
m.Push(data[4]...)
m.Push(data[5]...)
// Output order would be 0, 1, 3, 4, 5, 2
Print(n)
Output: 21196 Keep On Truckin' 1999-05-17 00:00:00 +0000 UTC ahote glowtusks 9.75 -1162 Cry Wolf 2007-10-16 00:00:00 +0000 UTC adahy windshot 4.22 -1248 Needle In a Haystack 1988-09-06 00:00:00 +0000 UTC shikpa longmoon 0.7 50994 Greased Lightning 1989-06-04 00:00:00 +0000 UTC helushka emberhair 2.72 80640 Let Her Rip 1981-01-13 00:00:00 +0000 UTC geashkoo grassdream 1.6 50997 Up In Arms 1981-01-13 00:00:00 +0000 UTC oonnak hardrage 0.58 === 21196|Keep On Truckin' |1999-05-17 00:00:00 +0000 UTC| ahote glowtusks|9.75 -1162|Cry Wolf |2007-10-16 00:00:00 +0000 UTC| adahy windshot|4.22 -1248|Needle In a Haystack|1988-09-06 00:00:00 +0000 UTC| shikpa longmoon|0.7 50994|Greased Lightning |1989-06-04 00:00:00 +0000 UTC| helushka emberhair|2.72 80640|Let Her Rip |1981-01-13 00:00:00 +0000 UTC| geashkoo grassdream|1.6 50997|Up In Arms |1981-01-13 00:00:00 +0000 UTC| oonnak hardrage|0.58 === 21196 Keep On Truckin' 1999-05-17 00:00:00 +0000 UTC ahote glowtusks 9.75 -1162 Cry Wolf 2007-10-16 00:00:00 +0000 UTC adahy windshot 4.22 50994 Greased Lightning 1989-06-04 00:00:00 +0000 UTC helushka emberhair 2.72 80640 Let Her Rip 1981-01-13 00:00:00 +0000 UTC geashkoo grassdream 1.6 50997 Up In Arms 1981-01-13 00:00:00 +0000 UTC oonnak hardrage 0.58 -1248 Needle In a Haystack 1988-09-06 00:00:00 +0000 UTC shikpa longmoon 0.7
Example (DifferentLayouts) ¶
var (
pt = func(date string) time.Time {
t, _ := time.Parse("2006-01-02", date)
return t
}
data = [][]interface{}{
{21196, "Keep On Truckin'", pt("1999-05-17"), "ahote glowtusks", 9.75},
{-1162, "Cry Wolf", pt("2007-10-16"), "adahy windshot", 4.22},
{-1248, "Needle In a Haystack", pt("1988-09-06"), "shikpa longmoon", 0.7},
{5099, "Greased Lightning", pt("1989-06-04"), "helushka emberhair", 2.72},
{8064, "Let Her Rip", pt("1981-01-13"), "geashkoo grassdream", 1.6},
{5099, "Up In Arms", pt("1981-01-13"), "oonnak hardrage", 0.58},
}
)
n := NewNode()
// These 3 rows are under n, and share the same auto-width schema.
n.Push(data[0]...)
m, _ := n.Push(data[1]...)
n.Push(data[2]...)
// By default, Push() creates nodes that always share the same schema, even for different node level.
// We explictly create a typesetted row, and PushRow() it to the node m.
r := NewRow(
WithRowData(data[3]...),
WithRowColumns(
NewColumn(WithLeftAlignment()),
NewColumn(WithWidth(24)),
NewColumn(),
NewColumn(WithLeftAlignment()),
NewColumn(WithWidth(0)),
),
)
// Push it to the 2nd to create a new context (just like a new folder)
// Now data[3] is under node m.
_, err := m.PushRow(r)
if err != nil {
panic(err)
}
// These 2 rows are also under node m and data 3, 4, 5 share the same schema.
m.Push(data[4]...)
m.Push(data[5]...)
Print(n, WithColSep("|"))
Output: 21196| Keep On Truckin'|1999-05-17 00:00:00 +0000 UTC|ahote glowtusks|9.75 -1162| Cry Wolf|2007-10-16 00:00:00 +0000 UTC| adahy windshot|4.22 5099| Greased Lightning|1989-06-04 00:00:00 +0000 UTC|helushka emberhair |2.72 8064| Let Her Rip|1981-01-13 00:00:00 +0000 UTC|geashkoo grassdream|1.6 5099| Up In Arms|1981-01-13 00:00:00 +0000 UTC|oonnak hardrage |0.58 -1248|Needle In a Haystack|1988-09-06 00:00:00 +0000 UTC|shikpa longmoon| 0.7
Example (Sort) ¶
var (
pt = func(date string) time.Time {
t, _ := time.Parse("2006-01-02", date)
return t
}
data = [][]interface{}{
{21196, "Keep On Truckin'", pt("1999-05-17"), "ahote glowtusks", 9.75},
{-1162, "Cry Wolf", pt("2007-10-16"), "adahy windshot", 4.22},
{-1248, "Needle In a Haystack", pt("1988-09-06"), "shikpa longmoon", 0.7},
{50994, "Greased Lightning", pt("1989-06-04"), "helushka emberhair", 2.72},
{80640, "Let Her Rip", pt("1981-01-13"), "geashkoo grassdream", 1.6},
{50997, "Up In Arms", pt("1981-01-13"), "oonnak hardrage", 0.58},
}
)
n := NewNode()
for _, row := range data {
n.Push(row...)
}
// Sort on 3rd column, note that it compares raw value, not the string representation.
n.Sort(2)
Print(n)
Output: 80640 Let Her Rip 1981-01-13 00:00:00 +0000 UTC geashkoo grassdream 1.6 50997 Up In Arms 1981-01-13 00:00:00 +0000 UTC oonnak hardrage 0.58 -1248 Needle In a Haystack 1988-09-06 00:00:00 +0000 UTC shikpa longmoon 0.7 50994 Greased Lightning 1989-06-04 00:00:00 +0000 UTC helushka emberhair 2.72 21196 Keep On Truckin' 1999-05-17 00:00:00 +0000 UTC ahote glowtusks 9.75 -1162 Cry Wolf 2007-10-16 00:00:00 +0000 UTC adahy windshot 4.22
Example (SortRecursively) ¶
var (
pt = func(date string) time.Time {
t, _ := time.Parse("2006-01-02", date)
return t
}
data = [][]interface{}{
{21196, "Keep On Truckin'", pt("1999-05-17"), "ahote glowtusks", 9.75},
{-1162, "Cry Wolf", pt("2007-10-16"), "adahy windshot", 4.22},
{-1248, "Needle In a Haystack", pt("1988-09-06"), "shikpa longmoon", 0.7},
{50994, "Greased Lightning", pt("1989-06-04"), "helushka emberhair", 2.72},
{80640, "Let Her Rip", pt("1981-01-13"), "geashkoo grassdream", 1.6},
{50997, "Up In Arms", pt("1981-01-13"), "oonnak hardrage", 0.58},
}
)
n := NewNode()
// These 3 rows are under n
n.Push(data[0]...)
n.Push(data[1]...)
m, _ := n.Push(data[2]...)
// These 3 rows are under m
m.Push(data[3]...)
m.Push(data[4]...)
m.Push(data[5]...)
// Sort n affects only data 0, 1, 2. So you can sort differently per node level.
n.Sort(0)
m.Sort(0, WithDescending())
Print(n)
fmt.Println("===")
// Or recursively sort by Walk()
n.Sort(1)
n.Walk(func(c *Node) {
c.Sort(1)
})
Print(n)
Output: -1248 Needle In a Haystack 1988-09-06 00:00:00 +0000 UTC shikpa longmoon 0.7 80640 Let Her Rip 1981-01-13 00:00:00 +0000 UTC geashkoo grassdream 1.6 50997 Up In Arms 1981-01-13 00:00:00 +0000 UTC oonnak hardrage 0.58 50994 Greased Lightning 1989-06-04 00:00:00 +0000 UTC helushka emberhair 2.72 -1162 Cry Wolf 2007-10-16 00:00:00 +0000 UTC adahy windshot 4.22 21196 Keep On Truckin' 1999-05-17 00:00:00 +0000 UTC ahote glowtusks 9.75 === -1162 Cry Wolf 2007-10-16 00:00:00 +0000 UTC adahy windshot 4.22 21196 Keep On Truckin' 1999-05-17 00:00:00 +0000 UTC ahote glowtusks 9.75 -1248 Needle In a Haystack 1988-09-06 00:00:00 +0000 UTC shikpa longmoon 0.7 50994 Greased Lightning 1989-06-04 00:00:00 +0000 UTC helushka emberhair 2.72 80640 Let Her Rip 1981-01-13 00:00:00 +0000 UTC geashkoo grassdream 1.6 50997 Up In Arms 1981-01-13 00:00:00 +0000 UTC oonnak hardrage 0.58
Index ¶
- func MustToString(a interface{}) string
- func Print(n *Node, opts ...PrintingOpt)
- type CmpFn
- type Column
- type ColumnOpt
- type ColumnSchema
- type Node
- func (n *Node) EachNode(fn func(*Node))
- func (n *Node) IsNotRoot() bool
- func (n *Node) NodesCount() int
- func (n *Node) Parent() *Node
- func (n *Node) Push(a ...interface{}) (newNode *Node, err error)
- func (n *Node) PushNode(in *Node) (inMutated *Node, err error)
- func (n *Node) PushRow(r *Row) (newNode *Node, err error)
- func (n *Node) Row() *Row
- func (n *Node) Schema() *ColumnSchema
- func (n *Node) Sort(col int, opts ...SortOpt) error
- func (n *Node) String() string
- func (n *Node) Walk(fn func(*Node))
- type NodeOpt
- type Printing
- type PrintingOpt
- type Row
- type RowOpt
- type SortOpt
- Bugs
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MustToString ¶
func MustToString(a interface{}) string
Converts anything to a string. The function itself handles the common types including: fmt.Stringer, string, []byte, uint, int and nil. It passes anything else to the fmt.Sprintf to get the string representation of that value. It is used when initializing a Row instance.
Types ¶
type CmpFn ¶
type CmpFn func(a, b interface{}) bool
A comparator looks like this:
func(a, b interface{}) {
return a.(int) < b.(int)
}
It is passed to generate a sort.Less() function.
type Column ¶
type Column struct {
// contains filtered or unexported fields
}
Stores alignment and width.
type ColumnOpt ¶
type ColumnOpt func(*Column)
func WithLeftAlignment ¶
func WithLeftAlignment() ColumnOpt
Set to pad to the right. For example: WithWidth(20), WithLeftAlignment() = "%-20s".
type ColumnSchema ¶
type ColumnSchema struct {
// contains filtered or unexported fields
}
Defines how many columns in a row and their corresponding Column data.
func NewSchema ¶
func NewSchema(c ...Column) *ColumnSchema
func NewSchemaFrom ¶
func NewSchemaFrom(fields []interface{}) *ColumnSchema
Creates a column schema instance with N columns. N is the length of input fields.
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Tree node.
func NewNode ¶
Returns a pointer to a Node instance. Node options are:
WithRow(*Row): creates a node with provided Row instance.
WithSchema(*ColumnSchema): to inherit the schema from an existing row or node to be applied to all of its children.
WithColumns(...Column): to create a node with provided column schema to be applied to all of its children.
func (*Node) Push ¶
Creates a node to store the inputs and makes it a child of the current receiver. Returns a pointer to the created node and any error encountered.
The parent of the receiver applys its schema to the inputs being pushed. That is, all the column numbers, width and padding of the inputs inherits the schema that is shared among entire tree.
If the reciever has no schema, i.e. a root node without children. A schema instance will be generated based on the first pushed input. The self-generated schema instance is always of columns with auto-width and right-alignment.
Use PushRow() or PushNode() to create tree containing different schemas per node.
The column (fields) amount of the input doesn't have to be the same with receiver's. It will be enlarged (with empty string) or shrinked to fit the receiver's schema.
func (*Node) PushNode ¶
Makes incoming node become a child of the receiver. Returns a pointer to the mutated incoming node and any error encountered.
Consistency is maintained by comparing each other's node.schema and node.row.schema. Receiver(A) accepts incoming node(B) if:
1. A has no node schema, B contains a Row instance. 2. A has no node schema, B contains no Row instance, but B has node schema (tree root) 3. A has node schema, B contains no Row instance. (tree root) 4. A has node schema, B contains a Row instance with the schema which is exactly A's node schema.
BUG(adios): Use carefully, no loop detections.
func (*Node) PushRow ¶
Accepts a customized Row. Returns a pointer to the created node and any error encountered.
func (*Node) Schema ¶
func (n *Node) Schema() *ColumnSchema
Returns the schema instance of current receiver.
func (*Node) Sort ¶
Sort receiver's child nodes (that contain rows) on the given column of that node's row. Accepts a column index starting from 0. Returns any error encountered.
It uses stable sort to compare the raw value of the specified column field. Sort on values with non identical type returns an error. Sort on values with no type comparators returns an error.
Note that it doesn't sort descendants.
Sorting options are:
WithDescending(): default is ascending.
WithCmpMatchers(...func(a interface{}) CmpFn): to sort more types. Builtins: int, string and time.Time.
type NodeOpt ¶
type NodeOpt func(*Node)
func WithColumns ¶
To create a node with provided column schema to be applied to all of its children.
func WithSchema ¶
func WithSchema(s *ColumnSchema) NodeOpt
To inherit the schema from an existing row or node to be applied to all of its children.
type Printing ¶
type Printing struct {
// contains filtered or unexported fields
}
Algorithm for printing.
func NewPrinting ¶
func NewPrinting(opts ...PrintingOpt) *Printing
Printing options are:
WithColSep(string): set column separator (field separator). Defaults to " ".
WithLineBrk(string): set line break. Defaults to "\n".
WithWriter(io.Writer): set writer. Defaults to os.Stdout.
type PrintingOpt ¶
type PrintingOpt func(*Printing)
func WithColSep ¶
func WithColSep(sep string) PrintingOpt
Set column separator (field separator). Defaults to " ".
type Row ¶
type Row struct {
// contains filtered or unexported fields
}
Stores both raw input values and their string representations.
func NewRow ¶
Returns a pointer to a Row instance. Row options are:
WithRowSchema(*ColumnSchema): to inherit the schema from an existing row or node.
WithRowColumns(...Column): to create a row with provided column schema.
WithData(...interface{}): set data to the row.
func (*Row) EachFmtStr ¶
Traverses format strings with String() on each Column instance.
func (*Row) FmtArgs ¶
func (r *Row) FmtArgs() []interface{}
Returns the string slice that stores the string representations of raw values.
func (*Row) Schema ¶
func (r *Row) Schema() *ColumnSchema
type RowOpt ¶
type RowOpt func(*Row)
func WithRowColumns ¶
To create a row with provided column schema.
func WithRowSchema ¶
func WithRowSchema(s *ColumnSchema) RowOpt
To inherit the schema from an existing row or node.
type SortOpt ¶
type SortOpt func(*sortable)
func WithCmpMatchers ¶
Multiple matcher functions can be provided as input. The method executes them in order until a matcher can handle the current comparing type. A finder should look like this:
func(a interface{}) {
// you can do type switch on a to find a exact type of the input value,
// or simply ignores it if you know in advance the field type you are comparing to.
return func(a, b interface{}) { return a.(int) < b.(int) }
}
See MatchCmp() to learn how to write a matcher.
func WithDescending ¶
func WithDescending() SortOpt
Notes ¶
Bugs ¶
Use carefully, no loop detections.