| package main | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"strings" | 
 | ) | 
 |  | 
 | // table is a list of entries that form a table with sparse columns. Each entry | 
 | // defines its own columns. | 
 | type table struct { | 
 | 	entries []entry | 
 | } | 
 |  | 
 | // add an entry to the table. | 
 | func (t *table) add(e entry) { | 
 | 	t.entries = append(t.entries, e) | 
 | } | 
 |  | 
 | // An entry is made up of column key -> value pairs. | 
 | type entry struct { | 
 | 	columns []entryColumn | 
 | } | 
 |  | 
 | // add a key/value pair to the entry. | 
 | func (e *entry) add(key, value string) { | 
 | 	e.columns = append(e.columns, entryColumn{ | 
 | 		key:   key, | 
 | 		value: value, | 
 | 	}) | 
 | } | 
 |  | 
 | // get a value from a given key, returning zero string if not set. | 
 | func (e *entry) get(key string) string { | 
 | 	for _, col := range e.columns { | 
 | 		if col.key == key { | 
 | 			return col.value | 
 | 		} | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | // An entryColumn is a pair for table column key and entry column value. | 
 | type entryColumn struct { | 
 | 	key   string | 
 | 	value string | 
 | } | 
 |  | 
 | // columns returns the keys and widths of columns that are present in the table's | 
 | // entries. | 
 | func (t *table) columns() columns { | 
 | 	var res columns | 
 | 	for _, e := range t.entries { | 
 | 		for _, c := range e.columns { | 
 | 			tc := res.upsert(c.key) | 
 | 			if len(c.value) > tc.width { | 
 | 				tc.width = len(c.value) | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return res | 
 | } | 
 |  | 
 | type columns []*column | 
 |  | 
 | // A column in a table, not containing all entries that make up this table, but | 
 | // containing their maximum width (for layout purposes). | 
 | type column struct { | 
 | 	// key is the column key. | 
 | 	key string | 
 | 	// width is the maximum width (in runes) of all the entries' data in this column. | 
 | 	width int | 
 | } | 
 |  | 
 | // upsert a key into a list of columns, returning the upserted column. | 
 | func (c *columns) upsert(key string) *column { | 
 | 	for _, col := range *c { | 
 | 		if col.key == key { | 
 | 			return col | 
 | 		} | 
 | 	} | 
 | 	col := &column{ | 
 | 		key:   key, | 
 | 		width: len(key), | 
 | 	} | 
 | 	*c = append(*c, col) | 
 | 	return col | 
 | } | 
 |  | 
 | // filter returns a copy of columns where the only columns present are the ones | 
 | // whose onlyColumns values are true. If only columns is nil, no filtering takes | 
 | // place (all columns are returned). | 
 | func (c columns) filter(onlyColumns map[string]bool) columns { | 
 | 	var res []*column | 
 | 	for _, cc := range c { | 
 | 		if onlyColumns != nil && !onlyColumns[cc.key] { | 
 | 			continue | 
 | 		} | 
 | 		res = append(res, cc) | 
 | 	} | 
 | 	return res | 
 | } | 
 |  | 
 | // printHeader writes a table-like header to the given file, keeping margin | 
 | // spaces between columns. | 
 | func (c columns) printHeader(f io.Writer, margin int) { | 
 | 	for _, cc := range c { | 
 | 		fmt.Fprintf(f, "%-*s", cc.width+margin, strings.ToUpper(cc.key)) | 
 | 	} | 
 | 	fmt.Fprintf(f, "\n") | 
 | } | 
 |  | 
 | // print writes a table-like representation of this table to the given file, | 
 | // first filtering the columns by onlyColumns (if not set, no filtering takes | 
 | // place). | 
 | func (t *table) print(f io.Writer, onlyColumns map[string]bool) { | 
 | 	margin := 3 | 
 | 	cols := t.columns().filter(onlyColumns) | 
 | 	cols.printHeader(f, margin) | 
 |  | 
 | 	for _, e := range t.entries { | 
 | 		for _, c := range cols { | 
 | 			v := e.get(c.key) | 
 | 			fmt.Fprintf(f, "%-*s", c.width+margin, v) | 
 | 		} | 
 | 		fmt.Fprintf(f, "\n") | 
 | 	} | 
 | } |