2
0
mirror of https://github.com/miguelmota/cointop synced 2024-11-12 07:10:26 +00:00
cointop/pkg/table/table.go

280 lines
4.9 KiB
Go
Raw Normal View History

2018-03-29 22:02:24 +00:00
package table
import (
"fmt"
"io"
"sort"
"strings"
"unicode/utf8"
2018-03-29 22:02:24 +00:00
"github.com/acarl005/stripansi"
2021-09-30 06:17:58 +00:00
"github.com/cointop-sh/cointop/pkg/pad"
"github.com/cointop-sh/cointop/pkg/table/align"
2018-03-29 22:02:24 +00:00
)
// Table table
2018-03-29 22:02:24 +00:00
type Table struct {
cols Cols
rows Rows
sort []SortBy
width int
HideColumHeaders bool
}
2020-11-21 22:22:28 +00:00
// NewTable new table
func NewTable() *Table {
2018-03-29 22:02:24 +00:00
return &Table{}
}
// SetWidth set table width
2018-03-29 22:02:24 +00:00
func (t *Table) SetWidth(w int) *Table {
t.width = w
return t
}
// AddCol add column
2018-03-29 22:02:24 +00:00
func (t *Table) AddCol(n string) *Col {
c := &Col{name: n}
t.cols = append(t.cols, c)
return c
}
// AddRow add row
2018-03-29 22:02:24 +00:00
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
}
2020-11-21 22:22:28 +00:00
// AddRowCells add row using cells
func (t *Table) AddRowCells(cells ...*RowCell) *Row {
t.SetNumCol(len(cells))
v := make([]interface{}, len(cells))
for i, item := range cells {
v[i] = item.String()
}
return t.AddRow(v...)
}
// SetNumCol sets the number of columns
func (t *Table) SetNumCol(count int) {
for i := 0; i < count; i++ {
t.AddCol("")
}
}
// SortAscFn sort ascending function
2018-03-29 22:02:24 +00:00
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
2018-03-29 22:02:24 +00:00
func (t *Table) SortAsc(n string) *Table {
return t.SortAscFn(n, nil)
}
// SortDescFn sort descending function
2018-03-29 22:02:24 +00:00
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
2018-03-29 22:02:24 +00:00
func (t *Table) SortDesc(n string) *Table {
return t.SortDescFn(n, nil)
}
// Sort sort
2018-03-29 22:02:24 +00:00
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
2018-03-29 22:02:24 +00:00
func (t *Table) Format() *Table {
for _, c := range t.cols {
s := stripansi.Strip(c.name)
c.width = utf8.RuneCountInString(s) + 1
2018-03-29 22:02:24 +00:00
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 {
2020-11-21 22:22:28 +00:00
r.strValues[j] = fmt.Sprintf("%s", c.formatFn(v))
2018-03-29 22:02:24 +00:00
} else if c.format != "" {
2020-11-21 22:22:28 +00:00
r.strValues[j] = fmt.Sprintf(c.format, v)
2018-03-29 22:02:24 +00:00
} else {
2020-11-21 22:22:28 +00:00
r.strValues[j] = fmt.Sprintf("%v", v)
2018-03-29 22:02:24 +00:00
}
s := stripansi.Strip(r.strValues[j])
runeCount := utf8.RuneCountInString(s)
if runeCount > t.cols[j].width {
t.cols[j].width = runeCount
2018-03-29 22:02:24 +00:00
}
}
}
//t.normalizeColWidthPerc()
2018-03-29 22:02:24 +00:00
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
}
2020-11-21 22:22:28 +00:00
if len(t.cols) > 0 {
t.cols[i].width += t.width - t.colWidth()
}
2018-03-29 22:02:24 +00:00
return t
}
// Fprint write
2018-03-29 22:02:24 +00:00
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.Left(c.name+" ", c.width)
2018-03-29 22:02:24 +00:00
case AlignRight:
s = align.Right(c.name+" ", c.width)
2018-03-29 22:02:24 +00:00
case AlignCenter:
s = align.Center(c.name+" ", c.width)
2018-03-29 22:02:24 +00:00
}
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.Left(v, c.width)
2018-03-29 22:02:24 +00:00
case AlignRight:
s = align.Right(v, c.width)
2018-03-29 22:02:24 +00:00
case AlignCenter:
s = align.Center(v, c.width)
2018-03-29 22:02:24 +00:00
}
fmt.Fprintf(w, "%s", s)
}
2021-01-19 08:26:48 +00:00
// fill in rest of row with empty spaces to highlight all of row
fmt.Fprintf(w, strings.Repeat(" ", t.width)+"\n")
2018-03-29 22:02:24 +00:00
}
}
2020-11-21 22:22:28 +00:00
2021-02-12 08:40:28 +00:00
// RowCount returns the number of rows
func (t *Table) RowCount() int {
return len(t.rows)
}
2020-11-21 22:22:28 +00:00
// RowCell is a row cell struct
type RowCell struct {
2021-02-05 09:04:09 +00:00
LeftMargin int
RightMargin int
Width int
LeftAlign bool
Color func(a ...interface{}) string
Text string
2020-11-21 22:22:28 +00:00
}
// String returns row cell as string
func (rc *RowCell) String() string {
2021-02-05 09:04:09 +00:00
t := rc.Text
2020-11-21 22:22:28 +00:00
if rc.LeftAlign {
t = pad.Right(t, rc.Width, " ")
} else {
t = fmt.Sprintf("%"+fmt.Sprintf("%v", rc.Width)+"s", t)
}
2021-02-05 09:04:09 +00:00
t = strings.Repeat(" ", rc.LeftMargin) + t + strings.Repeat(" ", rc.RightMargin)
2020-11-21 22:22:28 +00:00
return rc.Color(t)
}