144 lines
3.2 KiB
Go
144 lines
3.2 KiB
Go
package table
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"xdcc-cli/util"
|
|
)
|
|
|
|
type Row []string
|
|
|
|
type TablePrinter struct {
|
|
Headers []string
|
|
Rows []Row
|
|
MaxRows int
|
|
MaxWidths []int
|
|
}
|
|
|
|
func NewTablePrinter(headers []string) *TablePrinter {
|
|
return &TablePrinter{
|
|
Headers: headers,
|
|
MaxRows: -1,
|
|
}
|
|
}
|
|
|
|
func (printer *TablePrinter) SetMaxWidths(widths []int) {
|
|
printer.MaxWidths = widths
|
|
}
|
|
|
|
func centerString(s string, width int) string {
|
|
padSpace := width - len(s)
|
|
leftPadding := padSpace / 2
|
|
rightPadding := padSpace - leftPadding
|
|
return strings.Repeat(" ", leftPadding) + s + strings.Repeat(" ", rightPadding)
|
|
}
|
|
|
|
func formatStr(s string, maxSize int) string {
|
|
return centerString(util.CutStr(s, maxSize), maxSize)
|
|
}
|
|
|
|
const paddingDefault = 2
|
|
|
|
func (printer *TablePrinter) NumRows() int {
|
|
if printer.Rows == nil {
|
|
return 0
|
|
}
|
|
return len(printer.Rows)
|
|
}
|
|
|
|
func (printer *TablePrinter) NumCols() int {
|
|
return len(printer.Headers)
|
|
}
|
|
|
|
func (printer *TablePrinter) hasRows() bool {
|
|
return printer.Rows != nil && len(printer.Rows) > 0
|
|
}
|
|
|
|
func (printer *TablePrinter) computeColumnWidthds() []int {
|
|
widths := make([]int, printer.NumCols())
|
|
for i := 0; i < printer.NumCols(); i++ {
|
|
widths[i] = len(printer.Headers[i])
|
|
}
|
|
|
|
if printer.hasRows() {
|
|
for col := 0; col < printer.NumCols(); col++ {
|
|
for row := 0; row < len(printer.Rows); row++ {
|
|
if len(printer.Rows[row][col]) > widths[col] {
|
|
widths[col] = len(printer.Rows[row][col])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for i := 0; i < printer.NumCols(); i++ {
|
|
widths[i] += paddingDefault
|
|
|
|
if printer.MaxWidths != nil {
|
|
if printer.MaxWidths[i] > 0 && widths[i] > printer.MaxWidths[i] {
|
|
widths[i] = printer.MaxWidths[i]
|
|
}
|
|
}
|
|
|
|
}
|
|
return widths
|
|
}
|
|
|
|
func (printer *TablePrinter) renderRow(s []string, colWidths []int) string {
|
|
content := "|"
|
|
for i := 0; i < len(printer.Headers)-1; i++ {
|
|
content += formatStr(s[i], colWidths[i]) + "|"
|
|
}
|
|
content += formatStr(s[printer.NumCols()-1], colWidths[printer.NumCols()-1]) + "|"
|
|
return content
|
|
}
|
|
|
|
func (printer *TablePrinter) renderLine(colWidths []int) string {
|
|
content := "+"
|
|
for i := 0; i < len(printer.Headers)-1; i++ {
|
|
content += formatStr(strings.Repeat("-", colWidths[i]), colWidths[i]) + "-"
|
|
}
|
|
content += formatStr(strings.Repeat("-", colWidths[printer.NumCols()-1]), colWidths[printer.NumCols()-1]) + "+"
|
|
return content
|
|
}
|
|
|
|
func (printer *TablePrinter) renderHeader(colWidths []int) {
|
|
fmt.Println(printer.renderLine(colWidths))
|
|
fmt.Println(printer.renderRow(printer.Headers, colWidths))
|
|
fmt.Println(printer.renderLine(colWidths))
|
|
}
|
|
|
|
const initialRows = 100
|
|
|
|
func (printer *TablePrinter) AddRow(r Row) {
|
|
if printer.Rows == nil {
|
|
printer.Rows = make([]Row, 0, initialRows)
|
|
}
|
|
|
|
if printer.MaxRows > 0 && printer.NumRows() == printer.MaxRows {
|
|
return
|
|
}
|
|
printer.Rows = append(printer.Rows, r)
|
|
|
|
}
|
|
|
|
func (printer *TablePrinter) SortByColumn(col int) {
|
|
if col < printer.NumCols() {
|
|
sort.Slice(printer.Rows, func(i, j int) bool {
|
|
return printer.Rows[i][col] < printer.Rows[j][col]
|
|
})
|
|
}
|
|
}
|
|
|
|
func (printer *TablePrinter) Print() {
|
|
colWidths := printer.computeColumnWidthds()
|
|
|
|
printer.renderHeader(colWidths)
|
|
if printer.hasRows() {
|
|
for _, row := range printer.Rows {
|
|
fmt.Println(printer.renderRow(row, colWidths))
|
|
}
|
|
fmt.Println(printer.renderLine(colWidths))
|
|
}
|
|
}
|