1
0

refactor md rendering

This commit is contained in:
Arpad Ryszka 2025-11-02 07:34:41 +01:00
parent a6332946e5
commit ab279fadb9

View File

@ -8,35 +8,24 @@ import (
"strings" "strings"
) )
func mdTextToString(text Txt) (string, error) { func mdTextToString(text Txt) string {
var b bytes.Buffer var b bytes.Buffer
w := newMDWriter(&b, true) renderMDText(&b, text)
renderMDText(w, text) return b.String()
w.flush()
if w.err != nil {
return "", w.err
}
return b.String(), nil
} }
func mdCellTexts(rows []TableRow) ([][]string, error) { func mdCellTexts(rows []TableRow) [][]string {
var texts [][]string var texts [][]string
for _, row := range rows { for _, row := range rows {
var rowTexts []string var rowTexts []string
for _, cell := range row.cells { for _, cell := range row.cells {
txt, err := mdTextToString(cell.text) rowTexts = append(rowTexts, mdTextToString(cell.text))
if err != nil {
return nil, err
}
rowTexts = append(rowTexts, txt)
} }
texts = append(texts, rowTexts) texts = append(texts, rowTexts)
} }
return texts, nil return texts
} }
func mdEnsureHeaderTexts(h []string) []string { func mdEnsureHeaderTexts(h []string) []string {
@ -52,11 +41,11 @@ func mdEnsureHeaderTexts(h []string) []string {
return hh return hh
} }
func renderMDText(w writer, text Txt) { func renderMDText(w io.Writer, text Txt) {
if len(text.cat) > 0 { if len(text.cat) > 0 {
for i, tc := range text.cat { for i, tc := range text.cat {
if i > 0 { if i > 0 {
w.write(" ") write(w, " ")
} }
renderMDText(w, tc) renderMDText(w, tc)
@ -70,73 +59,70 @@ func renderMDText(w writer, text Txt) {
text.link = editString(text.link, singleLine()) text.link = editString(text.link, singleLine())
text.link = editString(text.link, escapeMarkdown()) text.link = editString(text.link, escapeMarkdown())
if text.bold { if text.bold {
w.write("**") write(w, "**")
} }
if text.italic { if text.italic {
w.write("_") write(w, "_")
} }
defer func() { defer func() {
if text.italic { if text.italic {
w.write("_") write(w, "_")
} }
if text.bold { if text.bold {
w.write("**") write(w, "**")
} }
}() }()
if text.link != "" { if text.link != "" {
if text.text != "" { if text.text != "" {
w.write("[") write(w, "[")
w.write(text.text) write(w, text.text)
w.write("](") write(w, "](")
w.write(text.link) write(w, text.link)
w.write(")") write(w, ")")
return return
} }
w.write(text.link) write(w, text.link)
return return
} }
w.write(text.text) write(w, text.text)
} }
func renderMDTitle(w writer, e Entry) { func renderMDTitle(w io.Writer, e Entry) {
hashes := e.titleLevel + 1 hashes := e.titleLevel + 1
if hashes > 6 { if hashes > 6 {
hashes = 6 hashes = 6
} }
w.write(timesn("#", hashes), " ") write(w, timesn("#", hashes), " ")
renderMDText(w, e.text) renderMDText(w, e.text)
} }
func renderMDParagraphIndent(w writer, e Entry) { func renderMDParagraphIndent(w io.Writer, e Entry) {
txt, err := mdTextToString(e.text) var f func() (io.Writer, error)
if err != nil {
w.setErr(err)
}
indentFirst := e.indent + e.indentFirst
if e.wrapWidth > 0 { if e.wrapWidth > 0 {
txt = editString(txt, wrapIndent(indentFirst, e.indent, e.wrapWidth, e.wrapWidth)) indentFirst := e.indent + e.indentFirst
} else { w, f = writeWith(w, wrapIndent(indentFirst, e.indent, e.wrapWidth, e.wrapWidth))
// txt = editString(txt, indent(indentFirst, e.indent))
} }
w.write(txt) renderMDText(w, e.text)
if f != nil {
f()
}
} }
func renderMDParagraph(w writer, e Entry) { func renderMDParagraph(w io.Writer, e Entry) {
e.indent = 0 e.indent = 0
e.indentFirst = 0 e.indentFirst = 0
renderMDParagraphIndent(w, e) renderMDParagraphIndent(w, e)
} }
func renderMDList(w writer, e Entry) { func renderMDList(w io.Writer, e Entry) {
e.indent = 2 e.indent = 2
e.indentFirst = -2 e.indentFirst = -2
if e.wrapWidth > 2 { if e.wrapWidth > 2 {
@ -145,16 +131,16 @@ func renderMDList(w writer, e Entry) {
for i, item := range e.items { for i, item := range e.items {
if i > 0 { if i > 0 {
w.write("\n") write(w, "\n")
} }
w.write("- ") write(w, "- ")
p := itemToParagraph(e, item.text) p := itemToParagraph(e, item.text)
renderMDParagraphIndent(w, p) renderMDParagraphIndent(w, p)
} }
} }
func renderMDNumberedList(w writer, e Entry) { func renderMDNumberedList(w io.Writer, e Entry) {
maxDigits := numDigits(len(e.items)) maxDigits := numDigits(len(e.items))
e.indent = maxDigits + 2 e.indent = maxDigits + 2
e.indentFirst = 0 - maxDigits - 2 e.indentFirst = 0 - maxDigits - 2
@ -164,16 +150,16 @@ func renderMDNumberedList(w writer, e Entry) {
for i, item := range e.items { for i, item := range e.items {
if i > 0 { if i > 0 {
w.write("\n") write(w, "\n")
} }
w.write(padRight(fmt.Sprintf("%d.", i+1), maxDigits+2)) write(w, padRight(fmt.Sprintf("%d.", i+1), maxDigits+2))
p := itemToParagraph(e, item.text) p := itemToParagraph(e, item.text)
renderMDParagraphIndent(w, p) renderMDParagraphIndent(w, p)
} }
} }
func renderMDDefinitions(w writer, e Entry) { func renderMDDefinitions(w io.Writer, e Entry) {
for _, d := range e.definitions { for _, d := range e.definitions {
e.items = append( e.items = append(
e.items, e.items,
@ -184,7 +170,7 @@ func renderMDDefinitions(w writer, e Entry) {
renderMDList(w, e) renderMDList(w, e)
} }
func renderMDNumberedDefinitions(w writer, e Entry) { func renderMDNumberedDefinitions(w io.Writer, e Entry) {
for _, d := range e.definitions { for _, d := range e.definitions {
e.items = append( e.items = append(
e.items, e.items,
@ -195,25 +181,15 @@ func renderMDNumberedDefinitions(w writer, e Entry) {
renderMDNumberedList(w, e) renderMDNumberedList(w, e)
} }
func renderMDTable(w writer, e Entry) { func renderMDTable(w io.Writer, e Entry) {
e.rows = normalizeTable(e.rows) e.rows = normalizeTable(e.rows)
e.rows = ensureHeader(e.rows) e.rows = ensureHeader(e.rows)
if len(e.rows) == 0 || len(e.rows[0].cells) == 0 { if len(e.rows) == 0 || len(e.rows[0].cells) == 0 {
return return
} }
headerTexts, err := mdCellTexts(e.rows[:1]) headerTexts := mdCellTexts(e.rows[:1])
if err != nil { cellTexts := mdCellTexts(e.rows[1:])
w.setErr(err)
return
}
cellTexts, err := mdCellTexts(e.rows[1:])
if err != nil {
w.setErr(err)
return
}
headerTexts[0] = mdEnsureHeaderTexts(headerTexts[0]) headerTexts[0] = mdEnsureHeaderTexts(headerTexts[0])
columns := columnWidths(headerTexts) columns := columnWidths(headerTexts)
cellColumns := columnWidths(cellTexts) cellColumns := columnWidths(cellTexts)
@ -225,66 +201,66 @@ func renderMDTable(w writer, e Entry) {
} }
} }
w.write("|") write(w, "|")
for i, h := range headerTexts[0] { for i, h := range headerTexts[0] {
w.write(" ", padRight(h, columns[i])) write(w, " ", padRight(h, columns[i]))
w.write(" |") write(w, " |")
} }
w.write("\n|") write(w, "\n|")
for _, c := range columns { for _, c := range columns {
w.write(timesn("-", c+1)) write(w, timesn("-", c+1))
w.write("-|") write(w, "-|")
} }
for _, row := range cellTexts { for _, row := range cellTexts {
w.write("\n|") write(w, "\n|")
for i, cell := range row { for i, cell := range row {
w.write(" ", padRight(cell, columns[i])) write(w, " ", padRight(cell, columns[i]))
w.write(" |") write(w, " |")
} }
} }
} }
func renderMDCode(w writer, e Entry) { func renderMDCode(w io.Writer, e Entry) {
w.write("```\n") write(w, "```\n")
w.write(e.text.text) write(w, e.text.text)
w.write("\n```") write(w, "\n```")
} }
func renderMDMultiple(w writer, s SyntaxItem) { func renderMDMultiple(w io.Writer, s SyntaxItem) {
s.topLevel = false s.topLevel = false
s.multiple = false s.multiple = false
renderMDSyntaxItem(w, s) renderMDSyntaxItem(w, s)
w.write("...") write(w, "...")
} }
func renderMDRequired(w writer, s SyntaxItem) { func renderMDRequired(w io.Writer, s SyntaxItem) {
s.delimited = true s.delimited = true
s.topLevel = false s.topLevel = false
s.required = false s.required = false
w.write("<") write(w, "<")
renderMDSyntaxItem(w, s) renderMDSyntaxItem(w, s)
w.write(">") write(w, ">")
} }
func renderMDOptional(w writer, s SyntaxItem) { func renderMDOptional(w io.Writer, s SyntaxItem) {
s.delimited = true s.delimited = true
s.topLevel = false s.topLevel = false
s.optional = false s.optional = false
w.write("[") write(w, "[")
renderMDSyntaxItem(w, s) renderMDSyntaxItem(w, s)
w.write("]") write(w, "]")
} }
func renderMDSequence(w writer, s SyntaxItem) { func renderMDSequence(w io.Writer, s SyntaxItem) {
if !s.delimited && !s.topLevel { if !s.delimited && !s.topLevel {
w.write("(") write(w, "(")
} }
for i, item := range s.sequence { for i, item := range s.sequence {
if i > 0 { if i > 0 {
w.write(" ") write(w, " ")
} }
item.delimited = false item.delimited = false
@ -292,13 +268,13 @@ func renderMDSequence(w writer, s SyntaxItem) {
} }
if !s.delimited && !s.topLevel { if !s.delimited && !s.topLevel {
w.write(")") write(w, ")")
} }
} }
func renderMDChoice(w writer, s SyntaxItem) { func renderMDChoice(w io.Writer, s SyntaxItem) {
if !s.delimited && !s.topLevel { if !s.delimited && !s.topLevel {
w.write("(") write(w, "(")
} }
for i, item := range s.choice { for i, item := range s.choice {
@ -308,7 +284,7 @@ func renderMDChoice(w writer, s SyntaxItem) {
separator = "\n" separator = "\n"
} }
w.write(separator) write(w, separator)
} }
item.delimited = false item.delimited = false
@ -316,15 +292,17 @@ func renderMDChoice(w writer, s SyntaxItem) {
} }
if !s.delimited && !s.topLevel { if !s.delimited && !s.topLevel {
w.write(")") write(w, ")")
} }
} }
func renderMDSymbol(w writer, s SyntaxItem) { func renderMDSymbol(w io.Writer, s SyntaxItem) {
w.write(editString(s.symbol, escapeMarkdown())) w, f := writeWith(w, escapeMarkdown())
write(w, s.symbol)
f()
} }
func renderMDSyntaxItem(w writer, s SyntaxItem) { func renderMDSyntaxItem(w io.Writer, s SyntaxItem) {
switch { switch {
// foo... // foo...
@ -353,23 +331,19 @@ func renderMDSyntaxItem(w writer, s SyntaxItem) {
} }
} }
func renderMDSyntax(w writer, e Entry) { func renderMDSyntax(w io.Writer, e Entry) {
s := e.syntax s := e.syntax
s.topLevel = true s.topLevel = true
w.write("```\n") write(w, "```\n")
renderMDSyntaxItem(w, s) renderMDSyntaxItem(w, s)
w.write("\n```") write(w, "\n```")
} }
func renderMarkdown(out io.Writer, d Document) error { func renderMarkdown(out io.Writer, d Document) error {
w := newMDWriter(out, false) w, f := writeWith(out, mdNBSP(), errorHandler)
for i, e := range d.entries { for i, e := range d.entries {
if err := w.error(); err != nil {
return err
}
if i > 0 { if i > 0 {
w.write("\n\n") write(w, "\n\n")
} }
switch e.typ { switch e.typ {
@ -397,9 +371,9 @@ func renderMarkdown(out io.Writer, d Document) error {
} }
if len(d.entries) > 0 { if len(d.entries) > 0 {
w.write("\n") write(w, "\n")
} }
w.flush() _, err := f()
return w.err return err
} }