Skip to content

Instantly share code, notes, and snippets.

@dallasmarlow
Last active August 29, 2015 14:08
Show Gist options
  • Save dallasmarlow/5fcf623e58ecb127b52a to your computer and use it in GitHub Desktop.
Save dallasmarlow/5fcf623e58ecb127b52a to your computer and use it in GitHub Desktop.
text tables
package texttable
import (
"bytes"
"errors"
"fmt"
"strconv"
"strings"
"text/tabwriter"
)
const (
ErrInvalidCellType = "unsupported cell type encountered: %t"
ErrInvalidRowLength = "row length %d does not match existing table column count %d"
DefaultMinWidth = 0
DefaultTabWidth = 8
DefaultCellPadding = 1
DefaultHeaderChar = '-'
DefaultPaddingChar = '\t'
DefaultFormatFlags = 0
)
type Table struct {
tabwriter.Writer
Buf *bytes.Buffer
numCols, MinWidth, TabWidth, CellPadding int
HeaderChar, PaddingChar byte
FormatFlags uint
}
func NewDefaultTable() *Table {
table := &Table{
Buf: new(bytes.Buffer),
MinWidth: DefaultMinWidth,
TabWidth: DefaultTabWidth,
CellPadding: DefaultCellPadding,
HeaderChar: DefaultHeaderChar,
PaddingChar: DefaultPaddingChar,
FormatFlags: DefaultFormatFlags,
}
// initialize tab writer
table.Init(
table.Buf,
table.MinWidth,
table.TabWidth,
table.CellPadding,
table.PaddingChar,
table.FormatFlags)
return table
}
func (t *Table) String() string {
t.Flush()
return t.Buf.String()
}
func (t *Table) AddRow(cells ...interface{}) error {
row, err := t.formatCells(cells...)
if err != nil {
return err
}
fmt.Fprintln(t, t.formatRow(row))
return nil
}
func (t *Table) AddHeader(cells ...interface{}) error {
headers, err := t.formatCells(cells...)
if err != nil {
return err
}
fmt.Fprintln(t, t.formatRow(headers))
var headerBorders []string
for _, header := range headers {
headerBorders = append(headerBorders, strings.Repeat(string(t.HeaderChar), strings.Count(header, "")-1))
}
fmt.Fprintln(t, t.formatRow(headerBorders))
return nil
}
func (t *Table) formatCells(cells ...interface{}) ([]string, error) {
numCells := len(cells)
switch {
case t.numCols == 0:
t.numCols = numCells
case t.numCols != numCells:
return nil, errors.New(fmt.Sprintf(ErrInvalidRowLength, numCells, t.numCols))
}
var row []string
for _, cell := range cells {
switch cell.(type) {
case string:
row = append(row, cell.(string))
case []string:
row = append(row, cell.([]string)...)
case bool:
row = append(row, strconv.FormatBool(cell.(bool)))
case int:
row = append(row, strconv.Itoa(cell.(int)))
case int64:
row = append(row, strconv.FormatInt(cell.(int64), 10))
case uint64:
row = append(row, strconv.FormatUint(cell.(uint64), 10))
case float64:
row = append(row, strconv.FormatFloat(cell.(float64), 'f', -1, 64))
default:
return nil, errors.New(fmt.Sprintf(ErrInvalidCellType, cell))
}
}
return row, nil
}
func (t *Table) formatRow(cells []string) string {
return strings.Join(cells, string(t.PaddingChar))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment