diff options
| author | Paul Buetow <paul@buetow.org> | 2025-02-05 00:30:29 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-02-05 00:30:29 +0200 |
| commit | 07d9f1840494924dd6ca713493dd3d630e9ad721 (patch) | |
| tree | 1abb8c8788fc3224e405428d6ff3f27d1fc1a295 /internal/table | |
| parent | 35204effbd09bc14e9e2e93b2f99f0f5a0009b23 (diff) | |
initial generic table
Diffstat (limited to 'internal/table')
| -rw-r--r-- | internal/table/render.go | 57 | ||||
| -rw-r--r-- | internal/table/table.go | 84 |
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") +// } |
