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() }