You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cointop/pkg/table/table.go

226 lines
3.7 KiB
Go

package table
import (
"fmt"
"io"
"sort"
"strings"
"github.com/miguelmota/cointop/pkg/table/align"
)
// Table table
type Table struct {
cols Cols
rows Rows
sort []SortBy
width int
HideColumHeaders bool
}
// New new table
func New() *Table {
return &Table{}
}
// SetWidth set table width
func (t *Table) SetWidth(w int) *Table {
t.width = w
return t
}
// AddCol add column
func (t *Table) AddCol(n string) *Col {
c := &Col{name: n}
t.cols = append(t.cols, c)
return c
}
// AddRow add row
func (t *Table) AddRow(v ...interface{}) *Row {
r := &Row{table: t, values: v, strValues: make([]string, len(v))}
t.rows = append(t.rows, r)
return r
}
// SortAscFn sort ascending function
func (t *Table) SortAscFn(n string, fn SortFn) *Table {
i := t.cols.Index(n)
s := SortBy{index: i, order: SortAsc, sortFn: fn}
t.sort = append(t.sort, s)
return t
}
// SortAsc sort ascending
func (t *Table) SortAsc(n string) *Table {
return t.SortAscFn(n, nil)
}
// SortDescFn sort descending function
func (t *Table) SortDescFn(n string, fn SortFn) *Table {
i := t.cols.Index(n)
s := SortBy{index: i, order: SortDesc, sortFn: fn}
t.sort = append(t.sort, s)
return t
}
// SortDesc sort descending
func (t *Table) SortDesc(n string) *Table {
return t.SortDescFn(n, nil)
}
// Sort sort
func (t *Table) Sort() *Table {
if len(t.sort) > 0 {
sort.Sort(t.rows)
}
return t
}
func (t *Table) colWidth() int {
width := 0
for _, c := range t.cols {
if c.hide {
continue
}
width += c.width
}
return width
}
func (t *Table) normalizeColWidthPerc() {
perc := 0
for _, c := range t.cols {
if c.hide {
continue
}
perc += c.minWidthPerc
}
for _, c := range t.cols {
if c.hide {
continue
}
c.perc = float32(c.minWidthPerc) / float32(perc)
}
}
// Format format table
func (t *Table) Format() *Table {
for _, c := range t.cols {
c.width = len(c.name) + 1
if c.minWidth > c.width {
c.width = c.minWidth
}
}
for _, r := range t.rows {
for j, v := range r.values {
c := t.cols[j]
if c.hide {
continue
}
if c.formatFn != nil {
r.strValues[j] = fmt.Sprintf("%s", c.formatFn(v)) + " "
} else if c.format != "" {
r.strValues[j] = fmt.Sprintf(c.format, v) + " "
} else {
r.strValues[j] = fmt.Sprintf("%v", v) + " "
}
if len(r.strValues[j]) > t.cols[j].width {
t.cols[j].width = len(r.strValues[j])
}
}
}
//t.normalizeColWidthPerc()
unused := t.width - t.colWidth()
if unused <= 0 {
return t
}
for _, c := range t.cols {
if c.hide {
continue
}
if c.perc > 0 {
c.width += int(float32(unused) * c.perc)
}
}
var i int
for i = len(t.cols) - 1; i >= 0; i-- {
if t.cols[i].hide {
continue
}
break
}
t.cols[i].width += t.width - t.colWidth()
return t
}
// Fprint write
func (t *Table) Fprint(w io.Writer) {
if !t.HideColumHeaders {
for _, c := range t.cols {
if c.hide {
continue
}
var s string
switch c.align {
case AlignLeft:
s = align.AlignLeft(c.name+" ", c.width)
case AlignRight:
s = align.AlignRight(c.name+" ", c.width)
case AlignCenter:
s = align.AlignCenter(c.name+" ", c.width)
}
fmt.Fprintf(w, "%s", s)
}
fmt.Fprintf(w, "\n")
for _, c := range t.cols {
if c.hide {
continue
}
fmt.Fprintf(w, strings.Repeat("─", c.width))
}
fmt.Fprintf(w, "\n")
}
for _, r := range t.rows {
for i, v := range r.strValues {
c := t.cols[i]
if c.hide {
continue
}
var s string
switch c.align {
case AlignLeft:
s = align.AlignLeft(v, c.width)
case AlignRight:
s = align.AlignRight(v, c.width)
case AlignCenter:
s = align.AlignCenter(v, c.width)
}
fmt.Fprintf(w, "%s", s)
}
fmt.Fprintf(w, "\n")
}
}