summaryrefslogtreecommitdiff
path: root/internal/table/table.go
blob: 5147b9c4b4ab574c2aff92ecd03c910968322092 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package table

import (
	"fmt"
	"strconv"

	"github.com/fatih/color"
)

type row []string

type Table struct {
	headers []string
	rows    []row
	lengths []int                                   // Max length of each col
	sprintf func(format string, args ...any) string // For colored output
	err     error
}

func New() *Table {
	return &Table{sprintf: fmt.Sprintf}
}

func (t *Table) WithColor(col *color.Color) *Table {
	t.sprintf = col.Sprintf
	return t
}

func (t *Table) Header(args ...any) *Table {
	t.headers = make([]string, 0, len(args))
	t.lengths = make([]int, 0, len(args))

	for _, arg := range args {
		strVal := val(arg)
		t.headers = append(t.headers, strVal)
		t.lengths = append(t.lengths, len(strVal))
	}

	return t
}

func (t *Table) Row(args ...any) *Table {
	if len(args) != len(t.headers) {
		t.err = fmt.Errorf("Table row (%v) not same length as table headers (%v)", args, t.headers)
	}
	if t.err != nil {
		return t
	}

	row := make(row, 0, len(args))
	for i, arg := range args {
		strVal := val(arg)
		row = append(row, strVal)
		if t.lengths[i] < len(row[i]) {
			t.lengths[i] = len(row[i])
		}
	}
	t.rows = append(t.rows, row)

	return t
}

func (t *Table) MustRender() {
	if err := t.Render(); err != nil {
		panic(err)
	}
}

func (t *Table) Render() error {
	if len(t.headers) == 0 {
		return fmt.Errorf("no headers")
	}
	if len(t.rows) == 0 {
		return fmt.Errorf("no rows")
	}
	if t.err != nil {
		return t.err
	}
	fmt.Print(newRender(t).String())
	return nil
}

func val(val any) string {
	switch v := val.(type) {
	case int:
		return strconv.Itoa(v)
	case float64:
		return fmt.Sprintf("%0.2f", v)
	case string:
		return v
	default:
		return fmt.Sprintf("%v", v)
	}
}

// func dataRow(sb *strings.Builder, descr1 string, val1 any, descr2 string, val2 any) {
// 	const format = "| %-21s | %-11s | %-21s | %-11s |"
// 	sb.WriteString(colour.SInfo2f(format, descr1, val(val1), descr2, val(val2)))
// 	sb.WriteString("\n")
// }

// func (t *Table) separator() {
// 	t.sb.WriteString(t.sep)
// 	t.sb.WriteString("\n")
// }