2024-03-31 19:01:47 +00:00
|
|
|
package markdown
|
|
|
|
|
2024-03-31 21:08:01 +00:00
|
|
|
import (
|
|
|
|
"html"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
headerStart = []string{"<h1>", "<h2>", "<h3>", "<h4>", "<h5>", "<h6>"}
|
|
|
|
headerEnd = []string{"</h1>", "</h2>", "</h3>", "</h4>", "</h5>", "</h6>"}
|
|
|
|
)
|
|
|
|
|
2024-03-31 19:01:47 +00:00
|
|
|
// Render creates HTML from the supplied markdown text.
|
|
|
|
func Render(markdown string) string {
|
2024-03-31 21:08:01 +00:00
|
|
|
var (
|
|
|
|
out = strings.Builder{}
|
|
|
|
paragraph = strings.Builder{}
|
|
|
|
i = 0
|
|
|
|
lineStart = 0
|
|
|
|
)
|
|
|
|
|
|
|
|
flush := func() {
|
|
|
|
if paragraph.Len() == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
out.WriteString("<p>")
|
|
|
|
out.WriteString(html.EscapeString(paragraph.String()))
|
|
|
|
out.WriteString("</p>")
|
|
|
|
paragraph.Reset()
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
if i > len(markdown) {
|
|
|
|
flush()
|
|
|
|
return out.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
if i != len(markdown) && markdown[i] != '\n' {
|
|
|
|
i++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
line := markdown[lineStart:i]
|
|
|
|
lineStart = i + 1
|
|
|
|
i++
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case strings.HasPrefix(line, "#"):
|
|
|
|
flush()
|
|
|
|
space := strings.IndexByte(line, ' ')
|
|
|
|
|
|
|
|
if space > 0 && space <= 6 {
|
|
|
|
out.WriteString(headerStart[space-1])
|
|
|
|
out.WriteString(html.EscapeString(line[space+1:]))
|
|
|
|
out.WriteString(headerEnd[space-1])
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
if len(line) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if paragraph.Len() > 0 {
|
|
|
|
paragraph.WriteByte(' ')
|
|
|
|
}
|
|
|
|
|
|
|
|
paragraph.WriteString(line)
|
|
|
|
}
|
|
|
|
}
|
2024-03-31 19:01:47 +00:00
|
|
|
}
|