summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gomarkdown/markdown/html/renderer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gomarkdown/markdown/html/renderer.go')
-rw-r--r--vendor/github.com/gomarkdown/markdown/html/renderer.go441
1 files changed, 276 insertions, 165 deletions
diff --git a/vendor/github.com/gomarkdown/markdown/html/renderer.go b/vendor/github.com/gomarkdown/markdown/html/renderer.go
index 01e0deec..6c56ac12 100644
--- a/vendor/github.com/gomarkdown/markdown/html/renderer.go
+++ b/vendor/github.com/gomarkdown/markdown/html/renderer.go
@@ -3,6 +3,7 @@ package html
import (
"bytes"
"fmt"
+ "html"
"io"
"regexp"
"sort"
@@ -10,6 +11,7 @@ import (
"strings"
"github.com/gomarkdown/markdown/ast"
+ "github.com/gomarkdown/markdown/parser"
)
// Flags control optional behavior of HTML renderer.
@@ -125,13 +127,60 @@ type Renderer struct {
headingIDs map[string]int
lastOutputLen int
- disableTags int
+
+ // if > 0, will strip html tags in Out and Outs
+ DisableTags int
sr *SPRenderer
documentMatter ast.DocumentMatters // keep track of front/main/back matter.
}
+// Escaper defines how to escape HTML special characters
+var Escaper = [256][]byte{
+ '&': []byte("&"),
+ '<': []byte("&lt;"),
+ '>': []byte("&gt;"),
+ '"': []byte("&quot;"),
+}
+
+// EscapeHTML writes html-escaped d to w. It escapes &, <, > and " characters.
+func EscapeHTML(w io.Writer, d []byte) {
+ var start, end int
+ n := len(d)
+ for end < n {
+ escSeq := Escaper[d[end]]
+ if escSeq != nil {
+ w.Write(d[start:end])
+ w.Write(escSeq)
+ start = end + 1
+ }
+ end++
+ }
+ if start < n && end <= n {
+ w.Write(d[start:end])
+ }
+}
+
+func escLink(w io.Writer, text []byte) {
+ unesc := html.UnescapeString(string(text))
+ EscapeHTML(w, []byte(unesc))
+}
+
+// Escape writes the text to w, but skips the escape character.
+func Escape(w io.Writer, text []byte) {
+ esc := false
+ for i := 0; i < len(text); i++ {
+ if text[i] == '\\' {
+ esc = !esc
+ }
+ if esc && text[i] == '\\' {
+ continue
+ }
+ w.Write([]byte{text[i]})
+ }
+}
+
// NewRenderer creates and configures an Renderer object, which
// satisfies the Renderer interface.
func NewRenderer(opts RendererOptions) *Renderer {
@@ -384,25 +433,28 @@ func skipParagraphTags(para *ast.Paragraph) bool {
return tightOrTerm
}
-func (r *Renderer) out(w io.Writer, d []byte) {
+// Out is a helper to write data to writer
+func (r *Renderer) Out(w io.Writer, d []byte) {
r.lastOutputLen = len(d)
- if r.disableTags > 0 {
+ if r.DisableTags > 0 {
d = htmlTagRe.ReplaceAll(d, []byte{})
}
w.Write(d)
}
-func (r *Renderer) outs(w io.Writer, s string) {
+// Outs is a helper to write data to writer
+func (r *Renderer) Outs(w io.Writer, s string) {
r.lastOutputLen = len(s)
- if r.disableTags > 0 {
+ if r.DisableTags > 0 {
s = htmlTagRe.ReplaceAllString(s, "")
}
io.WriteString(w, s)
}
-func (r *Renderer) cr(w io.Writer) {
+// CR writes a new line
+func (r *Renderer) CR(w io.Writer) {
if r.lastOutputLen > 0 {
- r.outs(w, "\n")
+ r.Outs(w, "\n")
}
}
@@ -426,11 +478,12 @@ func headingCloseTagFromLevel(level int) string {
}
func (r *Renderer) outHRTag(w io.Writer, attrs []string) {
- hr := tagWithAttributes("<hr", attrs)
- r.outOneOf(w, r.opts.Flags&UseXHTML == 0, hr, "<hr />")
+ hr := TagWithAttributes("<hr", attrs)
+ r.OutOneOf(w, r.opts.Flags&UseXHTML == 0, hr, "<hr />")
}
-func (r *Renderer) text(w io.Writer, text *ast.Text) {
+// Text writes ast.Text node
+func (r *Renderer) Text(w io.Writer, text *ast.Text) {
if r.opts.Flags&Smartypants != 0 {
var tmp bytes.Buffer
EscapeHTML(&tmp, text.Literal)
@@ -445,41 +498,46 @@ func (r *Renderer) text(w io.Writer, text *ast.Text) {
}
}
-func (r *Renderer) hardBreak(w io.Writer, node *ast.Hardbreak) {
- r.outOneOf(w, r.opts.Flags&UseXHTML == 0, "<br>", "<br />")
- r.cr(w)
+// HardBreak writes ast.Hardbreak node
+func (r *Renderer) HardBreak(w io.Writer, node *ast.Hardbreak) {
+ r.OutOneOf(w, r.opts.Flags&UseXHTML == 0, "<br>", "<br />")
+ r.CR(w)
}
-func (r *Renderer) nonBlockingSpace(w io.Writer, node *ast.NonBlockingSpace) {
- r.outs(w, "&nbsp;")
+// NonBlockingSpace writes ast.NonBlockingSpace node
+func (r *Renderer) NonBlockingSpace(w io.Writer, node *ast.NonBlockingSpace) {
+ r.Outs(w, "&nbsp;")
}
-func (r *Renderer) outOneOf(w io.Writer, outFirst bool, first string, second string) {
+// OutOneOf writes first or second depending on outFirst
+func (r *Renderer) OutOneOf(w io.Writer, outFirst bool, first string, second string) {
if outFirst {
- r.outs(w, first)
+ r.Outs(w, first)
} else {
- r.outs(w, second)
+ r.Outs(w, second)
}
}
-func (r *Renderer) outOneOfCr(w io.Writer, outFirst bool, first string, second string) {
+// OutOneOfCr writes CR + first or second + CR depending on outFirst
+func (r *Renderer) OutOneOfCr(w io.Writer, outFirst bool, first string, second string) {
if outFirst {
- r.cr(w)
- r.outs(w, first)
+ r.CR(w)
+ r.Outs(w, first)
} else {
- r.outs(w, second)
- r.cr(w)
+ r.Outs(w, second)
+ r.CR(w)
}
}
-func (r *Renderer) htmlSpan(w io.Writer, span *ast.HTMLSpan) {
+// HTMLSpan writes ast.HTMLSpan node
+func (r *Renderer) HTMLSpan(w io.Writer, span *ast.HTMLSpan) {
if r.opts.Flags&SkipHTML == 0 {
- r.out(w, span.Literal)
+ r.Out(w, span.Literal)
}
}
func (r *Renderer) linkEnter(w io.Writer, link *ast.Link) {
- var attrs []string
+ attrs := link.AdditionalAttributes
dest := link.Destination
dest = r.addAbsPrefix(dest)
var hrefBuf bytes.Buffer
@@ -488,7 +546,7 @@ func (r *Renderer) linkEnter(w io.Writer, link *ast.Link) {
hrefBuf.WriteByte('"')
attrs = append(attrs, hrefBuf.String())
if link.NoteID != 0 {
- r.outs(w, footnoteRef(r.opts.FootnoteAnchorPrefix, link))
+ r.Outs(w, footnoteRef(r.opts.FootnoteAnchorPrefix, link))
return
}
@@ -505,14 +563,15 @@ func (r *Renderer) linkEnter(w io.Writer, link *ast.Link) {
func (r *Renderer) linkExit(w io.Writer, link *ast.Link) {
if link.NoteID == 0 {
- r.outs(w, "</a>")
+ r.Outs(w, "</a>")
}
}
-func (r *Renderer) link(w io.Writer, link *ast.Link, entering bool) {
+// Link writes ast.Link node
+func (r *Renderer) Link(w io.Writer, link *ast.Link, entering bool) {
// mark it but don't link it if it is not a safe link: no smartypants
if needSkipLink(r.opts.Flags, link.Destination) {
- r.outOneOf(w, entering, "<tt>", "</tt>")
+ r.OutOneOf(w, entering, "<tt>", "</tt>")
return
}
@@ -526,26 +585,35 @@ func (r *Renderer) link(w io.Writer, link *ast.Link, entering bool) {
func (r *Renderer) imageEnter(w io.Writer, image *ast.Image) {
dest := image.Destination
dest = r.addAbsPrefix(dest)
- if r.disableTags == 0 {
+ if r.DisableTags == 0 {
//if options.safe && potentiallyUnsafe(dest) {
//out(w, `<img src="" alt="`)
//} else {
- r.outs(w, `<img src="`)
+ r.Outs(w, `<img src="`)
escLink(w, dest)
- r.outs(w, `" alt="`)
+ r.Outs(w, `" alt="`)
//}
}
- r.disableTags++
+ r.DisableTags++
}
func (r *Renderer) imageExit(w io.Writer, image *ast.Image) {
- r.disableTags--
- if r.disableTags == 0 {
+ r.DisableTags--
+ if r.DisableTags == 0 {
if image.Title != nil {
- r.outs(w, `" title="`)
+ r.Outs(w, `" title="`)
EscapeHTML(w, image.Title)
}
- r.outs(w, `" />`)
+ r.Outs(w, `" />`)
+ }
+}
+
+// Image writes ast.Image node
+func (r *Renderer) Image(w io.Writer, node *ast.Image, entering bool) {
+ if entering {
+ r.imageEnter(w, node)
+ } else {
+ r.imageExit(w, node)
}
}
@@ -556,33 +624,34 @@ func (r *Renderer) paragraphEnter(w io.Writer, para *ast.Paragraph) {
if prev != nil {
switch prev.(type) {
case *ast.HTMLBlock, *ast.List, *ast.Paragraph, *ast.Heading, *ast.CaptionFigure, *ast.CodeBlock, *ast.BlockQuote, *ast.Aside, *ast.HorizontalRule:
- r.cr(w)
+ r.CR(w)
}
}
if prev == nil {
_, isParentBlockQuote := para.Parent.(*ast.BlockQuote)
if isParentBlockQuote {
- r.cr(w)
+ r.CR(w)
}
_, isParentAside := para.Parent.(*ast.Aside)
if isParentAside {
- r.cr(w)
+ r.CR(w)
}
}
- tag := tagWithAttributes("<p", BlockAttrs(para))
- r.outs(w, tag)
+ tag := TagWithAttributes("<p", BlockAttrs(para))
+ r.Outs(w, tag)
}
func (r *Renderer) paragraphExit(w io.Writer, para *ast.Paragraph) {
- r.outs(w, "</p>")
+ r.Outs(w, "</p>")
if !(isListItem(para.Parent) && ast.GetNextNode(para) == nil) {
- r.cr(w)
+ r.CR(w)
}
}
-func (r *Renderer) paragraph(w io.Writer, para *ast.Paragraph, entering bool) {
+// Paragraph writes ast.Paragraph node
+func (r *Renderer) Paragraph(w io.Writer, para *ast.Paragraph, entering bool) {
if skipParagraphTags(para) {
return
}
@@ -592,27 +661,22 @@ func (r *Renderer) paragraph(w io.Writer, para *ast.Paragraph, entering bool) {
r.paragraphExit(w, para)
}
}
-func (r *Renderer) image(w io.Writer, node *ast.Image, entering bool) {
- if entering {
- r.imageEnter(w, node)
- } else {
- r.imageExit(w, node)
- }
-}
-func (r *Renderer) code(w io.Writer, node *ast.Code) {
- r.outs(w, "<code>")
+// Code writes ast.Code node
+func (r *Renderer) Code(w io.Writer, node *ast.Code) {
+ r.Outs(w, "<code>")
EscapeHTML(w, node.Literal)
- r.outs(w, "</code>")
+ r.Outs(w, "</code>")
}
-func (r *Renderer) htmlBlock(w io.Writer, node *ast.HTMLBlock) {
+// HTMLBlock write ast.HTMLBlock node
+func (r *Renderer) HTMLBlock(w io.Writer, node *ast.HTMLBlock) {
if r.opts.Flags&SkipHTML != 0 {
return
}
- r.cr(w)
- r.out(w, node.Literal)
- r.cr(w)
+ r.CR(w)
+ r.Out(w, node.Literal)
+ r.CR(w)
}
func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) {
@@ -644,18 +708,19 @@ func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) {
attrs = append(attrs, attrID)
}
attrs = append(attrs, BlockAttrs(nodeData)...)
- r.cr(w)
+ r.CR(w)
r.outTag(w, headingOpenTagFromLevel(nodeData.Level), attrs)
}
func (r *Renderer) headingExit(w io.Writer, heading *ast.Heading) {
- r.outs(w, headingCloseTagFromLevel(heading.Level))
+ r.Outs(w, headingCloseTagFromLevel(heading.Level))
if !(isListItem(heading.Parent) && ast.GetNextNode(heading) == nil) {
- r.cr(w)
+ r.CR(w)
}
}
-func (r *Renderer) heading(w io.Writer, node *ast.Heading, entering bool) {
+// Heading writes ast.Heading node
+func (r *Renderer) Heading(w io.Writer, node *ast.Heading, entering bool) {
if entering {
r.headingEnter(w, node)
} else {
@@ -663,10 +728,11 @@ func (r *Renderer) heading(w io.Writer, node *ast.Heading, entering bool) {
}
}
-func (r *Renderer) horizontalRule(w io.Writer, node *ast.HorizontalRule) {
- r.cr(w)
+// HorizontalRule writes ast.HorizontalRule node
+func (r *Renderer) HorizontalRule(w io.Writer, node *ast.HorizontalRule) {
+ r.CR(w)
r.outHRTag(w, BlockAttrs(node))
- r.cr(w)
+ r.CR(w)
}
func (r *Renderer) listEnter(w io.Writer, nodeData *ast.List) {
@@ -674,17 +740,17 @@ func (r *Renderer) listEnter(w io.Writer, nodeData *ast.List) {
var attrs []string
if nodeData.IsFootnotesList {
- r.outs(w, "\n<div class=\"footnotes\">\n\n")
+ r.Outs(w, "\n<div class=\"footnotes\">\n\n")
if r.opts.Flags&FootnoteNoHRTag == 0 {
r.outHRTag(w, nil)
- r.cr(w)
+ r.CR(w)
}
}
- r.cr(w)
+ r.CR(w)
if isListItem(nodeData.Parent) {
grand := nodeData.Parent.GetParent()
if isListTight(grand) {
- r.cr(w)
+ r.CR(w)
}
}
@@ -700,7 +766,7 @@ func (r *Renderer) listEnter(w io.Writer, nodeData *ast.List) {
}
attrs = append(attrs, BlockAttrs(nodeData)...)
r.outTag(w, openTag, attrs)
- r.cr(w)
+ r.CR(w)
}
func (r *Renderer) listExit(w io.Writer, list *ast.List) {
@@ -711,7 +777,7 @@ func (r *Renderer) listExit(w io.Writer, list *ast.List) {
if list.ListFlags&ast.ListTypeDefinition != 0 {
closeTag = "</dl>"
}
- r.outs(w, closeTag)
+ r.Outs(w, closeTag)
//cr(w)
//if node.parent.Type != Item {
@@ -721,18 +787,19 @@ func (r *Renderer) listExit(w io.Writer, list *ast.List) {
switch parent.(type) {
case *ast.ListItem:
if ast.GetNextNode(list) != nil {
- r.cr(w)
+ r.CR(w)
}
case *ast.Document, *ast.BlockQuote, *ast.Aside:
- r.cr(w)
+ r.CR(w)
}
if list.IsFootnotesList {
- r.outs(w, "\n</div>\n")
+ r.Outs(w, "\n</div>\n")
}
}
-func (r *Renderer) list(w io.Writer, list *ast.List, entering bool) {
+// List writes ast.List node
+func (r *Renderer) List(w io.Writer, list *ast.List, entering bool) {
if entering {
r.listEnter(w, list)
} else {
@@ -742,11 +809,11 @@ func (r *Renderer) list(w io.Writer, list *ast.List, entering bool) {
func (r *Renderer) listItemEnter(w io.Writer, listItem *ast.ListItem) {
if listItemOpenCR(listItem) {
- r.cr(w)
+ r.CR(w)
}
if listItem.RefLink != nil {
slug := slugify(listItem.RefLink)
- r.outs(w, footnoteItem(r.opts.FootnoteAnchorPrefix, slug))
+ r.Outs(w, footnoteItem(r.opts.FootnoteAnchorPrefix, slug))
return
}
@@ -757,7 +824,7 @@ func (r *Renderer) listItemEnter(w io.Writer, listItem *ast.ListItem) {
if listItem.ListFlags&ast.ListTypeTerm != 0 {
openTag = "<dt>"
}
- r.outs(w, openTag)
+ r.Outs(w, openTag)
}
func (r *Renderer) listItemExit(w io.Writer, listItem *ast.ListItem) {
@@ -766,7 +833,7 @@ func (r *Renderer) listItemExit(w io.Writer, listItem *ast.ListItem) {
prefix := r.opts.FootnoteAnchorPrefix
link := r.opts.FootnoteReturnLinkContents
s := footnoteReturnLink(prefix, link, slug)
- r.outs(w, s)
+ r.Outs(w, s)
}
closeTag := "</li>"
@@ -776,11 +843,12 @@ func (r *Renderer) listItemExit(w io.Writer, listItem *ast.ListItem) {
if listItem.ListFlags&ast.ListTypeTerm != 0 {
closeTag = "</dt>"
}
- r.outs(w, closeTag)
- r.cr(w)
+ r.Outs(w, closeTag)
+ r.CR(w)
}
-func (r *Renderer) listItem(w io.Writer, listItem *ast.ListItem, entering bool) {
+// ListItem writes ast.ListItem node
+func (r *Renderer) ListItem(w io.Writer, listItem *ast.ListItem, entering bool) {
if entering {
r.listItemEnter(w, listItem)
} else {
@@ -788,38 +856,74 @@ func (r *Renderer) listItem(w io.Writer, listItem *ast.ListItem, entering bool)
}
}
-func (r *Renderer) codeBlock(w io.Writer, codeBlock *ast.CodeBlock) {
+// EscapeHTMLCallouts writes html-escaped d to w. It escapes &, <, > and " characters, *but*
+// expands callouts <<N>> with the callout HTML, i.e. by calling r.callout() with a newly created
+// ast.Callout node.
+func (r *Renderer) EscapeHTMLCallouts(w io.Writer, d []byte) {
+ ld := len(d)
+Parse:
+ for i := 0; i < ld; i++ {
+ for _, comment := range r.opts.Comments {
+ if !bytes.HasPrefix(d[i:], comment) {
+ break
+ }
+
+ lc := len(comment)
+ if i+lc < ld {
+ if id, consumed := parser.IsCallout(d[i+lc:]); consumed > 0 {
+ // We have seen a callout
+ callout := &ast.Callout{ID: id}
+ r.Callout(w, callout)
+ i += consumed + lc - 1
+ continue Parse
+ }
+ }
+ }
+
+ escSeq := Escaper[d[i]]
+ if escSeq != nil {
+ w.Write(escSeq)
+ } else {
+ w.Write([]byte{d[i]})
+ }
+ }
+}
+
+// CodeBlock writes ast.CodeBlock node
+func (r *Renderer) CodeBlock(w io.Writer, codeBlock *ast.CodeBlock) {
var attrs []string
// TODO(miek): this can add multiple class= attribute, they should be coalesced into one.
// This is probably true for some other elements as well
attrs = appendLanguageAttr(attrs, codeBlock.Info)
attrs = append(attrs, BlockAttrs(codeBlock)...)
- r.cr(w)
+ r.CR(w)
- r.outs(w, "<pre>")
- code := tagWithAttributes("<code", attrs)
- r.outs(w, code)
+ r.Outs(w, "<pre>")
+ code := TagWithAttributes("<code", attrs)
+ r.Outs(w, code)
if r.opts.Comments != nil {
r.EscapeHTMLCallouts(w, codeBlock.Literal)
} else {
EscapeHTML(w, codeBlock.Literal)
}
- r.outs(w, "</code>")
- r.outs(w, "</pre>")
+ r.Outs(w, "</code>")
+ r.Outs(w, "</pre>")
if !isListItem(codeBlock.Parent) {
- r.cr(w)
+ r.CR(w)
}
}
-func (r *Renderer) caption(w io.Writer, caption *ast.Caption, entering bool) {
+// Caption writes ast.Caption node
+func (r *Renderer) Caption(w io.Writer, caption *ast.Caption, entering bool) {
if entering {
- r.outs(w, "<figcaption>")
+ r.Outs(w, "<figcaption>")
return
}
- r.outs(w, "</figcaption>")
+ r.Outs(w, "</figcaption>")
}
-func (r *Renderer) captionFigure(w io.Writer, figure *ast.CaptionFigure, entering bool) {
+// CaptionFigure writes ast.CaptionFigure node
+func (r *Renderer) CaptionFigure(w io.Writer, figure *ast.CaptionFigure, entering bool) {
// TODO(miek): copy more generic ways of mmark over to here.
fig := "<figure"
if figure.HeadingID != "" {
@@ -827,13 +931,14 @@ func (r *Renderer) captionFigure(w io.Writer, figure *ast.CaptionFigure, enterin
} else {
fig += ">"
}
- r.outOneOf(w, entering, fig, "\n</figure>\n")
+ r.OutOneOf(w, entering, fig, "\n</figure>\n")
}
-func (r *Renderer) tableCell(w io.Writer, tableCell *ast.TableCell, entering bool) {
+// TableCell writes ast.TableCell node
+func (r *Renderer) TableCell(w io.Writer, tableCell *ast.TableCell, entering bool) {
if !entering {
- r.outOneOf(w, tableCell.IsHeader, "</th>", "</td>")
- r.cr(w)
+ r.OutOneOf(w, tableCell.IsHeader, "</th>", "</td>")
+ r.CR(w)
return
}
@@ -848,44 +953,47 @@ func (r *Renderer) tableCell(w io.Writer, tableCell *ast.TableCell, entering boo
attrs = append(attrs, fmt.Sprintf(`align="%s"`, align))
}
if ast.GetPrevNode(tableCell) == nil {
- r.cr(w)
+ r.CR(w)
}
r.outTag(w, openTag, attrs)
}
-func (r *Renderer) tableBody(w io.Writer, node *ast.TableBody, entering bool) {
+// TableBody writes ast.TableBody node
+func (r *Renderer) TableBody(w io.Writer, node *ast.TableBody, entering bool) {
if entering {
- r.cr(w)
- r.outs(w, "<tbody>")
+ r.CR(w)
+ r.Outs(w, "<tbody>")
// XXX: this is to adhere to a rather silly test. Should fix test.
if ast.GetFirstChild(node) == nil {
- r.cr(w)
+ r.CR(w)
}
} else {
- r.outs(w, "</tbody>")
- r.cr(w)
+ r.Outs(w, "</tbody>")
+ r.CR(w)
}
}
-func (r *Renderer) matter(w io.Writer, node *ast.DocumentMatter, entering bool) {
+// DocumentMatter writes ast.DocumentMatter
+func (r *Renderer) DocumentMatter(w io.Writer, node *ast.DocumentMatter, entering bool) {
if !entering {
return
}
if r.documentMatter != ast.DocumentMatterNone {
- r.outs(w, "</section>\n")
+ r.Outs(w, "</section>\n")
}
switch node.Matter {
case ast.DocumentMatterFront:
- r.outs(w, `<section data-matter="front">`)
+ r.Outs(w, `<section data-matter="front">`)
case ast.DocumentMatterMain:
- r.outs(w, `<section data-matter="main">`)
+ r.Outs(w, `<section data-matter="main">`)
case ast.DocumentMatterBack:
- r.outs(w, `<section data-matter="back">`)
+ r.Outs(w, `<section data-matter="back">`)
}
r.documentMatter = node.Matter
}
-func (r *Renderer) citation(w io.Writer, node *ast.Citation) {
+// Citation writes ast.Citation node
+func (r *Renderer) Citation(w io.Writer, node *ast.Citation) {
for i, c := range node.Destination {
attr := []string{`class="none"`}
switch node.Type[i] {
@@ -897,23 +1005,25 @@ func (r *Renderer) citation(w io.Writer, node *ast.Citation) {
attr[0] = `class="suppressed"`
}
r.outTag(w, "<cite", attr)
- r.outs(w, fmt.Sprintf(`<a href="#%s">`+r.opts.CitationFormatString+`</a>`, c, c))
- r.outs(w, "</cite>")
+ r.Outs(w, fmt.Sprintf(`<a href="#%s">`+r.opts.CitationFormatString+`</a>`, c, c))
+ r.Outs(w, "</cite>")
}
}
-func (r *Renderer) callout(w io.Writer, node *ast.Callout) {
+// Callout writes ast.Callout node
+func (r *Renderer) Callout(w io.Writer, node *ast.Callout) {
attr := []string{`class="callout"`}
r.outTag(w, "<span", attr)
- r.out(w, node.ID)
- r.outs(w, "</span>")
+ r.Out(w, node.ID)
+ r.Outs(w, "</span>")
}
-func (r *Renderer) index(w io.Writer, node *ast.Index) {
+// Index writes ast.Index node
+func (r *Renderer) Index(w io.Writer, node *ast.Index) {
// there is no in-text representation.
attr := []string{`class="index"`, fmt.Sprintf(`id="%s"`, node.ID)}
r.outTag(w, "<span", attr)
- r.outs(w, "</span>")
+ r.Outs(w, "</span>")
}
// RenderNode renders a markdown node to HTML
@@ -926,102 +1036,102 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal
}
switch node := node.(type) {
case *ast.Text:
- r.text(w, node)
+ r.Text(w, node)
case *ast.Softbreak:
- r.cr(w)
+ r.CR(w)
// TODO: make it configurable via out(renderer.softbreak)
case *ast.Hardbreak:
- r.hardBreak(w, node)
+ r.HardBreak(w, node)
case *ast.NonBlockingSpace:
- r.nonBlockingSpace(w, node)
+ r.NonBlockingSpace(w, node)
case *ast.Emph:
- r.outOneOf(w, entering, "<em>", "</em>")
+ r.OutOneOf(w, entering, "<em>", "</em>")
case *ast.Strong:
- r.outOneOf(w, entering, "<strong>", "</strong>")
+ r.OutOneOf(w, entering, "<strong>", "</strong>")
case *ast.Del:
- r.outOneOf(w, entering, "<del>", "</del>")
+ r.OutOneOf(w, entering, "<del>", "</del>")
case *ast.BlockQuote:
- tag := tagWithAttributes("<blockquote", BlockAttrs(node))
- r.outOneOfCr(w, entering, tag, "</blockquote>")
+ tag := TagWithAttributes("<blockquote", BlockAttrs(node))
+ r.OutOneOfCr(w, entering, tag, "</blockquote>")
case *ast.Aside:
- tag := tagWithAttributes("<aside", BlockAttrs(node))
- r.outOneOfCr(w, entering, tag, "</aside>")
+ tag := TagWithAttributes("<aside", BlockAttrs(node))
+ r.OutOneOfCr(w, entering, tag, "</aside>")
case *ast.Link:
- r.link(w, node, entering)
+ r.Link(w, node, entering)
case *ast.CrossReference:
link := &ast.Link{Destination: append([]byte("#"), node.Destination...)}
- r.link(w, link, entering)
+ r.Link(w, link, entering)
case *ast.Citation:
- r.citation(w, node)
+ r.Citation(w, node)
case *ast.Image:
if r.opts.Flags&SkipImages != 0 {
return ast.SkipChildren
}
- r.image(w, node, entering)
+ r.Image(w, node, entering)
case *ast.Code:
- r.code(w, node)
+ r.Code(w, node)
case *ast.CodeBlock:
- r.codeBlock(w, node)
+ r.CodeBlock(w, node)
case *ast.Caption:
- r.caption(w, node, entering)
+ r.Caption(w, node, entering)
case *ast.CaptionFigure:
- r.captionFigure(w, node, entering)
+ r.CaptionFigure(w, node, entering)
case *ast.Document:
// do nothing
case *ast.Paragraph:
- r.paragraph(w, node, entering)
+ r.Paragraph(w, node, entering)
case *ast.HTMLSpan:
- r.htmlSpan(w, node)
+ r.HTMLSpan(w, node)
case *ast.HTMLBlock:
- r.htmlBlock(w, node)
+ r.HTMLBlock(w, node)
case *ast.Heading:
- r.heading(w, node, entering)
+ r.Heading(w, node, entering)
case *ast.HorizontalRule:
- r.horizontalRule(w, node)
+ r.HorizontalRule(w, node)
case *ast.List:
- r.list(w, node, entering)
+ r.List(w, node, entering)
case *ast.ListItem:
- r.listItem(w, node, entering)
+ r.ListItem(w, node, entering)
case *ast.Table:
- tag := tagWithAttributes("<table", BlockAttrs(node))
- r.outOneOfCr(w, entering, tag, "</table>")
+ tag := TagWithAttributes("<table", BlockAttrs(node))
+ r.OutOneOfCr(w, entering, tag, "</table>")
case *ast.TableCell:
- r.tableCell(w, node, entering)
+ r.TableCell(w, node, entering)
case *ast.TableHeader:
- r.outOneOfCr(w, entering, "<thead>", "</thead>")
+ r.OutOneOfCr(w, entering, "<thead>", "</thead>")
case *ast.TableBody:
- r.tableBody(w, node, entering)
+ r.TableBody(w, node, entering)
case *ast.TableRow:
- r.outOneOfCr(w, entering, "<tr>", "</tr>")
+ r.OutOneOfCr(w, entering, "<tr>", "</tr>")
case *ast.TableFooter:
- r.outOneOfCr(w, entering, "<tfoot>", "</tfoot>")
+ r.OutOneOfCr(w, entering, "<tfoot>", "</tfoot>")
case *ast.Math:
- r.outOneOf(w, true, `<span class="math inline">\(`, `\)</span>`)
+ r.OutOneOf(w, true, `<span class="math inline">\(`, `\)</span>`)
EscapeHTML(w, node.Literal)
- r.outOneOf(w, false, `<span class="math inline">\(`, `\)</span>`)
+ r.OutOneOf(w, false, `<span class="math inline">\(`, `\)</span>`)
case *ast.MathBlock:
- r.outOneOf(w, entering, `<p><span class="math display">\[`, `\]</span></p>`)
+ r.OutOneOf(w, entering, `<p><span class="math display">\[`, `\]</span></p>`)
if entering {
EscapeHTML(w, node.Literal)
}
case *ast.DocumentMatter:
- r.matter(w, node, entering)
+ r.DocumentMatter(w, node, entering)
case *ast.Callout:
- r.callout(w, node)
+ r.Callout(w, node)
case *ast.Index:
- r.index(w, node)
+ r.Index(w, node)
case *ast.Subscript:
- r.outOneOf(w, true, "<sub>", "</sub>")
+ r.OutOneOf(w, true, "<sub>", "</sub>")
if entering {
Escape(w, node.Literal)
}
- r.outOneOf(w, false, "<sub>", "</sub>")
+ r.OutOneOf(w, false, "<sub>", "</sub>")
case *ast.Superscript:
- r.outOneOf(w, true, "<sup>", "</sup>")
+ r.OutOneOf(w, true, "<sup>", "</sup>")
if entering {
Escape(w, node.Literal)
}
- r.outOneOf(w, false, "<sup>", "</sup>")
+ r.OutOneOf(w, false, "<sup>", "</sup>")
case *ast.Footnotes:
// nothing by default; just output the list.
default:
@@ -1041,7 +1151,7 @@ func (r *Renderer) RenderHeader(w io.Writer, ast ast.Node) {
// RenderFooter writes HTML document footer.
func (r *Renderer) RenderFooter(w io.Writer, _ ast.Node) {
if r.documentMatter != ast.DocumentMatterNone {
- r.outs(w, "</section>\n")
+ r.Outs(w, "</section>\n")
}
if r.opts.Flags&CompletePage == 0 {
@@ -1315,7 +1425,8 @@ func BlockAttrs(node ast.Node) []string {
return s
}
-func tagWithAttributes(name string, attrs []string) string {
+// TagWithAttributes creates a HTML tag with a given name and attributes
+func TagWithAttributes(name string, attrs []string) string {
s := name
if len(attrs) > 0 {
s += " " + strings.Join(attrs, " ")