Documentation ¶
Overview ¶
Package psv provides a way to convert arrays of structs or maps into pretty, pipe-separated text tables, and vice-versa. (psv: pipe separated values)
Example
data := []map[string]string{ {"name":"Joe", "age":"42"}, {"name":"Freddie", "age":"41"}, {"name":"Amy", "age":"don't ask"}, } tbl := table.Marshal(data) tbl.Columns = []string{"age","name"} tbl.Indent = " " tbl.Decorations = []table.Decoration{ {Line:0,Text:`The "who's-who" list of people`}, {Line:1}, {Line:2,Ruler:"+ -"}, {Line:4,Ruler:"|==="}, } fmt.Println(tbl.Encode())
Output
The "who's-who" list of people + --------- + ------- + | age | name | |=====================| | 42 | Joe | | 41 | Freddie | | don't ask | Amy |
The table data and appearance can be set up via any of the following examples:
// convert a string into a table tbl := table.Decode(string) // all decorations are retained for re-rendering, e.g. fmt.Println(tbl.Encode()) // convert a string into a data structure // data returned in interface{} table.Unmarshal(string,interface{}) // create a table from scratch (string data only) tbl := table.NewTable() tbl.Indent = "..." tbl.Decorations = []*Decoration{...} tbl.Data = [][]string{...} fmt.Println(tbl.Encode()) // convert a data structure into a table (for rendering) tbl := table.Marshal(interface{}) // optionally modify aspects of the table tbl.Indent = "..." tbl.Decorations = []*Decoration{...} fmt.Println(tbl.Encode())
References ¶
This package focusses on data representation, human readability and the exchange of intentions, which a computer may incidentally be able to make sense of. Mostly, each cell of a table is a simple, single string value, however, with a bit of additional work, the string values may be mapped to slices or maps of slightly more complicated (incl. custom) structures.
The lack of support for every last, complicated, nested structure is intentional.
There a large number of csv, tsv, dsv packages availble on pkg.go.dev, but they all concentrate on "machine readable data exchange". Nevertheless, they served as inspiration for this package as well.
psv always *felt* like the wrong program to write, but I was unable to find an existing program with suitable features:
- simple to use, suitable for as an editor plugin / shell pipe - align columnated data - while ignoring lines which aren't columnated
The unix tools [column] and [tbl] and go's own encoding/csv package all served as a good basis, but they all had different goals.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var Version = `v0.0.6`
Functions ¶
This section is empty.
Types ¶
type Decoration ¶
type Decoration struct { Line int // 1-based number of this line's position in the resulting table Indent string // only used to re-construct original indentation outside a table's bounds Text string // un-indented text to be inserted into the table, may be "" Ruler string // ruler specification, see Ruler type }
Decoration specifies a single non-table text line to be positioned at a specific point in the generated table string.
type Indenter ¶
type Indenter struct {
// contains filtered or unexported fields
}
Example ¶
inputLines := []string{ ``, `hello`, ` hello`, `// hello`, `// // hello`, ` // hello`, } patterns := []struct { pattern string isFinal bool }{ {pattern: ""}, {pattern: ``, isFinal: true}, {pattern: `0`}, {pattern: `-1`}, {pattern: `-0`}, {pattern: `+1`}, {pattern: `1`}, {pattern: `63`}, {pattern: `64`}, {pattern: ` `}, {pattern: `//`}, {pattern: ` //`}, {pattern: ` // `}, {pattern: `> >`}, {pattern: ` > >`}, {pattern: ` > > `}, } PATTERNS: for _, p := range patterns { for _, l := range inputLines { i := NewIndenter() fmt.Printf("indent option: %q\n", p.pattern) if p.pattern != "" || p.isFinal { err := i.SetIndent(p.pattern) if err != nil { fmt.Printf("failed to set indent: %q\n\n", err) continue PATTERNS } } fmt.Printf("indenter: %s\n", i.String()) found := i.FindIndent(l) i.FinalizeIndent() fmt.Printf("input line: %q\n", l) fmt.Printf("detected indent: %q\n", found) fmt.Printf("finalised indent: %q\n", i.Indent()+l[len(found):]) fmt.Println() } fmt.Println("----") }
Output: indent option: "" indenter: "" (default) input line: "" detected indent: "" finalised indent: "" indent option: "" indenter: "" (default) input line: "hello" detected indent: "" finalised indent: "hello" indent option: "" indenter: "" (default) input line: " hello" detected indent: " " finalised indent: " hello" indent option: "" indenter: "" (default) input line: "// hello" detected indent: "" finalised indent: "// hello" indent option: "" indenter: "" (default) input line: "// // hello" detected indent: "" finalised indent: "// // hello" indent option: "" indenter: "" (default) input line: " // hello" detected indent: " " finalised indent: " // hello" ---- indent option: "" indenter: "" (finalised) input line: "" detected indent: "" finalised indent: "" indent option: "" indenter: "" (finalised) input line: "hello" detected indent: "" finalised indent: "hello" indent option: "" indenter: "" (finalised) input line: " hello" detected indent: " " finalised indent: "hello" indent option: "" indenter: "" (finalised) input line: "// hello" detected indent: "" finalised indent: "// hello" indent option: "" indenter: "" (finalised) input line: "// // hello" detected indent: "" finalised indent: "// // hello" indent option: "" indenter: "" (finalised) input line: " // hello" detected indent: " " finalised indent: "// hello" ---- indent option: "0" indenter: "" (finalised) input line: "" detected indent: "" finalised indent: "" indent option: "0" indenter: "" (finalised) input line: "hello" detected indent: "" finalised indent: "hello" indent option: "0" indenter: "" (finalised) input line: " hello" detected indent: " " finalised indent: "hello" indent option: "0" indenter: "" (finalised) input line: "// hello" detected indent: "" finalised indent: "// hello" indent option: "0" indenter: "" (finalised) input line: "// // hello" detected indent: "" finalised indent: "// // hello" indent option: "0" indenter: "" (finalised) input line: " // hello" detected indent: " " finalised indent: "// hello" ---- indent option: "-1" failed to set indent: "indent must be an unsigned integer <64 or non-numeric string" indent option: "-0" failed to set indent: "indent must be an unsigned integer <64 or non-numeric string" indent option: "+1" failed to set indent: "indent must be an unsigned integer <64 or non-numeric string" indent option: "1" indenter: " " (finalised) input line: "" detected indent: "" finalised indent: " " indent option: "1" indenter: " " (finalised) input line: "hello" detected indent: "" finalised indent: " hello" indent option: "1" indenter: " " (finalised) input line: " hello" detected indent: " " finalised indent: " hello" indent option: "1" indenter: " " (finalised) input line: "// hello" detected indent: "" finalised indent: " // hello" indent option: "1" indenter: " " (finalised) input line: "// // hello" detected indent: "" finalised indent: " // // hello" indent option: "1" indenter: " " (finalised) input line: " // hello" detected indent: " " finalised indent: " // hello" ---- indent option: "63" indenter: " " (finalised) input line: "" detected indent: "" finalised indent: " " indent option: "63" indenter: " " (finalised) input line: "hello" detected indent: "" finalised indent: " hello" indent option: "63" indenter: " " (finalised) input line: " hello" detected indent: " " finalised indent: " hello" indent option: "63" indenter: " " (finalised) input line: "// hello" detected indent: "" finalised indent: " // hello" indent option: "63" indenter: " " (finalised) input line: "// // hello" detected indent: "" finalised indent: " // // hello" indent option: "63" indenter: " " (finalised) input line: " // hello" detected indent: " " finalised indent: " // hello" ---- indent option: "64" failed to set indent: "indent must be an unsigned integer <64 or non-numeric string" indent option: " " indenter: " " (finalised) input line: "" detected indent: "" finalised indent: " " indent option: " " indenter: " " (finalised) input line: "hello" detected indent: "" finalised indent: " hello" indent option: " " indenter: " " (finalised) input line: " hello" detected indent: " " finalised indent: " hello" indent option: " " indenter: " " (finalised) input line: "// hello" detected indent: "" finalised indent: " // hello" indent option: " " indenter: " " (finalised) input line: "// // hello" detected indent: "" finalised indent: " // // hello" indent option: " " indenter: " " (finalised) input line: " // hello" detected indent: " " finalised indent: " // hello" ---- indent option: "//" indenter: "//" (default) input line: "" detected indent: "" finalised indent: "// " indent option: "//" indenter: "//" (default) input line: "hello" detected indent: "" finalised indent: "// hello" indent option: "//" indenter: "//" (default) input line: " hello" detected indent: " " finalised indent: "// hello" indent option: "//" indenter: "//" (default) input line: "// hello" detected indent: "// " finalised indent: "// hello" indent option: "//" indenter: "//" (default) input line: "// // hello" detected indent: "// // " finalised indent: "// // hello" indent option: "//" indenter: "//" (default) input line: " // hello" detected indent: " // " finalised indent: " // hello" ---- indent option: " //" indenter: " //" (finalised) input line: "" detected indent: "" finalised indent: " //" indent option: " //" indenter: " //" (finalised) input line: "hello" detected indent: "" finalised indent: " //hello" indent option: " //" indenter: " //" (finalised) input line: " hello" detected indent: " " finalised indent: " //hello" indent option: " //" indenter: " //" (finalised) input line: "// hello" detected indent: "// " finalised indent: " //hello" indent option: " //" indenter: " //" (finalised) input line: "// // hello" detected indent: "// // " finalised indent: " //hello" indent option: " //" indenter: " //" (finalised) input line: " // hello" detected indent: " // " finalised indent: " //hello" ---- indent option: " // " indenter: " // " (finalised) input line: "" detected indent: "" finalised indent: " // " indent option: " // " indenter: " // " (finalised) input line: "hello" detected indent: "" finalised indent: " // hello" indent option: " // " indenter: " // " (finalised) input line: " hello" detected indent: " " finalised indent: " // hello" indent option: " // " indenter: " // " (finalised) input line: "// hello" detected indent: "// " finalised indent: " // hello" indent option: " // " indenter: " // " (finalised) input line: "// // hello" detected indent: "// // " finalised indent: " // hello" indent option: " // " indenter: " // " (finalised) input line: " // hello" detected indent: " // " finalised indent: " // hello" ---- indent option: "> >" indenter: "> >" (default) input line: "" detected indent: "" finalised indent: "> > " indent option: "> >" indenter: "> >" (default) input line: "hello" detected indent: "" finalised indent: "> > hello" indent option: "> >" indenter: "> >" (default) input line: " hello" detected indent: " " finalised indent: "> > hello" indent option: "> >" indenter: "> >" (default) input line: "// hello" detected indent: "" finalised indent: "> > // hello" indent option: "> >" indenter: "> >" (default) input line: "// // hello" detected indent: "" finalised indent: "> > // // hello" indent option: "> >" indenter: "> >" (default) input line: " // hello" detected indent: " " finalised indent: "> > // hello" ---- indent option: " > >" indenter: " > >" (finalised) input line: "" detected indent: "" finalised indent: " > >" indent option: " > >" indenter: " > >" (finalised) input line: "hello" detected indent: "" finalised indent: " > >hello" indent option: " > >" indenter: " > >" (finalised) input line: " hello" detected indent: " " finalised indent: " > >hello" indent option: " > >" indenter: " > >" (finalised) input line: "// hello" detected indent: "" finalised indent: " > >// hello" indent option: " > >" indenter: " > >" (finalised) input line: "// // hello" detected indent: "" finalised indent: " > >// // hello" indent option: " > >" indenter: " > >" (finalised) input line: " // hello" detected indent: " " finalised indent: " > >// hello" ---- indent option: " > > " indenter: " > > " (finalised) input line: "" detected indent: "" finalised indent: " > > " indent option: " > > " indenter: " > > " (finalised) input line: "hello" detected indent: "" finalised indent: " > > hello" indent option: " > > " indenter: " > > " (finalised) input line: " hello" detected indent: " " finalised indent: " > > hello" indent option: " > > " indenter: " > > " (finalised) input line: "// hello" detected indent: "" finalised indent: " > > // hello" indent option: " > > " indenter: " > > " (finalised) input line: "// // hello" detected indent: "" finalised indent: " > > // // hello" indent option: " > > " indenter: " > > " (finalised) input line: " // hello" detected indent: " " finalised indent: " > > // hello" ----
func NewIndenter ¶
func NewIndenter() *Indenter
func (*Indenter) FinalizeIndent ¶
func (i *Indenter) FinalizeIndent()
func (*Indenter) FindIndent ¶
type Options ¶
type Options struct { Squash bool // squash multiple blank lines into a single blank line when encoding Quotes string // prioritized list of preferred quoting styles IndentPattern string // user-provided indent to use IndentIsFinal bool // flag to force the use of Options.Indent (required to force the use of "") }
type Ruler ¶
type Ruler struct {
// contains filtered or unexported fields
}
Ruler represents a horizontal separator to be placed within a table.
Rulers only contain the characters |, :, *, +, - and optional spaces.
When a table is rendered, rulers are generated to fit the column widths of the table.
If the input string contains 4 runes or less, it is intepreted as a format:
e.g. '| -:' |||+-- internal column separator ||+--- horizonal line |+---- padding +----- outer border
If the input string is more than 4 runes, it is assumed to be a previously-generated ruler, and is analysed to determine the format.
If the format of a ruler cannot be determined, the 'border' rune will be 0 and the original input is used. (non-destructive failure)
func NewRuler ¶
NewRuler creates a new ruler based on a format or previously rendered ruler. Note: a returned error is really only a warning! The returned *Ruler is still valid and usable!
type Table ¶
type Table struct { Options // configuration options *Indenter // indent matcher and producer FirstRow int // first row of table data LastRow int // last row of table data Data [][]string // 2-Dimensional array of string cells indexed by [row][column] Decorations []*Decoration // an array of decorations to add to the table }
Table is a structure used to encapsulate a table of string data, which can be re-rendered with correct indentation and column alignment. The exported fields of Table may be used to customize the rendered result.
func NewTable ¶
func NewTable() *Table
NewTable creates a new, empty table. Use its public fields to setup the data to be printed. See also: encode_test.go