package org
import (
"fmt"
"html"
"path"
"strings"
)
type HTMLWriter struct {
stringBuilder
HighlightCodeBlock func(source, lang string) string
}
var emphasisTags = map[string][]string{
"/": []string{"", ""},
"*": []string{"", ""},
"+": []string{"", ""},
"~": []string{"", "
"},
"=": []string{``, "
"},
"_": []string{``, ""},
"_{}": []string{"", ""},
"^{}": []string{"
%s", html.EscapeString(source)) }, } } func (w *HTMLWriter) emptyClone() *HTMLWriter { wcopy := *w wcopy.stringBuilder = stringBuilder{} return &wcopy } func (w *HTMLWriter) before(d *Document) {} func (w *HTMLWriter) after(d *Document) { w.writeFootnotes(d) } func (w *HTMLWriter) writeNodes(ns ...Node) { for _, n := range ns { switch n := n.(type) { case Keyword, Comment: continue case Headline: w.writeHeadline(n) case Block: w.writeBlock(n) case FootnoteDefinition: w.writeFootnoteDefinition(n) case List: w.writeList(n) case ListItem: w.writeListItem(n) case Table: w.writeTable(n) case TableHeader: w.writeTableHeader(n) case TableRow: w.writeTableRow(n) case TableSeparator: w.writeTableSeparator(n) case Paragraph: w.writeParagraph(n) case HorizontalRule: w.writeHorizontalRule(n) case Line: w.writeLine(n) case Text: w.writeText(n) case Emphasis: w.writeEmphasis(n) case Linebreak: w.writeLinebreak(n) case RegularLink: w.writeRegularLink(n) case FootnoteLink: w.writeFootnoteLink(n) default: if n != nil { panic(fmt.Sprintf("bad node %#v", n)) } } } } func (w *HTMLWriter) writeLines(lines []Node) { for i, line := range lines { w.writeNodes(line) if i != len(lines)-1 && line.(Line).Children != nil { w.WriteString(" ") } } } func (w *HTMLWriter) writeBlock(b Block) { switch b.Name { case "SRC": lines, lang := []string{}, "text" if len(b.Parameters) >= 1 { lang = b.Parameters[0] } for _, n := range b.Children { lines = append(lines, n.(Line).Children[0].(Text).Content) } w.WriteString(fmt.Sprintf(``, lang) + "\n") w.WriteString(w.HighlightCodeBlock(strings.Join(lines, "\n"), lang)) w.WriteString("\n
\n") case "EXAMPLE": w.WriteString(`` + "\n") w.writeNodes(b.Children...) w.WriteString("\n\n") case "QUOTE": w.WriteString("\n") w.writeNodes(b.Children...) w.WriteString("\n\n") case "CENTER": w.WriteString(`` + "\n") w.writeNodes(b.Children...) w.WriteString("\n\n") } } func (w *HTMLWriter) writeFootnoteDefinition(f FootnoteDefinition) { w.WriteString(`` + "\n") w.WriteString(fmt.Sprintf(`%s`, f.Name, f.Name) + "\n") w.writeNodes(f.Children...) w.WriteString("\n") } func (w *HTMLWriter) writeFootnotes(d *Document) { fs := d.Footnotes if len(fs.Definitions) == 0 { return } w.WriteString(`` + "\n") w.WriteString(`\n") } func (w *HTMLWriter) writeHeadline(h Headline) { w.WriteString(fmt.Sprintf("` + fs.Title + `
` + "\n") w.WriteString(`` + "\n") for _, name := range fs.Order { w.writeNodes(fs.Definitions[name]) } w.WriteString("\n", h.Lvl)) w.writeNodes(h.Title...) w.WriteString(fmt.Sprintf(" \n", h.Lvl)) w.writeNodes(h.Children...) } func (w *HTMLWriter) writeText(t Text) { w.WriteString(html.EscapeString(t.Content)) } func (w *HTMLWriter) writeEmphasis(e Emphasis) { tags, ok := emphasisTags[e.Kind] if !ok { panic(fmt.Sprintf("bad emphasis %#v", e)) } w.WriteString(tags[0]) w.writeNodes(e.Content...) w.WriteString(tags[1]) } func (w *HTMLWriter) writeLinebreak(l Linebreak) { w.WriteString("
\n") } func (w *HTMLWriter) writeFootnoteLink(l FootnoteLink) { name := html.EscapeString(l.Name) w.WriteString(fmt.Sprintf(`%s`, name, name)) } func (w *HTMLWriter) writeRegularLink(l RegularLink) { url := html.EscapeString(l.URL) descriptionWriter := w.emptyClone() descriptionWriter.writeNodes(l.Description...) description := descriptionWriter.String() switch l.Protocol { case "file": // TODO url = url[len("file:"):] if strings.Contains(".png.jpg.jpeg.gif", path.Ext(l.URL)) { w.WriteString(fmt.Sprintf(``, url, description, description)) } else { w.WriteString(fmt.Sprintf(`%s`, url, description)) } default: w.WriteString(fmt.Sprintf(`%s`, url, description)) } } func (w *HTMLWriter) writeList(l List) { tags, ok := listTags[l.Kind] if !ok { panic(fmt.Sprintf("bad list kind %#v", l)) } w.WriteString(tags[0] + "\n") w.writeNodes(l.Items...) w.WriteString(tags[1] + "\n") } func (w *HTMLWriter) writeListItem(li ListItem) { w.WriteString("
") w.writeLines(p.Children) w.WriteString("
\n") } func (w *HTMLWriter) writeHorizontalRule(h HorizontalRule) { w.WriteString("