Renderer is now an interface
This commit is contained in:
parent
793fee5451
commit
3c6f18afc7
94
block.go
94
block.go
|
@ -43,7 +43,7 @@ func (parser *Parser) parseBlock(out *bytes.Buffer, data []byte) {
|
|||
// <div>
|
||||
// ...
|
||||
// </div>
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
161
html.go
161
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("</h%d>\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} => <pre lang="python"><code>
|
||||
*/
|
||||
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("<blockquote>\n")
|
||||
out.Write(text)
|
||||
out.WriteString("</blockquote>")
|
||||
}
|
||||
|
||||
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</tbody></table>")
|
||||
}
|
||||
|
||||
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</tr>")
|
||||
}
|
||||
|
||||
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("</td>")
|
||||
}
|
||||
|
||||
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("<li>")
|
||||
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("</li>\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("</p>\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("<code>")
|
||||
attrEscape(out, text)
|
||||
out.WriteString("</code>")
|
||||
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("<br")
|
||||
out.WriteString(options.closeTag)
|
||||
return true
|
||||
}
|
||||
|
||||
func htmlLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opaque interface{}) bool {
|
||||
options := opaque.(*htmlOptions)
|
||||
func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) bool {
|
||||
if options.flags&HTML_SKIP_LINKS != 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -526,8 +486,7 @@ func htmlLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opaq
|
|||
return true
|
||||
}
|
||||
|
||||
func htmlRawTag(out *bytes.Buffer, text []byte, opaque interface{}) bool {
|
||||
options := opaque.(*htmlOptions)
|
||||
func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) bool {
|
||||
if options.flags&HTML_SKIP_HTML != 0 {
|
||||
return true
|
||||
}
|
||||
|
@ -544,7 +503,7 @@ func htmlRawTag(out *bytes.Buffer, text []byte, opaque interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func htmlTripleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool {
|
||||
func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) bool {
|
||||
if len(text) == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -554,7 +513,7 @@ func htmlTripleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) bool
|
|||
return true
|
||||
}
|
||||
|
||||
func htmlStrikeThrough(out *bytes.Buffer, text []byte, opaque interface{}) bool {
|
||||
func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) bool {
|
||||
if len(text) == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -564,21 +523,48 @@ func htmlStrikeThrough(out *bytes.Buffer, text []byte, opaque interface{}) bool
|
|||
return true
|
||||
}
|
||||
|
||||
func htmlEntity(out *bytes.Buffer, entity []byte, opaque interface{}) {
|
||||
func (options *Html) Entity(out *bytes.Buffer, entity []byte) {
|
||||
out.Write(entity)
|
||||
}
|
||||
|
||||
func htmlNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
|
||||
options := opaque.(*htmlOptions)
|
||||
func (options *Html) NormalText(out *bytes.Buffer, text []byte) {
|
||||
if options.flags&HTML_USE_SMARTYPANTS != 0 {
|
||||
htmlSmartypants(out, text, opaque)
|
||||
options.Smartypants(out, text)
|
||||
} else {
|
||||
attrEscape(out, text)
|
||||
}
|
||||
}
|
||||
|
||||
func htmlDocumentHeader(out *bytes.Buffer, opaque interface{}) {
|
||||
options := opaque.(*htmlOptions)
|
||||
func (options *Html) Smartypants(out *bytes.Buffer, text []byte) {
|
||||
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:])
|
||||
}
|
||||
}
|
||||
|
||||
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("<head>\n")
|
||||
out.WriteString(" <title>")
|
||||
htmlNormalText(out, []byte(options.title), opaque)
|
||||
options.NormalText(out, []byte(options.title))
|
||||
out.WriteString("</title>\n")
|
||||
out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
|
||||
out.WriteString(VERSION)
|
||||
|
@ -619,12 +605,10 @@ func htmlDocumentHeader(out *bytes.Buffer, opaque interface{}) {
|
|||
options.tocMarker = out.Len()
|
||||
}
|
||||
|
||||
func htmlDocumentFooter(out *bytes.Buffer, opaque interface{}) {
|
||||
options := opaque.(*htmlOptions)
|
||||
|
||||
func (options *Html) DocumentFooter(out *bytes.Buffer) {
|
||||
// finalize and insert the table of contents
|
||||
if options.flags&HTML_TOC != 0 {
|
||||
htmlTocFinalize(opaque)
|
||||
options.TocFinalize()
|
||||
|
||||
// now we have to insert the table of contents into the document
|
||||
var temp bytes.Buffer
|
||||
|
@ -651,9 +635,7 @@ func htmlDocumentFooter(out *bytes.Buffer, opaque interface{}) {
|
|||
|
||||
}
|
||||
|
||||
func htmlTocHeader(text []byte, level int, opaque interface{}) {
|
||||
options := opaque.(*htmlOptions)
|
||||
|
||||
func (options *Html) TocHeader(text []byte, level int) {
|
||||
for level > options.currentLevel {
|
||||
switch {
|
||||
case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")):
|
||||
|
@ -685,8 +667,7 @@ func htmlTocHeader(text []byte, level int, opaque interface{}) {
|
|||
options.toc.WriteString("</a></li>\n")
|
||||
}
|
||||
|
||||
func htmlTocFinalize(opaque interface{}) {
|
||||
options := opaque.(*htmlOptions)
|
||||
func (options *Html) TocFinalize() {
|
||||
for options.currentLevel > 1 {
|
||||
options.toc.WriteString("</ul></li>\n")
|
||||
options.currentLevel--
|
||||
|
|
83
inline.go
83
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
|
||||
|
|
89
latex.go
89
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")
|
||||
}
|
||||
|
|
96
markdown.go
96
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")
|
||||
|
|
|
@ -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:])
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue