Skip to content

Commit

Permalink
refactoring and nice unicode tables
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonWaldherr committed Jul 18, 2024
1 parent 95179c9 commit aae6037
Showing 1 changed file with 77 additions and 43 deletions.
120 changes: 77 additions & 43 deletions table/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,31 @@ import (
// TableOption defines the configuration for table output
type TableOption struct {
Rotate bool
Align []string // alignment options for each column: "left", "center", "right"
Align []string // can be "left", "right", or "center"
Format string // can be "ascii", "unicode", "markdown", or "html"
}

// RenderASCII renders the struct slice as an ASCII table
func RenderASCII(data interface{}, opt TableOption) (string, error) {
var buffer bytes.Buffer
return Render(data, TableOption{Rotate: opt.Rotate, Align: opt.Align, Format: "ascii"})
}

// RenderASCII renders the struct slice as an ASCII table
func RenderUnicode(data interface{}, opt TableOption) (string, error) {
return Render(data, TableOption{Rotate: opt.Rotate, Align: opt.Align, Format: "unicode"})
}

// RenderMarkdown renders the struct slice as a Markdown table
func RenderMarkdown(data interface{}, opt TableOption) (string, error) {
return Render(data, TableOption{Rotate: opt.Rotate, Align: opt.Align, Format: "markdown"})
}

// RenderHTML renders the struct slice as an HTML table
func RenderHTML(data interface{}, opt TableOption) (string, error) {
return Render(data, TableOption{Rotate: opt.Rotate, Align: opt.Align, Format: "html"})
}

func Render(data interface{}, opt TableOption) (string, error) {
headers, rows, err := parseStruct(data)
if err != nil {
return "", err
Expand All @@ -31,57 +50,82 @@ func RenderASCII(data interface{}, opt TableOption) (string, error) {
headers, rows = rotate(headers, rows)
}

switch opt.Format {
case "ascii":
return renderASCII(headers, rows, opt, basicBorders)
case "unicode":
return renderASCII(headers, rows, opt, niceBorders)
case "markdown":
return renderMarkdown(headers, rows, opt)
case "html":
return renderHTML(headers, rows)
default:
return "", fmt.Errorf("unsupported format: %s", opt.Format)
}
}

type borders struct {
topLeft, topMid, topRight, midLeft, midMid, midRight, botLeft, botMid, botRight, hor, ver string
}

var basicBorders = borders{"+", "+", "+", "+", "+", "+", "+", "+", "+", "-", "|"}
var niceBorders = borders{"┏", "┳", "┓", "┡", "╇", "┩", "└", "┴", "┘", "━", "┃"}

func renderASCII(headers []string, rows [][]string, opt TableOption, brd borders) (string, error) {
var buffer bytes.Buffer
colWidths := calculateColumnWidths(headers, rows)

// Create header line
buffer.WriteString("+")
for _, width := range colWidths {
buffer.WriteString(strings.Repeat("-", width+2) + "+")
buffer.WriteString(brd.topLeft)
for i, width := range colWidths {
if i > 0 {
buffer.WriteString(brd.topMid)
}
buffer.WriteString(strings.Repeat(brd.hor, width+2))
}
buffer.WriteString("\n|")
buffer.WriteString(brd.topRight + "\n" + brd.ver)
for i, header := range headers {
if i > 0 {
buffer.WriteString(brd.ver)
}
alignment := getColumnAlignment(i, opt.Align, header)
buffer.WriteString(" " + alignText(header, colWidths[i], alignment) + " |")
buffer.WriteString(" " + alignText(header, colWidths[i], alignment) + " ")
}
buffer.WriteString("\n+")
for _, width := range colWidths {
buffer.WriteString(strings.Repeat("-", width+2) + "+")
buffer.WriteString(brd.ver + "\n" + brd.midLeft)
for i, width := range colWidths {
if i > 0 {
buffer.WriteString(brd.midMid)
}
buffer.WriteString(strings.Repeat(brd.hor, width+2))
}
buffer.WriteString("\n")
buffer.WriteString(brd.midRight + "\n")

// Create rows
for _, row := range rows {
buffer.WriteString("|")
buffer.WriteString(brd.ver)
for i, col := range row {
if i > 0 {
buffer.WriteString(brd.ver)
}
alignment := getColumnAlignment(i, opt.Align, col)
buffer.WriteString(" " + alignText(col, colWidths[i], alignment) + " |")
buffer.WriteString(" " + alignText(col, colWidths[i], alignment) + " ")
}
buffer.WriteString("\n")
buffer.WriteString(brd.ver + "\n")
}
buffer.WriteString("+")
for _, width := range colWidths {
buffer.WriteString(strings.Repeat("-", width+2) + "+")
buffer.WriteString(brd.botLeft)
for i, width := range colWidths {
if i > 0 {
buffer.WriteString(brd.botMid)
}
buffer.WriteString(strings.Repeat(brd.hor, width+2))
}
buffer.WriteString("\n")
buffer.WriteString(brd.botRight + "\n")

return buffer.String(), nil
}

// RenderMarkdown renders the struct slice as a Markdown table
func RenderMarkdown(data interface{}, opt TableOption) (string, error) {
func renderMarkdown(headers []string, rows [][]string, opt TableOption) (string, error) {
var buffer bytes.Buffer
headers, rows, err := parseStruct(data)
if err != nil {
return "", err
}

if opt.Rotate {
headers, rows = rotate(headers, rows)
}

colWidths := calculateColumnWidths(headers, rows)

// Create header line
buffer.WriteString("|")
for i, header := range headers {
buffer.WriteString(fmt.Sprintf(" %-*s |", colWidths[i], header))
Expand All @@ -92,7 +136,6 @@ func RenderMarkdown(data interface{}, opt TableOption) (string, error) {
}
buffer.WriteString("\n")

// Create rows
for _, row := range rows {
buffer.WriteString("|")
for i, col := range row {
Expand All @@ -105,17 +148,8 @@ func RenderMarkdown(data interface{}, opt TableOption) (string, error) {
return buffer.String(), nil
}

// RenderHTML renders the struct slice as an HTML table
func RenderHTML(data interface{}, opt TableOption) (string, error) {
func renderHTML(headers []string, rows [][]string) (string, error) {
var buffer bytes.Buffer
headers, rows, err := parseStruct(data)
if err != nil {
return "", err
}

if opt.Rotate {
headers, rows = rotate(headers, rows)
}

buffer.WriteString("<table>\n<thead>\n<tr>")
for _, header := range headers {
Expand Down

0 comments on commit aae6037

Please sign in to comment.