From 3c6f18afc72d1a27f6eb0673a3ee387f4a0548b5 Mon Sep 17 00:00:00 2001
From: Russ Ross
Date: Wed, 29 Jun 2011 11:13:17 -0600
Subject: [PATCH] Renderer is now an interface
---
block.go | 94 +++++++++++-----------------
example/main.go | 2 +-
html.go | 161 +++++++++++++++++++++---------------------------
inline.go | 83 ++++++++-----------------
latex.go | 89 +++++++++-----------------
markdown.go | 96 ++++++++++++-----------------
smartypants.go | 30 ---------
7 files changed, 203 insertions(+), 352 deletions(-)
diff --git a/block.go b/block.go
index 21cfb97..13f64ab 100644
--- a/block.go
+++ b/block.go
@@ -43,7 +43,7 @@ func (parser *Parser) parseBlock(out *bytes.Buffer, data []byte) {
//
// ...
//
- if data[0] == '<' && parser.r.BlockHtml != nil {
+ if data[0] == '<' {
if i := parser.blockHtml(out, data, true); i > 0 {
data = data[i:]
continue
@@ -64,9 +64,7 @@ func (parser *Parser) parseBlock(out *bytes.Buffer, data []byte) {
// or
// ______
if parser.isHRule(data) {
- if parser.r.HRule != nil {
- parser.r.HRule(out, parser.r.Opaque)
- }
+ parser.r.HRule(out)
var i int
for i = 0; i < len(data) && data[i] != '\n'; i++ {
}
@@ -189,13 +187,11 @@ func (parser *Parser) blockPrefixHeader(out *bytes.Buffer, data []byte) int {
end--
}
if end > i {
- if parser.r.Header != nil {
- work := func() bool {
- parser.parseInline(out, data[i:end])
- return true
- }
- parser.r.Header(out, work, level, parser.r.Opaque)
+ work := func() bool {
+ parser.parseInline(out, data[i:end])
+ return true
}
+ parser.r.Header(out, work, level)
}
return skip
}
@@ -261,8 +257,8 @@ func (parser *Parser) blockHtml(out *bytes.Buffer, data []byte, doRender bool) i
if j > 0 {
size := i + j
- if doRender && parser.r.BlockHtml != nil {
- parser.r.BlockHtml(out, data[:size], parser.r.Opaque)
+ if doRender {
+ parser.r.BlockHtml(out, data[:size])
}
return size
}
@@ -283,8 +279,8 @@ func (parser *Parser) blockHtml(out *bytes.Buffer, data []byte, doRender bool) i
j = parser.isEmpty(data[i:])
if j > 0 {
size := i + j
- if doRender && parser.r.BlockHtml != nil {
- parser.r.BlockHtml(out, data[:size], parser.r.Opaque)
+ if doRender {
+ parser.r.BlockHtml(out, data[:size])
}
return size
}
@@ -329,8 +325,8 @@ func (parser *Parser) blockHtml(out *bytes.Buffer, data []byte, doRender bool) i
}
// the end of the block has been found
- if doRender && parser.r.BlockHtml != nil {
- parser.r.BlockHtml(out, data[:i], parser.r.Opaque)
+ if doRender {
+ parser.r.BlockHtml(out, data[:i])
}
return i
@@ -566,15 +562,13 @@ func (parser *Parser) blockFencedCode(out *bytes.Buffer, data []byte) int {
work.WriteByte('\n')
}
- if parser.r.BlockCode != nil {
- syntax := ""
- if lang != nil {
- syntax = *lang
- }
-
- parser.r.BlockCode(out, work.Bytes(), syntax, parser.r.Opaque)
+ syntax := ""
+ if lang != nil {
+ syntax = *lang
}
+ parser.r.BlockCode(out, work.Bytes(), syntax)
+
return beg
}
@@ -604,9 +598,7 @@ func (parser *Parser) blockTable(out *bytes.Buffer, data []byte) int {
i++
}
- if parser.r.Table != nil {
- parser.r.Table(out, headerWork.Bytes(), bodyWork.Bytes(), colData, parser.r.Opaque)
- }
+ parser.r.Table(out, headerWork.Bytes(), bodyWork.Bytes(), colData)
return i
}
@@ -725,31 +717,25 @@ func (parser *Parser) blockTableRow(out *bytes.Buffer, data []byte, columns int,
var cellWork bytes.Buffer
parser.parseInline(&cellWork, data[cellStart:cellEnd+1])
- if parser.r.TableCell != nil {
- cdata := 0
- if col < len(colData) {
- cdata = colData[col]
- }
- parser.r.TableCell(&rowWork, cellWork.Bytes(), cdata, parser.r.Opaque)
+ cdata := 0
+ if col < len(colData) {
+ cdata = colData[col]
}
+ parser.r.TableCell(&rowWork, cellWork.Bytes(), cdata)
i++
}
for ; col < columns; col++ {
emptyCell := []byte{}
- if parser.r.TableCell != nil {
- cdata := 0
- if col < len(colData) {
- cdata = colData[col]
- }
- parser.r.TableCell(&rowWork, emptyCell, cdata, parser.r.Opaque)
+ cdata := 0
+ if col < len(colData) {
+ cdata = colData[col]
}
+ parser.r.TableCell(&rowWork, emptyCell, cdata)
}
- if parser.r.TableRow != nil {
- parser.r.TableRow(out, rowWork.Bytes(), parser.r.Opaque)
- }
+ parser.r.TableRow(out, rowWork.Bytes())
}
// returns blockquote prefix length
@@ -794,9 +780,7 @@ func (parser *Parser) blockQuote(out *bytes.Buffer, data []byte) int {
}
parser.parseBlock(&block, work.Bytes())
- if parser.r.BlockQuote != nil {
- parser.r.BlockQuote(out, block.Bytes(), parser.r.Opaque)
- }
+ parser.r.BlockQuote(out, block.Bytes())
return end
}
@@ -851,9 +835,7 @@ func (parser *Parser) blockCode(out *bytes.Buffer, data []byte) int {
work.WriteByte('\n')
- if parser.r.BlockCode != nil {
- parser.r.BlockCode(out, work.Bytes(), "", parser.r.Opaque)
- }
+ parser.r.BlockCode(out, work.Bytes(), "")
return beg
}
@@ -915,9 +897,7 @@ func (parser *Parser) blockList(out *bytes.Buffer, data []byte, flags int) int {
return true
}
- if parser.r.List != nil {
- parser.r.List(out, work, flags, parser.r.Opaque)
- }
+ parser.r.List(out, work, flags)
return i
}
@@ -1061,9 +1041,7 @@ func (parser *Parser) blockListItem(out *bytes.Buffer, data []byte, flags *int)
}
// render li itself
- if parser.r.ListItem != nil {
- parser.r.ListItem(out, inter.Bytes(), *flags, parser.r.Opaque)
- }
+ parser.r.ListItem(out, inter.Bytes(), *flags)
return beg
}
@@ -1081,7 +1059,7 @@ func (parser *Parser) renderParagraph(out *bytes.Buffer, data []byte) {
for end > beg && isspace(data[end-1]) {
end--
}
- if end == beg || parser.r.Paragraph == nil {
+ if end == beg {
return
}
@@ -1089,7 +1067,7 @@ func (parser *Parser) renderParagraph(out *bytes.Buffer, data []byte) {
parser.parseInline(out, data[beg:end])
return true
}
- parser.r.Paragraph(out, work, parser.r.Opaque)
+ parser.r.Paragraph(out, work)
}
func (parser *Parser) blockParagraph(out *bytes.Buffer, data []byte) int {
@@ -1112,7 +1090,7 @@ func (parser *Parser) blockParagraph(out *bytes.Buffer, data []byte) int {
}
// an underline under some text marks a header, so our paragraph ended on prev line
- if i > 0 && parser.r.Header != nil {
+ if i > 0 {
if level := parser.isUnderlinedHeader(current); level > 0 {
// render the paragraph
parser.renderParagraph(out, data[:prev])
@@ -1134,7 +1112,7 @@ func (parser *Parser) blockParagraph(out *bytes.Buffer, data []byte) int {
return true
}
}(out, parser, data[prev:eol])
- parser.r.Header(out, work, level, parser.r.Opaque)
+ parser.r.Header(out, work, level)
// find the end of the underline
for ; i < len(data) && data[i] != '\n'; i++ {
@@ -1145,7 +1123,7 @@ func (parser *Parser) blockParagraph(out *bytes.Buffer, data []byte) int {
// if the next line starts a block of HTML, then the paragraph ends here
if parser.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
- if data[i] == '<' && parser.r.BlockHtml != nil && parser.blockHtml(out, current, false) > 0 {
+ if data[i] == '<' && parser.blockHtml(out, current, false) > 0 {
// rewind to before the HTML block
parser.renderParagraph(out, data[:i])
return i
diff --git a/example/main.go b/example/main.go
index 3466cd6..a6bd1a4 100644
--- a/example/main.go
+++ b/example/main.go
@@ -121,7 +121,7 @@ func main() {
extensions |= blackfriday.EXTENSION_STRIKETHROUGH
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
- var renderer *blackfriday.Renderer
+ var renderer blackfriday.Renderer
if latex {
// render the data into LaTeX
renderer = blackfriday.LatexRenderer(0)
diff --git a/html.go b/html.go
index 648a75c..b2d9314 100644
--- a/html.go
+++ b/html.go
@@ -37,7 +37,7 @@ const (
HTML_SMARTYPANTS_LATEX_DASHES
)
-type htmlOptions struct {
+type Html struct {
flags int // HTML_* options
closeTag string // how to end singleton tags: either " />\n" or ">\n"
title string // document title
@@ -52,48 +52,19 @@ type htmlOptions struct {
smartypants *SmartypantsRenderer
}
-var xhtmlClose = " />\n"
-var htmlClose = ">\n"
+const (
+ xhtmlClose = " />\n"
+ htmlClose = ">\n"
+)
-func HtmlRenderer(flags int, title string, css string) *Renderer {
+func HtmlRenderer(flags int, title string, css string) Renderer {
// configure the rendering engine
- r := new(Renderer)
-
- r.BlockCode = htmlBlockCode
- r.BlockQuote = htmlBlockQuote
- r.BlockHtml = htmlBlockHtml
- r.Header = htmlHeader
- r.HRule = htmlHRule
- r.List = htmlList
- r.ListItem = htmlListItem
- r.Paragraph = htmlParagraph
- r.Table = htmlTable
- r.TableRow = htmlTableRow
- r.TableCell = htmlTableCell
-
- r.AutoLink = htmlAutoLink
- r.CodeSpan = htmlCodeSpan
- r.DoubleEmphasis = htmlDoubleEmphasis
- r.Emphasis = htmlEmphasis
- r.Image = htmlImage
- r.LineBreak = htmlLineBreak
- r.Link = htmlLink
- r.RawHtmlTag = htmlRawTag
- r.TripleEmphasis = htmlTripleEmphasis
- r.StrikeThrough = htmlStrikeThrough
-
- r.Entity = htmlEntity
- r.NormalText = htmlNormalText
-
- r.DocumentHeader = htmlDocumentHeader
- r.DocumentFooter = htmlDocumentFooter
-
closeTag := htmlClose
if flags&HTML_USE_XHTML != 0 {
closeTag = xhtmlClose
}
- r.Opaque = &htmlOptions{
+ return &Html{
flags: flags,
closeTag: closeTag,
title: title,
@@ -105,7 +76,6 @@ func HtmlRenderer(flags int, title string, css string) *Renderer {
smartypants: Smartypants(flags),
}
- return r
}
func attrEscape(out *bytes.Buffer, src []byte) {
@@ -154,8 +124,7 @@ func attrEscape(out *bytes.Buffer, src []byte) {
}
}
-func htmlHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) {
- options := opaque.(*htmlOptions)
+func (options *Html) Header(out *bytes.Buffer, text func() bool, level int) {
marker := out.Len()
if marker > 0 {
@@ -177,14 +146,13 @@ func htmlHeader(out *bytes.Buffer, text func() bool, level int, opaque interface
// are we building a table of contents?
if options.flags&HTML_TOC != 0 {
- htmlTocHeader(out.Bytes()[tocMarker:], level, opaque)
+ options.TocHeader(out.Bytes()[tocMarker:], level)
}
out.WriteString(fmt.Sprintf("\n", level))
}
-func htmlBlockHtml(out *bytes.Buffer, text []byte, opaque interface{}) {
- options := opaque.(*htmlOptions)
+func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) {
if options.flags&HTML_SKIP_HTML != 0 {
return
}
@@ -207,9 +175,7 @@ func htmlBlockHtml(out *bytes.Buffer, text []byte, opaque interface{}) {
out.WriteByte('\n')
}
-func htmlHRule(out *bytes.Buffer, opaque interface{}) {
- options := opaque.(*htmlOptions)
-
+func (options *Html) HRule(out *bytes.Buffer) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -217,16 +183,15 @@ func htmlHRule(out *bytes.Buffer, opaque interface{}) {
out.WriteString(options.closeTag)
}
-func htmlBlockCode(out *bytes.Buffer, text []byte, lang string, opaque interface{}) {
- options := opaque.(*htmlOptions)
+func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) {
if options.flags&HTML_GITHUB_BLOCKCODE != 0 {
- htmlBlockCodeGithub(out, text, lang, opaque)
+ options.BlockCodeGithub(out, text, lang)
} else {
- htmlBlockCodeNormal(out, text, lang, opaque)
+ options.BlockCodeNormal(out, text, lang)
}
}
-func htmlBlockCodeNormal(out *bytes.Buffer, text []byte, lang string, opaque interface{}) {
+func (options *Html) BlockCodeNormal(out *bytes.Buffer, text []byte, lang string) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -286,7 +251,7 @@ func htmlBlockCodeNormal(out *bytes.Buffer, text []byte, lang string, opaque int
* E.g.
* ~~~~ {.python .numbered} =>
*/
-func htmlBlockCodeGithub(out *bytes.Buffer, text []byte, lang string, opaque interface{}) {
+func (options *Html) BlockCodeGithub(out *bytes.Buffer, text []byte, lang string) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -318,13 +283,13 @@ func htmlBlockCodeGithub(out *bytes.Buffer, text []byte, lang string, opaque int
}
-func htmlBlockQuote(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) {
out.WriteString("\n")
out.Write(text)
out.WriteString("
")
}
-func htmlTable(out *bytes.Buffer, header []byte, body []byte, columnData []int, opaque interface{}) {
+func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -335,7 +300,7 @@ func htmlTable(out *bytes.Buffer, header []byte, body []byte, columnData []int,
out.WriteString("\n")
}
-func htmlTableRow(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Html) TableRow(out *bytes.Buffer, text []byte) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -344,7 +309,7 @@ func htmlTableRow(out *bytes.Buffer, text []byte, opaque interface{}) {
out.WriteString("\n")
}
-func htmlTableCell(out *bytes.Buffer, text []byte, align int, opaque interface{}) {
+func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteByte('\n')
}
@@ -363,7 +328,7 @@ func htmlTableCell(out *bytes.Buffer, text []byte, align int, opaque interface{}
out.WriteString("")
}
-func htmlList(out *bytes.Buffer, text func() bool, flags int, opaque interface{}) {
+func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) {
marker := out.Len()
if marker > 0 {
@@ -385,7 +350,7 @@ func htmlList(out *bytes.Buffer, text func() bool, flags int, opaque interface{}
}
}
-func htmlListItem(out *bytes.Buffer, text []byte, flags int, opaque interface{}) {
+func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) {
out.WriteString("")
size := len(text)
for size > 0 && text[size-1] == '\n' {
@@ -395,7 +360,7 @@ func htmlListItem(out *bytes.Buffer, text []byte, flags int, opaque interface{})
out.WriteString("\n")
}
-func htmlParagraph(out *bytes.Buffer, text func() bool, opaque interface{}) {
+func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
if marker > 0 {
out.WriteByte('\n')
@@ -409,9 +374,7 @@ func htmlParagraph(out *bytes.Buffer, text func() bool, opaque interface{}) {
out.WriteString("
\n")
}
-func htmlAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{}) bool {
- options := opaque.(*htmlOptions)
-
+func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) bool {
if len(link) == 0 {
return false
}
@@ -445,14 +408,14 @@ func htmlAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{})
return true
}
-func htmlCodeSpan(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) bool {
out.WriteString("")
attrEscape(out, text)
out.WriteString("
")
return true
}
-func htmlDoubleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) bool {
if len(text) == 0 {
return false
}
@@ -462,7 +425,7 @@ func htmlDoubleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool
return true
}
-func htmlEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Html) Emphasis(out *bytes.Buffer, text []byte) bool {
if len(text) == 0 {
return false
}
@@ -472,8 +435,7 @@ func htmlEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
return true
}
-func htmlImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque interface{}) bool {
- options := opaque.(*htmlOptions)
+func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) bool {
if options.flags&HTML_SKIP_IMAGES != 0 {
return false
}
@@ -497,15 +459,13 @@ func htmlImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque
return true
}
-func htmlLineBreak(out *bytes.Buffer, opaque interface{}) bool {
- options := opaque.(*htmlOptions)
+func (options *Html) LineBreak(out *bytes.Buffer) bool {
out.WriteString("
mark {
+ out.Write(text[mark:i])
+ }
+
+ previousChar := byte(0)
+ if i > 0 {
+ previousChar = text[i-1]
+ }
+ i += action(out, &smrt, previousChar, text[i:])
+ mark = i + 1
+ }
+ }
+
+ if mark < len(text) {
+ out.Write(text[mark:])
+ }
+}
+
+func (options *Html) DocumentHeader(out *bytes.Buffer) {
if options.flags&HTML_COMPLETE_PAGE == 0 {
return
}
@@ -596,7 +582,7 @@ func htmlDocumentHeader(out *bytes.Buffer, opaque interface{}) {
}
out.WriteString("\n")
out.WriteString(" ")
- htmlNormalText(out, []byte(options.title), opaque)
+ options.NormalText(out, []byte(options.title))
out.WriteString("\n")
out.WriteString(" options.currentLevel {
switch {
case bytes.HasSuffix(options.toc.Bytes(), []byte("\n")):
@@ -685,8 +667,7 @@ func htmlTocHeader(text []byte, level int, opaque interface{}) {
options.toc.WriteString("\n")
}
-func htmlTocFinalize(opaque interface{}) {
- options := opaque.(*htmlOptions)
+func (options *Html) TocFinalize() {
for options.currentLevel > 1 {
options.toc.WriteString("\n")
options.currentLevel--
diff --git a/inline.go b/inline.go
index eca7f43..4ecf862 100644
--- a/inline.go
+++ b/inline.go
@@ -36,11 +36,7 @@ func (parser *Parser) parseInline(out *bytes.Buffer, data []byte) {
end++
}
- if parser.r.NormalText != nil {
- parser.r.NormalText(out, data[i:end], parser.r.Opaque)
- } else {
- out.Write(data[i:end])
- }
+ parser.r.NormalText(out, data[i:end])
if end >= len(data) {
break
@@ -143,10 +139,7 @@ func inlineCodeSpan(out *bytes.Buffer, parser *Parser, data []byte, offset int)
}
// render the code span
- if parser.r.CodeSpan == nil {
- return 0
- }
- if !parser.r.CodeSpan(out, data[fBegin:fEnd], parser.r.Opaque) {
+ if !parser.r.CodeSpan(out, data[fBegin:fEnd]) {
end = 0
}
@@ -171,10 +164,7 @@ func inlineLineBreak(out *bytes.Buffer, parser *Parser, data []byte, offset int)
return 0
}
- if parser.r.LineBreak == nil {
- return 0
- }
- if parser.r.LineBreak(out, parser.r.Opaque) {
+ if parser.r.LineBreak(out) {
return 1
} else {
return 0
@@ -198,11 +188,6 @@ func inlineLink(out *bytes.Buffer, parser *Parser, data []byte, offset int) int
var title, link []byte
textHasNl := false
- // check whether the correct renderer exists
- if (isImg && parser.r.Image == nil) || (!isImg && parser.r.Link == nil) {
- return 0
- }
-
// look for the matching closing bracket
for level := 1; level > 0 && i < len(data); i++ {
switch {
@@ -439,9 +424,9 @@ func inlineLink(out *bytes.Buffer, parser *Parser, data []byte, offset int) int
out.Truncate(outSize - 1)
}
- ret = parser.r.Image(out, uLink, title, content.Bytes(), parser.r.Opaque)
+ ret = parser.r.Image(out, uLink, title, content.Bytes())
} else {
- ret = parser.r.Link(out, uLink, title, content.Bytes(), parser.r.Opaque)
+ ret = parser.r.Link(out, uLink, title, content.Bytes())
}
if ret {
@@ -458,13 +443,12 @@ func inlineLAngle(out *bytes.Buffer, parser *Parser, data []byte, offset int) in
ret := false
if end > 2 {
- switch {
- case parser.r.AutoLink != nil && altype != LINK_TYPE_NOT_AUTOLINK:
+ if altype != LINK_TYPE_NOT_AUTOLINK {
var uLink bytes.Buffer
unescapeText(&uLink, data[1:end+1-2])
- ret = parser.r.AutoLink(out, uLink.Bytes(), altype, parser.r.Opaque)
- case parser.r.RawHtmlTag != nil:
- ret = parser.r.RawHtmlTag(out, data[:end], parser.r.Opaque)
+ ret = parser.r.AutoLink(out, uLink.Bytes(), altype)
+ } else {
+ ret = parser.r.RawHtmlTag(out, data[:end])
}
}
@@ -485,11 +469,7 @@ func inlineEscape(out *bytes.Buffer, parser *Parser, data []byte, offset int) in
return 0
}
- if parser.r.NormalText != nil {
- parser.r.NormalText(out, data[1:2], parser.r.Opaque)
- } else {
- out.WriteByte(data[1])
- }
+ parser.r.NormalText(out, data[1:2])
}
return 2
@@ -537,11 +517,7 @@ func inlineEntity(out *bytes.Buffer, parser *Parser, data []byte, offset int) in
return 0 // lone '&'
}
- if parser.r.Entity != nil {
- parser.r.Entity(out, data[:end], parser.r.Opaque)
- } else {
- out.Write(data[:end])
- }
+ parser.r.Entity(out, data[:end])
return end
}
@@ -642,12 +618,10 @@ func inlineAutoLink(out *bytes.Buffer, parser *Parser, data []byte, offset int)
out.Truncate(len(out.Bytes()) - rewind)
}
- if parser.r.AutoLink != nil {
- var uLink bytes.Buffer
- unescapeText(&uLink, data[:linkEnd])
+ var uLink bytes.Buffer
+ unescapeText(&uLink, data[:linkEnd])
- parser.r.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL, parser.r.Opaque)
- }
+ parser.r.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL)
return linkEnd - rewind
}
@@ -863,10 +837,6 @@ func inlineHelperFindEmphChar(data []byte, c byte) int {
func inlineHelperEmph1(out *bytes.Buffer, parser *Parser, data []byte, c byte) int {
i := 0
- if parser.r.Emphasis == nil {
- return 0
- }
-
// skip one symbol if coming from emph3
if len(data) > 1 && data[0] == c && data[1] == c {
i = 1
@@ -897,7 +867,7 @@ func inlineHelperEmph1(out *bytes.Buffer, parser *Parser, data []byte, c byte) i
var work bytes.Buffer
parser.parseInline(&work, data[:i])
- if parser.r.Emphasis(out, work.Bytes(), parser.r.Opaque) {
+ if parser.r.Emphasis(out, work.Bytes()) {
return i + 1
} else {
return 0
@@ -909,15 +879,6 @@ func inlineHelperEmph1(out *bytes.Buffer, parser *Parser, data []byte, c byte) i
}
func inlineHelperEmph2(out *bytes.Buffer, parser *Parser, data []byte, c byte) int {
- renderMethod := parser.r.DoubleEmphasis
- if c == '~' {
- renderMethod = parser.r.StrikeThrough
- }
-
- if renderMethod == nil {
- return 0
- }
-
i := 0
for i < len(data) {
@@ -930,7 +891,15 @@ func inlineHelperEmph2(out *bytes.Buffer, parser *Parser, data []byte, c byte) i
if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) {
var work bytes.Buffer
parser.parseInline(&work, data[:i])
- if renderMethod(out, work.Bytes(), parser.r.Opaque) {
+ success := false
+
+ // pick the right renderer
+ if c == '~' {
+ success = parser.r.StrikeThrough(out, work.Bytes())
+ } else {
+ success = parser.r.DoubleEmphasis(out, work.Bytes())
+ }
+ if success {
return i + 2
} else {
return 0
@@ -959,12 +928,12 @@ func inlineHelperEmph3(out *bytes.Buffer, parser *Parser, data []byte, offset in
}
switch {
- case (i+2 < len(data) && data[i+1] == c && data[i+2] == c && parser.r.TripleEmphasis != nil):
+ case i+2 < len(data) && data[i+1] == c && data[i+2] == c:
// triple symbol found
var work bytes.Buffer
parser.parseInline(&work, data[:i])
- if parser.r.TripleEmphasis(out, work.Bytes(), parser.r.Opaque) {
+ if parser.r.TripleEmphasis(out, work.Bytes()) {
return i + 3
} else {
return 0
diff --git a/latex.go b/latex.go
index f62b973..7739746 100644
--- a/latex.go
+++ b/latex.go
@@ -19,47 +19,16 @@ import (
"bytes"
)
-func LatexRenderer(flags int) *Renderer {
- // configure the rendering engine
- r := new(Renderer)
+type Latex struct {
- // block-level rendering
- r.BlockCode = latexBlockCode
- r.BlockQuote = latexBlockQuote
- r.BlockHtml = latexBlockHtml
- r.Header = latexHeader
- r.HRule = latexHRule
- r.List = latexList
- r.ListItem = latexListItem
- r.Paragraph = latexParagraph
- r.Table = latexTable
- r.TableRow = latexTableRow
- r.TableCell = latexTableCell
+}
- // inline rendering
- r.AutoLink = latexAutoLink
- r.CodeSpan = latexCodeSpan
- r.DoubleEmphasis = latexDoubleEmphasis
- r.Emphasis = latexEmphasis
- r.Image = latexImage
- r.LineBreak = latexLineBreak
- r.Link = latexLink
- r.RawHtmlTag = latexRawHtmlTag
- r.TripleEmphasis = latexTripleEmphasis
- r.StrikeThrough = latexStrikeThrough
-
- r.Entity = latexEntity
- r.NormalText = latexNormalText
-
- r.DocumentHeader = latexDocumentHeader
- r.DocumentFooter = latexDocumentFooter
-
- r.Opaque = nil
- return r
+func LatexRenderer(flags int) Renderer {
+ return &Latex{}
}
// render code chunks using verbatim, or listings if we have a language
-func latexBlockCode(out *bytes.Buffer, text []byte, lang string, opaque interface{}) {
+func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) {
if lang == "" {
out.WriteString("\n\\begin{verbatim}\n")
} else {
@@ -75,20 +44,20 @@ func latexBlockCode(out *bytes.Buffer, text []byte, lang string, opaque interfac
}
}
-func latexBlockQuote(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
out.WriteString("\n\\begin{quotation}\n")
out.Write(text)
out.WriteString("\n\\end{quotation}\n")
}
-func latexBlockHtml(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
// a pretty lame thing to do...
out.WriteString("\n\\begin{verbatim}\n")
out.Write(text)
out.WriteString("\n\\end{verbatim}\n")
}
-func latexHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) {
+func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int) {
marker := out.Len()
switch level {
@@ -112,11 +81,11 @@ func latexHeader(out *bytes.Buffer, text func() bool, level int, opaque interfac
out.WriteString("}\n")
}
-func latexHRule(out *bytes.Buffer, opaque interface{}) {
+func (options *Latex) HRule(out *bytes.Buffer) {
out.WriteString("\n\\HRule\n")
}
-func latexList(out *bytes.Buffer, text func() bool, flags int, opaque interface{}) {
+func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
marker := out.Len()
if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("\n\\begin{enumerate}\n")
@@ -134,12 +103,12 @@ func latexList(out *bytes.Buffer, text func() bool, flags int, opaque interface{
}
}
-func latexListItem(out *bytes.Buffer, text []byte, flags int, opaque interface{}) {
+func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
out.WriteString("\n\\item ")
out.Write(text)
}
-func latexParagraph(out *bytes.Buffer, text func() bool, opaque interface{}) {
+func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
out.WriteString("\n")
if !text() {
@@ -149,7 +118,7 @@ func latexParagraph(out *bytes.Buffer, text func() bool, opaque interface{}) {
out.WriteString("\n")
}
-func latexTable(out *bytes.Buffer, header []byte, body []byte, columnData []int, opaque interface{}) {
+func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
out.WriteString("\n\\begin{tabular}{")
for _, elt := range columnData {
switch elt {
@@ -168,21 +137,21 @@ func latexTable(out *bytes.Buffer, header []byte, body []byte, columnData []int,
out.WriteString("\n\\end{tabular}\n")
}
-func latexTableRow(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
if out.Len() > 0 {
out.WriteString(" \\\\\n")
}
out.Write(text)
}
-func latexTableCell(out *bytes.Buffer, text []byte, align int, opaque interface{}) {
+func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}
-func latexAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{}) bool {
+func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) bool {
out.WriteString("\\href{")
if kind == LINK_TYPE_EMAIL {
out.WriteString("mailto:")
@@ -194,28 +163,28 @@ func latexAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{})
return true
}
-func latexCodeSpan(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) bool {
out.WriteString("\\texttt{")
escapeSpecialChars(out, text)
out.WriteString("}")
return true
}
-func latexDoubleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) bool {
out.WriteString("\\textbf{")
out.Write(text)
out.WriteString("}")
return true
}
-func latexEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) bool {
out.WriteString("\\textit{")
out.Write(text)
out.WriteString("}")
return true
}
-func latexImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque interface{}) bool {
+func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) bool {
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
// treat it like a link
out.WriteString("\\href{")
@@ -231,12 +200,12 @@ func latexImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque
return true
}
-func latexLineBreak(out *bytes.Buffer, opaque interface{}) bool {
+func (options *Latex) LineBreak(out *bytes.Buffer) bool {
out.WriteString(" \\\\\n")
return true
}
-func latexLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opaque interface{}) bool {
+func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) bool {
out.WriteString("\\href{")
out.Write(link)
out.WriteString("}{")
@@ -245,18 +214,18 @@ func latexLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opa
return true
}
-func latexRawHtmlTag(out *bytes.Buffer, tag []byte, opaque interface{}) bool {
+func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) bool {
return true
}
-func latexTripleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) bool {
out.WriteString("\\textbf{\\textit{")
out.Write(text)
out.WriteString("}}")
return true
}
-func latexStrikeThrough(out *bytes.Buffer, text []byte, opaque interface{}) bool {
+func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) bool {
out.WriteString("\\sout{")
out.Write(text)
out.WriteString("}")
@@ -293,17 +262,17 @@ func escapeSpecialChars(out *bytes.Buffer, text []byte) {
}
}
-func latexEntity(out *bytes.Buffer, entity []byte, opaque interface{}) {
+func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
// TODO: convert this into a unicode character or something
out.Write(entity)
}
-func latexNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
+func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
escapeSpecialChars(out, text)
}
// header and footer
-func latexDocumentHeader(out *bytes.Buffer, opaque interface{}) {
+func (options *Latex) DocumentHeader(out *bytes.Buffer) {
out.WriteString("\\documentclass{article}\n")
out.WriteString("\n")
out.WriteString("\\usepackage{graphicx}\n")
@@ -332,6 +301,6 @@ func latexDocumentHeader(out *bytes.Buffer, opaque interface{}) {
out.WriteString("\\begin{document}\n")
}
-func latexDocumentFooter(out *bytes.Buffer, opaque interface{}) {
+func (options *Latex) DocumentFooter(out *bytes.Buffer) {
out.WriteString("\n\\end{document}\n")
}
diff --git a/markdown.go b/markdown.go
index 5efc9e9..4b18155 100644
--- a/markdown.go
+++ b/markdown.go
@@ -105,48 +105,45 @@ var blockTags = map[string]bool{
//
// This is mostly of interest if you are implementing a new rendering format.
// Most users will use the convenience functions to fill in this structure.
-type Renderer struct {
- // block-level callbacks---nil skips the block
- BlockCode func(out *bytes.Buffer, text []byte, lang string, opaque interface{})
- BlockQuote func(out *bytes.Buffer, text []byte, opaque interface{})
- BlockHtml func(out *bytes.Buffer, text []byte, opaque interface{})
- Header func(out *bytes.Buffer, text func() bool, level int, opaque interface{})
- HRule func(out *bytes.Buffer, opaque interface{})
- List func(out *bytes.Buffer, text func() bool, flags int, opaque interface{})
- ListItem func(out *bytes.Buffer, text []byte, flags int, opaque interface{})
- Paragraph func(out *bytes.Buffer, text func() bool, opaque interface{})
- Table func(out *bytes.Buffer, header []byte, body []byte, columnData []int, opaque interface{})
- TableRow func(out *bytes.Buffer, text []byte, opaque interface{})
- TableCell func(out *bytes.Buffer, text []byte, flags int, opaque interface{})
+type Renderer interface {
+ // block-level callbacks
+ BlockCode(out *bytes.Buffer, text []byte, lang string)
+ BlockQuote(out *bytes.Buffer, text []byte)
+ BlockHtml(out *bytes.Buffer, text []byte)
+ Header(out *bytes.Buffer, text func() bool, level int)
+ HRule(out *bytes.Buffer)
+ List(out *bytes.Buffer, text func() bool, flags int)
+ ListItem(out *bytes.Buffer, text []byte, flags int)
+ Paragraph(out *bytes.Buffer, text func() bool)
+ Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
+ TableRow(out *bytes.Buffer, text []byte)
+ TableCell(out *bytes.Buffer, text []byte, flags int)
- // Span-level callbacks---nil or return false prints the span verbatim
- AutoLink func(out *bytes.Buffer, link []byte, kind int, opaque interface{}) bool
- CodeSpan func(out *bytes.Buffer, text []byte, opaque interface{}) bool
- DoubleEmphasis func(out *bytes.Buffer, text []byte, opaque interface{}) bool
- Emphasis func(out *bytes.Buffer, text []byte, opaque interface{}) bool
- Image func(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque interface{}) bool
- LineBreak func(out *bytes.Buffer, opaque interface{}) bool
- Link func(out *bytes.Buffer, link []byte, title []byte, content []byte, opaque interface{}) bool
- RawHtmlTag func(out *bytes.Buffer, tag []byte, opaque interface{}) bool
- TripleEmphasis func(out *bytes.Buffer, text []byte, opaque interface{}) bool
- StrikeThrough func(out *bytes.Buffer, text []byte, opaque interface{}) bool
+ // Span-level callbacks---return false prints the span verbatim
+ AutoLink(out *bytes.Buffer, link []byte, kind int) bool
+ CodeSpan(out *bytes.Buffer, text []byte) bool
+ DoubleEmphasis(out *bytes.Buffer, text []byte) bool
+ Emphasis(out *bytes.Buffer, text []byte) bool
+ Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) bool
+ LineBreak(out *bytes.Buffer) bool
+ Link(out *bytes.Buffer, link []byte, title []byte, content []byte) bool
+ RawHtmlTag(out *bytes.Buffer, tag []byte) bool
+ TripleEmphasis(out *bytes.Buffer, text []byte) bool
+ StrikeThrough(out *bytes.Buffer, text []byte) bool
- // Low-level callbacks---nil copies input directly into the output
- Entity func(out *bytes.Buffer, entity []byte, opaque interface{})
- NormalText func(out *bytes.Buffer, text []byte, opaque interface{})
+ // Low-level callbacks
+ Entity(out *bytes.Buffer, entity []byte)
+ NormalText(out *bytes.Buffer, text []byte)
// Header and footer
- DocumentHeader func(out *bytes.Buffer, opaque interface{})
- DocumentFooter func(out *bytes.Buffer, opaque interface{})
-
- // User data---passed back to every callback
- Opaque interface{}
+ DocumentHeader(out *bytes.Buffer)
+ DocumentFooter(out *bytes.Buffer)
}
type inlineParser func(out *bytes.Buffer, parser *Parser, data []byte, offset int) int
type Parser struct {
- r *Renderer
+ r Renderer
refs map[string]*reference
inline [256]inlineParser
flags int
@@ -199,7 +196,7 @@ func MarkdownCommon(input []byte) []byte {
// Parse and render a block of markdown-encoded text.
// The renderer is used to format the output, and extensions dictates which
// non-standard extensions are enabled.
-func Markdown(input []byte, renderer *Renderer, extensions int) []byte {
+func Markdown(input []byte, renderer Renderer, extensions int) []byte {
// no point in parsing if we can't render
if renderer == nil {
return nil
@@ -214,22 +211,14 @@ func Markdown(input []byte, renderer *Renderer, extensions int) []byte {
parser.insideLink = false
// register inline parsers
- if parser.r.Emphasis != nil || parser.r.DoubleEmphasis != nil || parser.r.TripleEmphasis != nil {
- parser.inline['*'] = inlineEmphasis
- parser.inline['_'] = inlineEmphasis
- if extensions&EXTENSION_STRIKETHROUGH != 0 {
- parser.inline['~'] = inlineEmphasis
- }
- }
- if parser.r.CodeSpan != nil {
- parser.inline['`'] = inlineCodeSpan
- }
- if parser.r.LineBreak != nil {
- parser.inline['\n'] = inlineLineBreak
- }
- if parser.r.Image != nil || parser.r.Link != nil {
- parser.inline['['] = inlineLink
+ parser.inline['*'] = inlineEmphasis
+ parser.inline['_'] = inlineEmphasis
+ if extensions&EXTENSION_STRIKETHROUGH != 0 {
+ parser.inline['~'] = inlineEmphasis
}
+ parser.inline['`'] = inlineCodeSpan
+ parser.inline['\n'] = inlineLineBreak
+ parser.inline['['] = inlineLink
parser.inline['<'] = inlineLAngle
parser.inline['\\'] = inlineEscape
parser.inline['&'] = inlineEntity
@@ -291,15 +280,10 @@ func firstPass(parser *Parser, input []byte) []byte {
// second pass: actual rendering
func secondPass(parser *Parser, input []byte) []byte {
var output bytes.Buffer
- if parser.r.DocumentHeader != nil {
- parser.r.DocumentHeader(&output, parser.r.Opaque)
- }
+ parser.r.DocumentHeader(&output)
parser.parseBlock(&output, input)
-
- if parser.r.DocumentFooter != nil {
- parser.r.DocumentFooter(&output, parser.r.Opaque)
- }
+ parser.r.DocumentFooter(&output)
if parser.nesting != 0 {
panic("Nesting level did not end at zero")
diff --git a/smartypants.go b/smartypants.go
index 24e34e5..771af25 100644
--- a/smartypants.go
+++ b/smartypants.go
@@ -369,33 +369,3 @@ func Smartypants(flags int) *SmartypantsRenderer {
r['`'] = smartBacktick
return r
}
-
-func htmlSmartypants(out *bytes.Buffer, text []byte, opaque interface{}) {
- options := opaque.(*htmlOptions)
- smrt := smartypantsData{false, false}
-
- // first do normal entity escaping
- var escaped bytes.Buffer
- attrEscape(&escaped, text)
- text = escaped.Bytes()
-
- mark := 0
- for i := 0; i < len(text); i++ {
- if action := options.smartypants[text[i]]; action != nil {
- if i > mark {
- out.Write(text[mark:i])
- }
-
- previousChar := byte(0)
- if i > 0 {
- previousChar = text[i-1]
- }
- i += action(out, &smrt, previousChar, text[i:])
- mark = i + 1
- }
- }
-
- if mark < len(text) {
- out.Write(text[mark:])
- }
-}