tprint/table.go

144 lines
3.1 KiB
Go
Raw Normal View History

2022-08-25 16:03:24 +02:00
package tprint
2022-08-25 16:00:13 +02:00
import (
"fmt"
"strings"
"git.milar.in/milarin/gmath"
"git.milar.in/milarin/slices"
)
type Table struct {
head [][]string
rowSep bool
headheight int
maxcols int
colwidth []int
rowheight []int
data [][][]string
}
2022-08-25 16:05:14 +02:00
func NewTable(head ...string) *Table {
2022-08-25 16:00:13 +02:00
thead := slices.Map(head, func(s string) []string { return strings.Split(s, "\n") })
return &Table{
head: thead,
colwidth: slices.Map(head, func(s string) int { return strLen(s) }),
headheight: len(slices.Search(thead, maxLengthSlice[string])),
rowheight: []int{},
maxcols: len(thead),
}
}
func (t *Table) AddRow(row ...interface{}) {
irow := slices.Map(row, func(v interface{}) []string { return strings.Split(fmt.Sprint(v), "\n") })
t.data = append(t.data, irow)
rowheight := len(slices.Search(irow, maxLengthSlice[string]))
t.rowheight = append(t.rowheight, rowheight)
if rowheight > 1 {
t.rowSep = true
}
t.maxcols = gmath.Max(t.maxcols, len(irow))
for i, cell := range irow {
maxLineLength := strLen(slices.Search(cell, maxLengthStr))
if i < len(t.colwidth) {
t.colwidth[i] = gmath.Max(t.colwidth[i], maxLineLength)
} else {
t.colwidth = append(t.colwidth, maxLineLength)
}
if i >= len(t.head) {
headname := "unknown column"
t.head = append(t.head, []string{headname})
t.colwidth[i] = gmath.Max(t.colwidth[i], strLen(headname))
}
}
}
func (t *Table) String() string {
b := new(strings.Builder)
2022-08-25 16:55:19 +02:00
b.WriteRune('┏')
2022-08-25 16:00:13 +02:00
for i, colwidth := range t.colwidth {
2022-08-25 16:55:19 +02:00
b.WriteString(strings.Repeat("━", colwidth))
2022-08-25 16:00:13 +02:00
if i < len(t.colwidth)-1 {
2022-08-25 16:55:19 +02:00
b.WriteRune('┯')
2022-08-25 16:00:13 +02:00
}
}
2022-08-25 16:55:19 +02:00
b.WriteRune('┓')
2022-08-25 16:00:13 +02:00
b.WriteRune('\n')
2022-08-25 16:55:19 +02:00
t.printRow(b, t.head, t.headheight)
2022-08-25 16:00:13 +02:00
2022-08-25 16:55:19 +02:00
b.WriteRune('┣')
for i, colwidth := range t.colwidth {
b.WriteString(strings.Repeat("━", colwidth))
if i < len(t.colwidth)-1 {
b.WriteRune('┿')
}
2022-08-25 16:00:13 +02:00
}
2022-08-25 16:55:19 +02:00
b.WriteRune('┫')
b.WriteRune('\n')
2022-08-25 16:00:13 +02:00
for i, row := range t.data {
2022-08-25 16:55:19 +02:00
t.printRow(b, row, t.rowheight[i])
2022-08-25 16:00:13 +02:00
if t.rowSep && i < len(t.data)-1 {
t.addNextCellLine(b)
}
}
t.addLastCellLine(b)
return b.String()
}
2022-08-25 16:55:19 +02:00
func (t *Table) printRow(b *strings.Builder, rowData [][]string, rowHeight int) {
2022-08-25 16:00:13 +02:00
for lineIndex := 0; lineIndex < rowHeight; lineIndex++ {
2022-08-25 16:55:19 +02:00
b.WriteRune('┃')
2022-08-25 16:00:13 +02:00
for colIndex := 0; colIndex < t.maxcols; colIndex++ {
line := ""
if colIndex < len(rowData) {
cell := rowData[colIndex]
if lineIndex < len(cell) {
line = cell[lineIndex]
}
}
2022-08-25 16:55:19 +02:00
b.WriteString(fmt.Sprint(padStringRight(line, ' ', t.colwidth[colIndex])))
if colIndex < t.maxcols-1 {
b.WriteRune('│')
}
2022-08-25 16:00:13 +02:00
}
2022-08-25 16:55:19 +02:00
b.WriteString("┃\n")
2022-08-25 16:00:13 +02:00
}
}
func (t *Table) addNextCellLine(b *strings.Builder) {
2022-08-25 16:55:19 +02:00
b.WriteRune('┠')
2022-08-25 16:00:13 +02:00
for i, colwidth := range t.colwidth {
b.WriteString(strings.Repeat("─", colwidth))
if i < len(t.colwidth)-1 {
b.WriteRune('┼')
}
}
2022-08-25 16:55:19 +02:00
b.WriteRune('┨')
2022-08-25 16:00:13 +02:00
b.WriteRune('\n')
}
func (t *Table) addLastCellLine(b *strings.Builder) {
2022-08-25 16:55:19 +02:00
b.WriteRune('┗')
2022-08-25 16:00:13 +02:00
for i, colwidth := range t.colwidth {
2022-08-25 16:55:19 +02:00
b.WriteString(strings.Repeat("━", colwidth))
2022-08-25 16:00:13 +02:00
if i < len(t.colwidth)-1 {
2022-08-25 16:55:19 +02:00
b.WriteRune('┷')
2022-08-25 16:00:13 +02:00
}
}
2022-08-25 16:55:19 +02:00
b.WriteString("┛\n")
2022-08-25 16:00:13 +02:00
}