Skip to content

Instantly share code, notes, and snippets.

@matteopic
Created June 5, 2024 04:54
Show Gist options
  • Save matteopic/8948f3e87523baa46d1831f03a12a4b2 to your computer and use it in GitHub Desktop.
Save matteopic/8948f3e87523baa46d1831f03a12a4b2 to your computer and use it in GitHub Desktop.
Provides a way to construct a markdown table by adding rows and then outputting the table in markdown format with properly aligned columns.
package export
import (
"bytes"
"io"
"strings"
"unicode/utf8"
)
type MarkdownTable struct {
widths []int
rows [][]string
}
func (mkt *MarkdownTable) AddRow(data ...string) {
if len(data) > len(mkt.widths) {
newWidths := make([]int, len(data))
copy(newWidths, mkt.widths)
mkt.widths = newWidths
}
for cell_index, cell := range data {
max_width := mkt.widths[cell_index]
width := utf8.RuneCountInString(cell)
if width > max_width {
mkt.widths[cell_index] = width
}
}
newRows := append(mkt.rows, data)
mkt.rows = newRows
}
func (mkt MarkdownTable) WriteTo(w io.Writer) (int64, error) {
sep := []byte("|")
padding := []byte(" ")
eol := []byte("\n")
buffer := new(bytes.Buffer)
var written int64
for row_index, row := range mkt.rows {
buffer.Reset()
for cell_index, cell := range row {
if cell_index == 0 {
buffer.Write(sep)
buffer.Write(padding)
} else {
buffer.Write(padding)
buffer.Write(sep)
buffer.Write(padding)
}
txtLenght := utf8.RuneCountInString(cell)
cellLength := mkt.widths[cell_index]
buffer.WriteString(cell)
fillLength := cellLength - txtLenght
fill := strings.Repeat(" ", fillLength)
buffer.WriteString(fill)
}
buffer.Write(padding)
buffer.Write(sep)
buffer.Write(eol)
if row_index == 0 {
mkt.writeHeaderSeparator(buffer)
}
count, err := buffer.WriteTo(w)
written += count
if err != nil {
return written, err
}
}
return written, nil
}
func (mkt MarkdownTable) writeHeaderSeparator(w io.Writer) {
sep := []byte("|")
eol := []byte("\n")
for _, width := range mkt.widths {
w.Write(sep)
fill := strings.Repeat("-", width+2)
w.Write([]byte(fill))
}
w.Write(sep)
w.Write(eol)
}
func NewMarkdownTable() *MarkdownTable {
widths := make([]int, 0)
rows := make([][]string, 0)
mkt := MarkdownTable{rows: rows, widths: widths}
return &mkt
}
package export
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestBasic(t *testing.T) {
mkt := NewMarkdownTable()
mkt.AddRow("Lorem", "ipsum", "dolor", "sit", "amet")
mkt.AddRow("consectetur", "adipiscing", "elit", "", "")
bb := new(bytes.Buffer)
mkt.WriteTo(bb)
txt := bb.String()
expected := "" +
"| Lorem | ipsum | dolor | sit | amet |\n" +
"|-------------|------------|-------|-----|------|\n" +
"| consectetur | adipiscing | elit | | |\n"
assert.Equal(t, expected, txt)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment