Files
2026-03-05 01:13:19 -06:00

143 lines
2.8 KiB
Go

package render
import (
"fmt"
"strings"
)
// Builder accumulates markdown output.
type Builder struct {
sb strings.Builder
}
// New creates a new markdown builder.
func New() *Builder {
return &Builder{}
}
// H1 writes a level-1 heading.
func (b *Builder) H1(text string) {
fmt.Fprintf(&b.sb, "# %s\n\n", text)
}
// H2 writes a level-2 heading.
func (b *Builder) H2(text string) {
fmt.Fprintf(&b.sb, "## %s\n\n", text)
}
// H3 writes a level-3 heading.
func (b *Builder) H3(text string) {
fmt.Fprintf(&b.sb, "### %s\n\n", text)
}
// P writes a paragraph.
func (b *Builder) P(text string) {
fmt.Fprintf(&b.sb, "%s\n\n", text)
}
// Bold writes bold text inline (no newline).
func (b *Builder) Bold(text string) {
fmt.Fprintf(&b.sb, "**%s**", text)
}
// KV writes a key: value line.
func (b *Builder) KV(key, value string) {
if value == "" {
return
}
fmt.Fprintf(&b.sb, "- **%s:** %s\n", key, value)
}
// Bullet writes a bullet point.
func (b *Builder) Bullet(text string) {
fmt.Fprintf(&b.sb, "- %s\n", text)
}
// NumberedItem writes a numbered list item.
func (b *Builder) NumberedItem(n int, text string) {
fmt.Fprintf(&b.sb, "%d. %s\n", n, text)
}
// Table writes a markdown table.
func (b *Builder) Table(headers []string, rows [][]string) {
if len(headers) == 0 {
return
}
// Header row
fmt.Fprintf(&b.sb, "| %s |\n", strings.Join(headers, " | "))
// Separator
seps := make([]string, len(headers))
for i := range seps {
seps[i] = "---"
}
fmt.Fprintf(&b.sb, "| %s |\n", strings.Join(seps, " | "))
// Data rows
for _, row := range rows {
// Pad row to match header length
for len(row) < len(headers) {
row = append(row, "")
}
fmt.Fprintf(&b.sb, "| %s |\n", strings.Join(row[:len(headers)], " | "))
}
b.sb.WriteString("\n")
}
// Line writes a raw line.
func (b *Builder) Line(text string) {
fmt.Fprintf(&b.sb, "%s\n", text)
}
// Newline writes an empty line.
func (b *Builder) Newline() {
b.sb.WriteString("\n")
}
// HR writes a horizontal rule.
func (b *Builder) HR() {
b.sb.WriteString("---\n\n")
}
// String returns the accumulated markdown.
func (b *Builder) String() string {
return b.sb.String()
}
// FormatGP formats a coin amount with commas (e.g., 1,234,567 gp).
func FormatGP(amount int) string {
if amount < 0 {
return fmt.Sprintf("-%s gp", addCommas(-amount))
}
return fmt.Sprintf("%s gp", addCommas(amount))
}
// FormatNumber formats a number with commas.
func FormatNumber(n int) string {
return addCommas(n)
}
func addCommas(n int) string {
s := fmt.Sprintf("%d", n)
if len(s) <= 3 {
return s
}
var result strings.Builder
remainder := len(s) % 3
if remainder > 0 {
result.WriteString(s[:remainder])
if len(s) > remainder {
result.WriteString(",")
}
}
for i := remainder; i < len(s); i += 3 {
if i > remainder {
result.WriteString(",")
}
result.WriteString(s[i : i+3])
}
return result.String()
}