summaryrefslogtreecommitdiff
path: root/internal/table
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-02-05 00:30:29 +0200
committerPaul Buetow <paul@buetow.org>2025-02-05 00:30:29 +0200
commit07d9f1840494924dd6ca713493dd3d630e9ad721 (patch)
tree1abb8c8788fc3224e405428d6ff3f27d1fc1a295 /internal/table
parent35204effbd09bc14e9e2e93b2f99f0f5a0009b23 (diff)
initial generic table
Diffstat (limited to 'internal/table')
-rw-r--r--internal/table/render.go57
-rw-r--r--internal/table/table.go84
2 files changed, 141 insertions, 0 deletions
diff --git a/internal/table/render.go b/internal/table/render.go
new file mode 100644
index 0000000..edac866
--- /dev/null
+++ b/internal/table/render.go
@@ -0,0 +1,57 @@
+package table
+
+import (
+ "fmt"
+ "strings"
+)
+
+type render struct {
+ tab *Table
+ lineLen int
+ separator string
+}
+
+func newRender(tab *Table) render {
+ r := render{
+ tab: tab,
+ lineLen: len(tab.lengths) + 1,
+ }
+
+ var separator strings.Builder
+
+ for _, len := range tab.lengths {
+ separator.WriteString("+")
+ separator.WriteString(strings.Repeat("-", len+2))
+ r.lineLen += len + 3
+ }
+
+ separator.WriteString("+\n")
+ r.separator = separator.String()
+
+ return r
+}
+
+func (r render) String() string {
+ var sb strings.Builder
+
+ sb.WriteString(r.separator)
+ r.writeRow(&sb, r.tab.headers)
+
+ sb.WriteString(r.separator)
+ for _, row := range r.tab.rows {
+ r.writeRow(&sb, row)
+ }
+ sb.WriteString(r.separator)
+
+ return sb.String()
+}
+
+func (r render) writeRow(sb *strings.Builder, row []string) {
+ for i, col := range row {
+ sb.WriteString(fmt.Sprintf("| %s ", col))
+ for j := len(col); j < r.tab.lengths[i]; j++ {
+ sb.WriteString(" ")
+ }
+ }
+ sb.WriteString("|\n")
+}
diff --git a/internal/table/table.go b/internal/table/table.go
new file mode 100644
index 0000000..040f50d
--- /dev/null
+++ b/internal/table/table.go
@@ -0,0 +1,84 @@
+package table
+
+import (
+ "fmt"
+ "strconv"
+)
+
+type row []string
+
+type Table struct {
+ headers []string
+ rows []row
+ lengths []int // Max length of each col
+ err error
+}
+
+func New(args ...any) *Table {
+
+ t := Table{
+ headers: make([]string, 0, len(args)),
+ 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) Add(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) Render() error {
+ 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")
+// }