mirror of
https://github.com/russross/blackfriday.git
synced 2024-03-22 13:40:34 +08:00
render -> Parser, made parsing functions methods of *Parser
This commit is contained in:
parent
55cde00c8a
commit
f0cd9a420e
259
block.go
259
block.go
|
@ -18,12 +18,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// parse block-level data
|
// parse block-level data
|
||||||
func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
func (parser *Parser) parseBlock(out *bytes.Buffer, data []byte) {
|
||||||
// this is called recursively: enforce a maximum depth
|
// this is called recursively: enforce a maximum depth
|
||||||
if rndr.nesting >= rndr.maxNesting {
|
if parser.nesting >= parser.maxNesting {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rndr.nesting++
|
parser.nesting++
|
||||||
|
|
||||||
// parse out one block-level construct at a time
|
// parse out one block-level construct at a time
|
||||||
for len(data) > 0 {
|
for len(data) > 0 {
|
||||||
|
@ -33,8 +33,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// ## Header 2
|
// ## Header 2
|
||||||
// ...
|
// ...
|
||||||
// ###### Header 6
|
// ###### Header 6
|
||||||
if isPrefixHeader(rndr, data) {
|
if parser.isPrefixHeader(data) {
|
||||||
data = data[blockPrefixHeader(out, rndr, data):]
|
data = data[parser.blockPrefixHeader(out, data):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,15 +43,15 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// <div>
|
// <div>
|
||||||
// ...
|
// ...
|
||||||
// </div>
|
// </div>
|
||||||
if data[0] == '<' && rndr.mk.BlockHtml != nil {
|
if data[0] == '<' && parser.r.BlockHtml != nil {
|
||||||
if i := blockHtml(out, rndr, data, true); i > 0 {
|
if i := parser.blockHtml(out, data, true); i > 0 {
|
||||||
data = data[i:]
|
data = data[i:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blank lines. note: returns the # of bytes to skip
|
// blank lines. note: returns the # of bytes to skip
|
||||||
if i := isEmpty(data); i > 0 {
|
if i := parser.isEmpty(data); i > 0 {
|
||||||
data = data[i:]
|
data = data[i:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,9 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// ******
|
// ******
|
||||||
// or
|
// or
|
||||||
// ______
|
// ______
|
||||||
if isHRule(data) {
|
if parser.isHRule(data) {
|
||||||
if rndr.mk.HRule != nil {
|
if parser.r.HRule != nil {
|
||||||
rndr.mk.HRule(out, rndr.mk.Opaque)
|
parser.r.HRule(out, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
var i int
|
var i int
|
||||||
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
||||||
|
@ -84,8 +84,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// return n * fact(n-1)
|
// return n * fact(n-1)
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
if rndr.flags&EXTENSION_FENCED_CODE != 0 {
|
if parser.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
if i := blockFencedCode(out, rndr, data); i > 0 {
|
if i := parser.blockFencedCode(out, data); i > 0 {
|
||||||
data = data[i:]
|
data = data[i:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// ------|-----|---------
|
// ------|-----|---------
|
||||||
// Bob | 31 | 555-1234
|
// Bob | 31 | 555-1234
|
||||||
// Alice | 27 | 555-4321
|
// Alice | 27 | 555-4321
|
||||||
if rndr.flags&EXTENSION_TABLES != 0 {
|
if parser.flags&EXTENSION_TABLES != 0 {
|
||||||
if i := blockTable(out, rndr, data); i > 0 {
|
if i := parser.blockTable(out, data); i > 0 {
|
||||||
data = data[i:]
|
data = data[i:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -108,8 +108,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
//
|
//
|
||||||
// > A big quote I found somewhere
|
// > A big quote I found somewhere
|
||||||
// > on the web
|
// > on the web
|
||||||
if blockQuotePrefix(data) > 0 {
|
if parser.blockQuotePrefix(data) > 0 {
|
||||||
data = data[blockQuote(out, rndr, data):]
|
data = data[parser.blockQuote(out, data):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// }
|
// }
|
||||||
// return b
|
// return b
|
||||||
// }
|
// }
|
||||||
if blockCodePrefix(data) > 0 {
|
if parser.blockCodePrefix(data) > 0 {
|
||||||
data = data[blockCode(out, rndr, data):]
|
data = data[parser.blockCode(out, data):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,8 +132,8 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
// * Item 2
|
// * Item 2
|
||||||
//
|
//
|
||||||
// also works with + or -
|
// also works with + or -
|
||||||
if blockUliPrefix(data) > 0 {
|
if parser.blockUliPrefix(data) > 0 {
|
||||||
data = data[blockList(out, rndr, data, 0):]
|
data = data[parser.blockList(out, data, 0):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,25 +141,25 @@ func parseBlock(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
//
|
//
|
||||||
// 1. Item 1
|
// 1. Item 1
|
||||||
// 2. Item 2
|
// 2. Item 2
|
||||||
if blockOliPrefix(data) > 0 {
|
if parser.blockOliPrefix(data) > 0 {
|
||||||
data = data[blockList(out, rndr, data, LIST_TYPE_ORDERED):]
|
data = data[parser.blockList(out, data, LIST_TYPE_ORDERED):]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// anything else must look like a normal paragraph
|
// anything else must look like a normal paragraph
|
||||||
// note: this finds underlined headers, too
|
// note: this finds underlined headers, too
|
||||||
data = data[blockParagraph(out, rndr, data):]
|
data = data[parser.blockParagraph(out, data):]
|
||||||
}
|
}
|
||||||
|
|
||||||
rndr.nesting--
|
parser.nesting--
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPrefixHeader(rndr *render, data []byte) bool {
|
func (parser *Parser) isPrefixHeader(data []byte) bool {
|
||||||
if data[0] != '#' {
|
if data[0] != '#' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.flags&EXTENSION_SPACE_HEADERS != 0 {
|
if parser.flags&EXTENSION_SPACE_HEADERS != 0 {
|
||||||
level := 0
|
level := 0
|
||||||
for level < len(data) && level < 6 && data[level] == '#' {
|
for level < len(data) && level < 6 && data[level] == '#' {
|
||||||
level++
|
level++
|
||||||
|
@ -171,7 +171,7 @@ func isPrefixHeader(rndr *render, data []byte) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockPrefixHeader(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockPrefixHeader(out *bytes.Buffer, data []byte) int {
|
||||||
level := 0
|
level := 0
|
||||||
for level < len(data) && level < 6 && data[level] == '#' {
|
for level < len(data) && level < 6 && data[level] == '#' {
|
||||||
level++
|
level++
|
||||||
|
@ -189,18 +189,18 @@ func blockPrefixHeader(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
end--
|
end--
|
||||||
}
|
}
|
||||||
if end > i {
|
if end > i {
|
||||||
if rndr.mk.Header != nil {
|
if parser.r.Header != nil {
|
||||||
work := func() bool {
|
work := func() bool {
|
||||||
parseInline(out, rndr, data[i:end])
|
parser.parseInline(out, data[i:end])
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
rndr.mk.Header(out, work, level, rndr.mk.Opaque)
|
parser.r.Header(out, work, level, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return skip
|
return skip
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUnderlinedHeader(data []byte) int {
|
func (parser *Parser) isUnderlinedHeader(data []byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
// test of level 1 header
|
// test of level 1 header
|
||||||
|
@ -234,14 +234,14 @@ func isUnderlinedHeader(data []byte) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockHtml(out *bytes.Buffer, rndr *render, data []byte, doRender bool) int {
|
func (parser *Parser) blockHtml(out *bytes.Buffer, data []byte, doRender bool) int {
|
||||||
var i, j int
|
var i, j int
|
||||||
|
|
||||||
// identify the opening tag
|
// identify the opening tag
|
||||||
if len(data) < 2 || data[0] != '<' {
|
if len(data) < 2 || data[0] != '<' {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
curtag, tagfound := blockHtmlFindTag(data[1:])
|
curtag, tagfound := parser.blockHtmlFindTag(data[1:])
|
||||||
|
|
||||||
// handle special cases
|
// handle special cases
|
||||||
if !tagfound {
|
if !tagfound {
|
||||||
|
@ -256,13 +256,13 @@ func blockHtml(out *bytes.Buffer, rndr *render, data []byte, doRender bool) int
|
||||||
i++
|
i++
|
||||||
|
|
||||||
if i < len(data) {
|
if i < len(data) {
|
||||||
j = isEmpty(data[i:])
|
j = parser.isEmpty(data[i:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
size := i + j
|
size := i + j
|
||||||
if doRender && rndr.mk.BlockHtml != nil {
|
if doRender && parser.r.BlockHtml != nil {
|
||||||
rndr.mk.BlockHtml(out, data[:size], rndr.mk.Opaque)
|
parser.r.BlockHtml(out, data[:size], parser.r.Opaque)
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
@ -280,11 +280,11 @@ func blockHtml(out *bytes.Buffer, rndr *render, data []byte, doRender bool) int
|
||||||
|
|
||||||
if i+1 < len(data) {
|
if i+1 < len(data) {
|
||||||
i++
|
i++
|
||||||
j = isEmpty(data[i:])
|
j = parser.isEmpty(data[i:])
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
size := i + j
|
size := i + j
|
||||||
if doRender && rndr.mk.BlockHtml != nil {
|
if doRender && parser.r.BlockHtml != nil {
|
||||||
rndr.mk.BlockHtml(out, data[:size], rndr.mk.Opaque)
|
parser.r.BlockHtml(out, data[:size], parser.r.Opaque)
|
||||||
}
|
}
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ func blockHtml(out *bytes.Buffer, rndr *render, data []byte, doRender bool) int
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
j = blockHtmlFindEnd(curtag, rndr, data[i-1:])
|
j = parser.blockHtmlFindEnd(curtag, data[i-1:])
|
||||||
|
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
i += j - 1
|
i += j - 1
|
||||||
|
@ -329,14 +329,14 @@ func blockHtml(out *bytes.Buffer, rndr *render, data []byte, doRender bool) int
|
||||||
}
|
}
|
||||||
|
|
||||||
// the end of the block has been found
|
// the end of the block has been found
|
||||||
if doRender && rndr.mk.BlockHtml != nil {
|
if doRender && parser.r.BlockHtml != nil {
|
||||||
rndr.mk.BlockHtml(out, data[:i], rndr.mk.Opaque)
|
parser.r.BlockHtml(out, data[:i], parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockHtmlFindTag(data []byte) (string, bool) {
|
func (parser *Parser) blockHtmlFindTag(data []byte) (string, bool) {
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(data) && isalnum(data[i]) {
|
for i < len(data) && isalnum(data[i]) {
|
||||||
i++
|
i++
|
||||||
|
@ -351,7 +351,7 @@ func blockHtmlFindTag(data []byte) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockHtmlFindEnd(tag string, rndr *render, data []byte) int {
|
func (parser *Parser) blockHtmlFindEnd(tag string, data []byte) int {
|
||||||
// assume data[0] == '<' && data[1] == '/' already tested
|
// assume data[0] == '<' && data[1] == '/' already tested
|
||||||
|
|
||||||
// check if tag is a match
|
// check if tag is a match
|
||||||
|
@ -364,20 +364,20 @@ func blockHtmlFindEnd(tag string, rndr *render, data []byte) int {
|
||||||
i := len(tag) + 3
|
i := len(tag) + 3
|
||||||
w := 0
|
w := 0
|
||||||
if i < len(data) {
|
if i < len(data) {
|
||||||
if w = isEmpty(data[i:]); w == 0 {
|
if w = parser.isEmpty(data[i:]); w == 0 {
|
||||||
return 0 // non-blank after tag
|
return 0 // non-blank after tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += w
|
i += w
|
||||||
w = 0
|
w = 0
|
||||||
|
|
||||||
if rndr.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
|
if parser.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
|
||||||
if i < len(data) {
|
if i < len(data) {
|
||||||
w = isEmpty(data[i:])
|
w = parser.isEmpty(data[i:])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if i < len(data) {
|
if i < len(data) {
|
||||||
if w = isEmpty(data[i:]); w == 0 {
|
if w = parser.isEmpty(data[i:]); w == 0 {
|
||||||
return 0 // non-blank line after tag line
|
return 0 // non-blank line after tag line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,7 +386,7 @@ func blockHtmlFindEnd(tag string, rndr *render, data []byte) int {
|
||||||
return i + w
|
return i + w
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEmpty(data []byte) int {
|
func (parser *Parser) isEmpty(data []byte) int {
|
||||||
var i int
|
var i int
|
||||||
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
||||||
if data[i] != ' ' && data[i] != '\t' {
|
if data[i] != ' ' && data[i] != '\t' {
|
||||||
|
@ -396,7 +396,7 @@ func isEmpty(data []byte) int {
|
||||||
return i + 1
|
return i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHRule(data []byte) bool {
|
func (parser *Parser) isHRule(data []byte) bool {
|
||||||
// skip initial spaces
|
// skip initial spaces
|
||||||
if len(data) < 3 {
|
if len(data) < 3 {
|
||||||
return false
|
return false
|
||||||
|
@ -429,7 +429,7 @@ func isHRule(data []byte) bool {
|
||||||
return n >= 3
|
return n >= 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, marker string) {
|
func (parser *Parser) isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, marker string) {
|
||||||
i, size := 0, 0
|
i, size := 0, 0
|
||||||
skip = 0
|
skip = 0
|
||||||
|
|
||||||
|
@ -526,9 +526,9 @@ func isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, mar
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockFencedCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockFencedCode(out *bytes.Buffer, data []byte) int {
|
||||||
var lang *string
|
var lang *string
|
||||||
beg, marker := isFencedCode(data, &lang, "")
|
beg, marker := parser.isFencedCode(data, &lang, "")
|
||||||
if beg == 0 {
|
if beg == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -536,7 +536,7 @@ func blockFencedCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
|
|
||||||
for beg < len(data) {
|
for beg < len(data) {
|
||||||
fenceEnd, _ := isFencedCode(data[beg:], nil, marker)
|
fenceEnd, _ := parser.isFencedCode(data[beg:], nil, marker)
|
||||||
if fenceEnd != 0 {
|
if fenceEnd != 0 {
|
||||||
beg += fenceEnd
|
beg += fenceEnd
|
||||||
break
|
break
|
||||||
|
@ -548,7 +548,7 @@ func blockFencedCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
|
|
||||||
if beg < end {
|
if beg < end {
|
||||||
// verbatim copy to the working buffer
|
// verbatim copy to the working buffer
|
||||||
if isEmpty(data[beg:]) > 0 {
|
if parser.isEmpty(data[beg:]) > 0 {
|
||||||
work.WriteByte('\n')
|
work.WriteByte('\n')
|
||||||
} else {
|
} else {
|
||||||
work.Write(data[beg:end])
|
work.Write(data[beg:end])
|
||||||
|
@ -566,21 +566,21 @@ func blockFencedCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
work.WriteByte('\n')
|
work.WriteByte('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.BlockCode != nil {
|
if parser.r.BlockCode != nil {
|
||||||
syntax := ""
|
syntax := ""
|
||||||
if lang != nil {
|
if lang != nil {
|
||||||
syntax = *lang
|
syntax = *lang
|
||||||
}
|
}
|
||||||
|
|
||||||
rndr.mk.BlockCode(out, work.Bytes(), syntax, rndr.mk.Opaque)
|
parser.r.BlockCode(out, work.Bytes(), syntax, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return beg
|
return beg
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockTable(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockTable(out *bytes.Buffer, data []byte) int {
|
||||||
var headerWork bytes.Buffer
|
var headerWork bytes.Buffer
|
||||||
i, columns, colData := blockTableHeader(&headerWork, rndr, data)
|
i, columns, colData := parser.blockTableHeader(&headerWork, data)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -600,18 +600,18 @@ func blockTable(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
blockTableRow(&bodyWork, rndr, data[rowStart:i], columns, colData)
|
parser.blockTableRow(&bodyWork, data[rowStart:i], columns, colData)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.Table != nil {
|
if parser.r.Table != nil {
|
||||||
rndr.mk.Table(out, headerWork.Bytes(), bodyWork.Bytes(), colData, rndr.mk.Opaque)
|
parser.r.Table(out, headerWork.Bytes(), bodyWork.Bytes(), colData, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockTableHeader(out *bytes.Buffer, rndr *render, data []byte) (size int, columns int, columnData []int) {
|
func (parser *Parser) blockTableHeader(out *bytes.Buffer, data []byte) (size int, columns int, columnData []int) {
|
||||||
i, pipes := 0, 0
|
i, pipes := 0, 0
|
||||||
columnData = []int{}
|
columnData = []int{}
|
||||||
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
for i = 0; i < len(data) && data[i] != '\n'; i++ {
|
||||||
|
@ -692,12 +692,12 @@ func blockTableHeader(out *bytes.Buffer, rndr *render, data []byte) (size int, c
|
||||||
return 0, 0, columnData
|
return 0, 0, columnData
|
||||||
}
|
}
|
||||||
|
|
||||||
blockTableRow(out, rndr, data[:headerEnd], columns, columnData)
|
parser.blockTableRow(out, data[:headerEnd], columns, columnData)
|
||||||
size = underEnd + 1
|
size = underEnd + 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockTableRow(out *bytes.Buffer, rndr *render, data []byte, columns int, colData []int) {
|
func (parser *Parser) blockTableRow(out *bytes.Buffer, data []byte, columns int, colData []int) {
|
||||||
i, col := 0, 0
|
i, col := 0, 0
|
||||||
var rowWork bytes.Buffer
|
var rowWork bytes.Buffer
|
||||||
|
|
||||||
|
@ -723,14 +723,14 @@ func blockTableRow(out *bytes.Buffer, rndr *render, data []byte, columns int, co
|
||||||
}
|
}
|
||||||
|
|
||||||
var cellWork bytes.Buffer
|
var cellWork bytes.Buffer
|
||||||
parseInline(&cellWork, rndr, data[cellStart:cellEnd+1])
|
parser.parseInline(&cellWork, data[cellStart:cellEnd+1])
|
||||||
|
|
||||||
if rndr.mk.TableCell != nil {
|
if parser.r.TableCell != nil {
|
||||||
cdata := 0
|
cdata := 0
|
||||||
if col < len(colData) {
|
if col < len(colData) {
|
||||||
cdata = colData[col]
|
cdata = colData[col]
|
||||||
}
|
}
|
||||||
rndr.mk.TableCell(&rowWork, cellWork.Bytes(), cdata, rndr.mk.Opaque)
|
parser.r.TableCell(&rowWork, cellWork.Bytes(), cdata, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
i++
|
i++
|
||||||
|
@ -738,22 +738,22 @@ func blockTableRow(out *bytes.Buffer, rndr *render, data []byte, columns int, co
|
||||||
|
|
||||||
for ; col < columns; col++ {
|
for ; col < columns; col++ {
|
||||||
emptyCell := []byte{}
|
emptyCell := []byte{}
|
||||||
if rndr.mk.TableCell != nil {
|
if parser.r.TableCell != nil {
|
||||||
cdata := 0
|
cdata := 0
|
||||||
if col < len(colData) {
|
if col < len(colData) {
|
||||||
cdata = colData[col]
|
cdata = colData[col]
|
||||||
}
|
}
|
||||||
rndr.mk.TableCell(&rowWork, emptyCell, cdata, rndr.mk.Opaque)
|
parser.r.TableCell(&rowWork, emptyCell, cdata, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.TableRow != nil {
|
if parser.r.TableRow != nil {
|
||||||
rndr.mk.TableRow(out, rowWork.Bytes(), rndr.mk.Opaque)
|
parser.r.TableRow(out, rowWork.Bytes(), parser.r.Opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns blockquote prefix length
|
// returns blockquote prefix length
|
||||||
func blockQuotePrefix(data []byte) int {
|
func (parser *Parser) blockQuotePrefix(data []byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(data) && i < 3 && data[i] == ' ' {
|
for i < len(data) && i < 3 && data[i] == ' ' {
|
||||||
i++
|
i++
|
||||||
|
@ -768,7 +768,7 @@ func blockQuotePrefix(data []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse a blockquote fragment
|
// parse a blockquote fragment
|
||||||
func blockQuote(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockQuote(out *bytes.Buffer, data []byte) int {
|
||||||
var block bytes.Buffer
|
var block bytes.Buffer
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
beg, end := 0, 0
|
beg, end := 0, 0
|
||||||
|
@ -776,11 +776,13 @@ func blockQuote(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
for end = beg + 1; end < len(data) && data[end-1] != '\n'; end++ {
|
for end = beg + 1; end < len(data) && data[end-1] != '\n'; end++ {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pre := blockQuotePrefix(data[beg:]); pre > 0 {
|
if pre := parser.blockQuotePrefix(data[beg:]); pre > 0 {
|
||||||
beg += pre // skip prefix
|
beg += pre // skip prefix
|
||||||
} else {
|
} else {
|
||||||
// empty line followed by non-quote line
|
// empty line followed by non-quote line
|
||||||
if isEmpty(data[beg:]) > 0 && (end >= len(data) || (blockQuotePrefix(data[end:]) == 0 && isEmpty(data[end:]) == 0)) {
|
if parser.isEmpty(data[beg:]) > 0 &&
|
||||||
|
(end >= len(data) ||
|
||||||
|
(parser.blockQuotePrefix(data[end:]) == 0 && parser.isEmpty(data[end:]) == 0)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -791,15 +793,15 @@ func blockQuote(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
beg = end
|
beg = end
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBlock(&block, rndr, work.Bytes())
|
parser.parseBlock(&block, work.Bytes())
|
||||||
if rndr.mk.BlockQuote != nil {
|
if parser.r.BlockQuote != nil {
|
||||||
rndr.mk.BlockQuote(out, block.Bytes(), rndr.mk.Opaque)
|
parser.r.BlockQuote(out, block.Bytes(), parser.r.Opaque)
|
||||||
}
|
}
|
||||||
return end
|
return end
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns prefix length for block code
|
// returns prefix length for block code
|
||||||
func blockCodePrefix(data []byte) int {
|
func (parser *Parser) blockCodePrefix(data []byte) int {
|
||||||
if len(data) > 0 && data[0] == '\t' {
|
if len(data) > 0 && data[0] == '\t' {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -809,7 +811,7 @@ func blockCodePrefix(data []byte) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockCode(out *bytes.Buffer, data []byte) int {
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
|
|
||||||
beg, end := 0, 0
|
beg, end := 0, 0
|
||||||
|
@ -817,10 +819,10 @@ func blockCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
for end = beg + 1; end < len(data) && data[end-1] != '\n'; end++ {
|
for end = beg + 1; end < len(data) && data[end-1] != '\n'; end++ {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pre := blockCodePrefix(data[beg:end]); pre > 0 {
|
if pre := parser.blockCodePrefix(data[beg:end]); pre > 0 {
|
||||||
beg += pre
|
beg += pre
|
||||||
} else {
|
} else {
|
||||||
if isEmpty(data[beg:end]) == 0 {
|
if parser.isEmpty(data[beg:end]) == 0 {
|
||||||
// non-empty non-prefixed line breaks the pre
|
// non-empty non-prefixed line breaks the pre
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -828,7 +830,7 @@ func blockCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
|
|
||||||
if beg < end {
|
if beg < end {
|
||||||
// verbatim copy to the working buffer, escaping entities
|
// verbatim copy to the working buffer, escaping entities
|
||||||
if isEmpty(data[beg:end]) > 0 {
|
if parser.isEmpty(data[beg:end]) > 0 {
|
||||||
work.WriteByte('\n')
|
work.WriteByte('\n')
|
||||||
} else {
|
} else {
|
||||||
work.Write(data[beg:end])
|
work.Write(data[beg:end])
|
||||||
|
@ -849,15 +851,15 @@ func blockCode(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
|
|
||||||
work.WriteByte('\n')
|
work.WriteByte('\n')
|
||||||
|
|
||||||
if rndr.mk.BlockCode != nil {
|
if parser.r.BlockCode != nil {
|
||||||
rndr.mk.BlockCode(out, work.Bytes(), "", rndr.mk.Opaque)
|
parser.r.BlockCode(out, work.Bytes(), "", parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return beg
|
return beg
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns unordered list item prefix
|
// returns unordered list item prefix
|
||||||
func blockUliPrefix(data []byte) int {
|
func (parser *Parser) blockUliPrefix(data []byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
// start with up to 3 spaces
|
// start with up to 3 spaces
|
||||||
|
@ -875,7 +877,7 @@ func blockUliPrefix(data []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns ordered list item prefix
|
// returns ordered list item prefix
|
||||||
func blockOliPrefix(data []byte) int {
|
func (parser *Parser) blockOliPrefix(data []byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
// start with up to 3 spaces
|
// start with up to 3 spaces
|
||||||
|
@ -898,12 +900,12 @@ func blockOliPrefix(data []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse ordered or unordered list block
|
// parse ordered or unordered list block
|
||||||
func blockList(out *bytes.Buffer, rndr *render, data []byte, flags int) int {
|
func (parser *Parser) blockList(out *bytes.Buffer, data []byte, flags int) int {
|
||||||
i := 0
|
i := 0
|
||||||
work := func() bool {
|
work := func() bool {
|
||||||
j := 0
|
j := 0
|
||||||
for i < len(data) {
|
for i < len(data) {
|
||||||
j = blockListItem(out, rndr, data[i:], &flags)
|
j = parser.blockListItem(out, data[i:], &flags)
|
||||||
i += j
|
i += j
|
||||||
|
|
||||||
if j == 0 || flags&LIST_ITEM_END_OF_LIST != 0 {
|
if j == 0 || flags&LIST_ITEM_END_OF_LIST != 0 {
|
||||||
|
@ -913,15 +915,15 @@ func blockList(out *bytes.Buffer, rndr *render, data []byte, flags int) int {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.List != nil {
|
if parser.r.List != nil {
|
||||||
rndr.mk.List(out, work, flags, rndr.mk.Opaque)
|
parser.r.List(out, work, flags, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse a single list item
|
// parse a single list item
|
||||||
// assumes initial prefix is already removed
|
// assumes initial prefix is already removed
|
||||||
func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int {
|
func (parser *Parser) blockListItem(out *bytes.Buffer, data []byte, flags *int) int {
|
||||||
// keep track of the first indentation prefix
|
// keep track of the first indentation prefix
|
||||||
beg, end, pre, sublist, orgpre, i := 0, 0, 0, 0, 0, 0
|
beg, end, pre, sublist, orgpre, i := 0, 0, 0, 0, 0, 0
|
||||||
|
|
||||||
|
@ -929,9 +931,9 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
orgpre++
|
orgpre++
|
||||||
}
|
}
|
||||||
|
|
||||||
beg = blockUliPrefix(data)
|
beg = parser.blockUliPrefix(data)
|
||||||
if beg == 0 {
|
if beg == 0 {
|
||||||
beg = blockOliPrefix(data)
|
beg = parser.blockOliPrefix(data)
|
||||||
}
|
}
|
||||||
if beg == 0 {
|
if beg == 0 {
|
||||||
return 0
|
return 0
|
||||||
|
@ -966,7 +968,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
// process an empty line
|
// process an empty line
|
||||||
if isEmpty(data[beg:end]) > 0 {
|
if parser.isEmpty(data[beg:end]) > 0 {
|
||||||
containsBlankLine = true
|
containsBlankLine = true
|
||||||
beg = end
|
beg = end
|
||||||
continue
|
continue
|
||||||
|
@ -982,7 +984,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
if data[beg] == '\t' {
|
if data[beg] == '\t' {
|
||||||
i = 1
|
i = 1
|
||||||
pre = TAB_SIZE_DEFAULT
|
pre = TAB_SIZE_DEFAULT
|
||||||
if rndr.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
if parser.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
||||||
pre = TAB_SIZE_EIGHT
|
pre = TAB_SIZE_EIGHT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -990,7 +992,8 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
chunk := data[beg+i : end]
|
chunk := data[beg+i : end]
|
||||||
|
|
||||||
// check for a nested list item
|
// check for a nested list item
|
||||||
if (blockUliPrefix(chunk) > 0 && !isHRule(chunk)) || blockOliPrefix(chunk) > 0 {
|
if (parser.blockUliPrefix(chunk) > 0 && !parser.isHRule(chunk)) ||
|
||||||
|
parser.blockOliPrefix(chunk) > 0 {
|
||||||
if containsBlankLine {
|
if containsBlankLine {
|
||||||
containsBlock = true
|
containsBlock = true
|
||||||
}
|
}
|
||||||
|
@ -1005,7 +1008,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// how about a nested prefix header?
|
// how about a nested prefix header?
|
||||||
if isPrefixHeader(rndr, chunk) {
|
if parser.isPrefixHeader(chunk) {
|
||||||
// only nest headers that are indented
|
// only nest headers that are indented
|
||||||
if containsBlankLine && i < 4 && data[beg] != '\t' {
|
if containsBlankLine && i < 4 && data[beg] != '\t' {
|
||||||
*flags |= LIST_ITEM_END_OF_LIST
|
*flags |= LIST_ITEM_END_OF_LIST
|
||||||
|
@ -1042,31 +1045,31 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
||||||
if *flags&LIST_ITEM_CONTAINS_BLOCK != 0 {
|
if *flags&LIST_ITEM_CONTAINS_BLOCK != 0 {
|
||||||
// intermediate render of block li
|
// intermediate render of block li
|
||||||
if sublist > 0 && sublist < len(workbytes) {
|
if sublist > 0 && sublist < len(workbytes) {
|
||||||
parseBlock(&inter, rndr, workbytes[:sublist])
|
parser.parseBlock(&inter, workbytes[:sublist])
|
||||||
parseBlock(&inter, rndr, workbytes[sublist:])
|
parser.parseBlock(&inter, workbytes[sublist:])
|
||||||
} else {
|
} else {
|
||||||
parseBlock(&inter, rndr, workbytes)
|
parser.parseBlock(&inter, workbytes)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// intermediate render of inline li
|
// intermediate render of inline li
|
||||||
if sublist > 0 && sublist < len(workbytes) {
|
if sublist > 0 && sublist < len(workbytes) {
|
||||||
parseInline(&inter, rndr, workbytes[:sublist])
|
parser.parseInline(&inter, workbytes[:sublist])
|
||||||
parseBlock(&inter, rndr, workbytes[sublist:])
|
parser.parseBlock(&inter, workbytes[sublist:])
|
||||||
} else {
|
} else {
|
||||||
parseInline(&inter, rndr, workbytes)
|
parser.parseInline(&inter, workbytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// render li itself
|
// render li itself
|
||||||
if rndr.mk.ListItem != nil {
|
if parser.r.ListItem != nil {
|
||||||
rndr.mk.ListItem(out, inter.Bytes(), *flags, rndr.mk.Opaque)
|
parser.r.ListItem(out, inter.Bytes(), *flags, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return beg
|
return beg
|
||||||
}
|
}
|
||||||
|
|
||||||
// render a single paragraph that has already been parsed out
|
// render a single paragraph that has already been parsed out
|
||||||
func renderParagraph(out *bytes.Buffer, rndr *render, data []byte) {
|
func (parser *Parser) renderParagraph(out *bytes.Buffer, data []byte) {
|
||||||
// trim leading whitespace
|
// trim leading whitespace
|
||||||
beg := 0
|
beg := 0
|
||||||
for beg < len(data) && isspace(data[beg]) {
|
for beg < len(data) && isspace(data[beg]) {
|
||||||
|
@ -1078,18 +1081,18 @@ func renderParagraph(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
for end > beg && isspace(data[end-1]) {
|
for end > beg && isspace(data[end-1]) {
|
||||||
end--
|
end--
|
||||||
}
|
}
|
||||||
if end == beg || rndr.mk.Paragraph == nil {
|
if end == beg || parser.r.Paragraph == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
work := func() bool {
|
work := func() bool {
|
||||||
parseInline(out, rndr, data[beg:end])
|
parser.parseInline(out, data[beg:end])
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
rndr.mk.Paragraph(out, work, rndr.mk.Opaque)
|
parser.r.Paragraph(out, work, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
|
func (parser *Parser) blockParagraph(out *bytes.Buffer, data []byte) int {
|
||||||
// prev: index of 1st char of previous line
|
// prev: index of 1st char of previous line
|
||||||
// line: index of 1st char of current line
|
// line: index of 1st char of current line
|
||||||
// i: index of cursor/end of current line
|
// i: index of cursor/end of current line
|
||||||
|
@ -1103,16 +1106,16 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
line = i
|
line = i
|
||||||
|
|
||||||
// did we find a blank line marking the end of the paragraph?
|
// did we find a blank line marking the end of the paragraph?
|
||||||
if n := isEmpty(current); n > 0 {
|
if n := parser.isEmpty(current); n > 0 {
|
||||||
renderParagraph(out, rndr, data[:i])
|
parser.renderParagraph(out, data[:i])
|
||||||
return i + n
|
return i + n
|
||||||
}
|
}
|
||||||
|
|
||||||
// an underline under some text marks a header, so our paragraph ended on prev line
|
// an underline under some text marks a header, so our paragraph ended on prev line
|
||||||
if i > 0 && rndr.mk.Header != nil {
|
if i > 0 && parser.r.Header != nil {
|
||||||
if level := isUnderlinedHeader(current); level > 0 {
|
if level := parser.isUnderlinedHeader(current); level > 0 {
|
||||||
// render the paragraph
|
// render the paragraph
|
||||||
renderParagraph(out, rndr, data[:prev])
|
parser.renderParagraph(out, data[:prev])
|
||||||
|
|
||||||
// ignore leading and trailing whitespace
|
// ignore leading and trailing whitespace
|
||||||
eol := i - 1
|
eol := i - 1
|
||||||
|
@ -1125,13 +1128,13 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
|
|
||||||
// render the header
|
// render the header
|
||||||
// this ugly double closure avoids forcing variables onto the heap
|
// this ugly double closure avoids forcing variables onto the heap
|
||||||
work := func(o *bytes.Buffer, r *render, d []byte) func() bool {
|
work := func(o *bytes.Buffer, p *Parser, d []byte) func() bool {
|
||||||
return func() bool {
|
return func() bool {
|
||||||
parseInline(o, r, d)
|
p.parseInline(o, d)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}(out, rndr, data[prev:eol])
|
}(out, parser, data[prev:eol])
|
||||||
rndr.mk.Header(out, work, level, rndr.mk.Opaque)
|
parser.r.Header(out, work, level, parser.r.Opaque)
|
||||||
|
|
||||||
// find the end of the underline
|
// find the end of the underline
|
||||||
for ; i < len(data) && data[i] != '\n'; i++ {
|
for ; i < len(data) && data[i] != '\n'; i++ {
|
||||||
|
@ -1141,17 +1144,17 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the next line starts a block of HTML, then the paragraph ends here
|
// if the next line starts a block of HTML, then the paragraph ends here
|
||||||
if rndr.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
|
if parser.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
|
||||||
if data[i] == '<' && rndr.mk.BlockHtml != nil && blockHtml(out, rndr, current, false) > 0 {
|
if data[i] == '<' && parser.r.BlockHtml != nil && parser.blockHtml(out, current, false) > 0 {
|
||||||
// rewind to before the HTML block
|
// rewind to before the HTML block
|
||||||
renderParagraph(out, rndr, data[:i])
|
parser.renderParagraph(out, data[:i])
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's a prefixed header or a horizontal rule after this, paragraph is over
|
// if there's a prefixed header or a horizontal rule after this, paragraph is over
|
||||||
if isPrefixHeader(rndr, current) || isHRule(current) {
|
if parser.isPrefixHeader(current) || parser.isHRule(current) {
|
||||||
renderParagraph(out, rndr, data[:i])
|
parser.renderParagraph(out, data[:i])
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,6 +1165,6 @@ func blockParagraph(out *bytes.Buffer, rndr *render, data []byte) int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderParagraph(out, rndr, data[:i])
|
parser.renderParagraph(out, data[:i])
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
124
inline.go
124
inline.go
|
@ -22,22 +22,22 @@ import (
|
||||||
// data is the complete block being rendered
|
// data is the complete block being rendered
|
||||||
// offset is the number of valid chars before the current cursor
|
// offset is the number of valid chars before the current cursor
|
||||||
|
|
||||||
func parseInline(out *bytes.Buffer, rndr *render, data []byte) {
|
func (parser *Parser) parseInline(out *bytes.Buffer, data []byte) {
|
||||||
// this is called recursively: enforce a maximum depth
|
// this is called recursively: enforce a maximum depth
|
||||||
if rndr.nesting >= rndr.maxNesting {
|
if parser.nesting >= parser.maxNesting {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rndr.nesting++
|
parser.nesting++
|
||||||
|
|
||||||
i, end := 0, 0
|
i, end := 0, 0
|
||||||
for i < len(data) {
|
for i < len(data) {
|
||||||
// copy inactive chars into the output
|
// copy inactive chars into the output
|
||||||
for end < len(data) && rndr.inline[data[end]] == nil {
|
for end < len(data) && parser.inline[data[end]] == nil {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.NormalText != nil {
|
if parser.r.NormalText != nil {
|
||||||
rndr.mk.NormalText(out, data[i:end], rndr.mk.Opaque)
|
parser.r.NormalText(out, data[i:end], parser.r.Opaque)
|
||||||
} else {
|
} else {
|
||||||
out.Write(data[i:end])
|
out.Write(data[i:end])
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,8 @@ func parseInline(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
i = end
|
i = end
|
||||||
|
|
||||||
// call the trigger
|
// call the trigger
|
||||||
parser := rndr.inline[data[end]]
|
handler := parser.inline[data[end]]
|
||||||
if consumed := parser(out, rndr, data, i); consumed == 0 {
|
if consumed := handler(out, parser, data, i); consumed == 0 {
|
||||||
// no action from the callback; buffer the byte for later
|
// no action from the callback; buffer the byte for later
|
||||||
end = i + 1
|
end = i + 1
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,11 +59,11 @@ func parseInline(out *bytes.Buffer, rndr *render, data []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rndr.nesting--
|
parser.nesting--
|
||||||
}
|
}
|
||||||
|
|
||||||
// single and double emphasis parsing
|
// single and double emphasis parsing
|
||||||
func inlineEmphasis(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineEmphasis(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
c := data[0]
|
c := data[0]
|
||||||
ret := 0
|
ret := 0
|
||||||
|
@ -74,7 +74,7 @@ func inlineEmphasis(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
if c == '~' || isspace(data[1]) {
|
if c == '~' || isspace(data[1]) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if ret = inlineHelperEmph1(out, rndr, data[1:], c); ret == 0 {
|
if ret = inlineHelperEmph1(out, parser, data[1:], c); ret == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ func inlineEmphasis(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
if isspace(data[2]) {
|
if isspace(data[2]) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if ret = inlineHelperEmph2(out, rndr, data[2:], c); ret == 0 {
|
if ret = inlineHelperEmph2(out, parser, data[2:], c); ret == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ func inlineEmphasis(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
if c == '~' || isspace(data[3]) {
|
if c == '~' || isspace(data[3]) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if ret = inlineHelperEmph3(out, rndr, data, 3, c); ret == 0 {
|
if ret = inlineHelperEmph3(out, parser, data, 3, c); ret == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ func inlineEmphasis(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlineCodeSpan(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineCodeSpan(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
|
|
||||||
nb := 0
|
nb := 0
|
||||||
|
@ -143,10 +143,10 @@ func inlineCodeSpan(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
}
|
}
|
||||||
|
|
||||||
// render the code span
|
// render the code span
|
||||||
if rndr.mk.CodeSpan == nil {
|
if parser.r.CodeSpan == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if rndr.mk.CodeSpan(out, data[fBegin:fEnd], rndr.mk.Opaque) == 0 {
|
if parser.r.CodeSpan(out, data[fBegin:fEnd], parser.r.Opaque) == 0 {
|
||||||
end = 0
|
end = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ func inlineCodeSpan(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
|
|
||||||
// newline preceded by two spaces becomes <br>
|
// newline preceded by two spaces becomes <br>
|
||||||
// newline without two spaces works when EXTENSION_HARD_LINE_BREAK is enabled
|
// newline without two spaces works when EXTENSION_HARD_LINE_BREAK is enabled
|
||||||
func inlineLineBreak(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineLineBreak(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
// remove trailing spaces from out
|
// remove trailing spaces from out
|
||||||
outBytes := out.Bytes()
|
outBytes := out.Bytes()
|
||||||
end := len(outBytes)
|
end := len(outBytes)
|
||||||
|
@ -167,14 +167,14 @@ func inlineLineBreak(out *bytes.Buffer, rndr *render, data []byte, offset int) i
|
||||||
out.Truncate(eol)
|
out.Truncate(eol)
|
||||||
|
|
||||||
// should there be a hard line break here?
|
// should there be a hard line break here?
|
||||||
if rndr.flags&EXTENSION_HARD_LINE_BREAK == 0 && end-eol < 2 {
|
if parser.flags&EXTENSION_HARD_LINE_BREAK == 0 && end-eol < 2 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.LineBreak == nil {
|
if parser.r.LineBreak == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if rndr.mk.LineBreak(out, rndr.mk.Opaque) > 0 {
|
if parser.r.LineBreak(out, parser.r.Opaque) > 0 {
|
||||||
return 1
|
return 1
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
|
@ -184,9 +184,9 @@ func inlineLineBreak(out *bytes.Buffer, rndr *render, data []byte, offset int) i
|
||||||
}
|
}
|
||||||
|
|
||||||
// '[': parse a link or an image
|
// '[': parse a link or an image
|
||||||
func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineLink(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
// no links allowed inside other links
|
// no links allowed inside other links
|
||||||
if rndr.insideLink {
|
if parser.insideLink {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
textHasNl := false
|
textHasNl := false
|
||||||
|
|
||||||
// check whether the correct renderer exists
|
// check whether the correct renderer exists
|
||||||
if (isImg && rndr.mk.Image == nil) || (!isImg && rndr.mk.Link == nil) {
|
if (isImg && parser.r.Image == nil) || (!isImg && parser.r.Link == nil) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
|
|
||||||
// find the reference with matching id (ids are case-insensitive)
|
// find the reference with matching id (ids are case-insensitive)
|
||||||
key := string(bytes.ToLower(id))
|
key := string(bytes.ToLower(id))
|
||||||
lr, ok := rndr.refs[key]
|
lr, ok := parser.refs[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
|
|
||||||
// find the reference with matching id
|
// find the reference with matching id
|
||||||
key := string(bytes.ToLower(id))
|
key := string(bytes.ToLower(id))
|
||||||
lr, ok := rndr.refs[key]
|
lr, ok := parser.refs[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -416,10 +416,10 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
content.Write(data[1:txtE])
|
content.Write(data[1:txtE])
|
||||||
} else {
|
} else {
|
||||||
// links cannot contain other links, so turn off link parsing temporarily
|
// links cannot contain other links, so turn off link parsing temporarily
|
||||||
insideLink := rndr.insideLink
|
insideLink := parser.insideLink
|
||||||
rndr.insideLink = true
|
parser.insideLink = true
|
||||||
parseInline(&content, rndr, data[1:txtE])
|
parser.parseInline(&content, data[1:txtE])
|
||||||
rndr.insideLink = insideLink
|
parser.insideLink = insideLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,9 +439,9 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
out.Truncate(outSize - 1)
|
out.Truncate(outSize - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = rndr.mk.Image(out, uLink, title, content.Bytes(), rndr.mk.Opaque)
|
ret = parser.r.Image(out, uLink, title, content.Bytes(), parser.r.Opaque)
|
||||||
} else {
|
} else {
|
||||||
ret = rndr.mk.Link(out, uLink, title, content.Bytes(), rndr.mk.Opaque)
|
ret = parser.r.Link(out, uLink, title, content.Bytes(), parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret > 0 {
|
if ret > 0 {
|
||||||
|
@ -451,7 +451,7 @@ func inlineLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// '<' when tags or autolinks are allowed
|
// '<' when tags or autolinks are allowed
|
||||||
func inlineLAngle(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineLAngle(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
altype := LINK_TYPE_NOT_AUTOLINK
|
altype := LINK_TYPE_NOT_AUTOLINK
|
||||||
end := tagLength(data, &altype)
|
end := tagLength(data, &altype)
|
||||||
|
@ -459,12 +459,12 @@ func inlineLAngle(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
||||||
|
|
||||||
if end > 2 {
|
if end > 2 {
|
||||||
switch {
|
switch {
|
||||||
case rndr.mk.AutoLink != nil && altype != LINK_TYPE_NOT_AUTOLINK:
|
case parser.r.AutoLink != nil && altype != LINK_TYPE_NOT_AUTOLINK:
|
||||||
var uLink bytes.Buffer
|
var uLink bytes.Buffer
|
||||||
unescapeText(&uLink, data[1:end+1-2])
|
unescapeText(&uLink, data[1:end+1-2])
|
||||||
ret = rndr.mk.AutoLink(out, uLink.Bytes(), altype, rndr.mk.Opaque)
|
ret = parser.r.AutoLink(out, uLink.Bytes(), altype, parser.r.Opaque)
|
||||||
case rndr.mk.RawHtmlTag != nil:
|
case parser.r.RawHtmlTag != nil:
|
||||||
ret = rndr.mk.RawHtmlTag(out, data[:end], rndr.mk.Opaque)
|
ret = parser.r.RawHtmlTag(out, data[:end], parser.r.Opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +477,7 @@ func inlineLAngle(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
||||||
// '\\' backslash escape
|
// '\\' backslash escape
|
||||||
var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>")
|
var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>")
|
||||||
|
|
||||||
func inlineEscape(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineEscape(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
|
|
||||||
if len(data) > 1 {
|
if len(data) > 1 {
|
||||||
|
@ -485,8 +485,8 @@ func inlineEscape(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.NormalText != nil {
|
if parser.r.NormalText != nil {
|
||||||
rndr.mk.NormalText(out, data[1:2], rndr.mk.Opaque)
|
parser.r.NormalText(out, data[1:2], parser.r.Opaque)
|
||||||
} else {
|
} else {
|
||||||
out.WriteByte(data[1])
|
out.WriteByte(data[1])
|
||||||
}
|
}
|
||||||
|
@ -518,7 +518,7 @@ func unescapeText(ob *bytes.Buffer, src []byte) {
|
||||||
|
|
||||||
// '&' escaped when it doesn't belong to an entity
|
// '&' escaped when it doesn't belong to an entity
|
||||||
// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+;
|
// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+;
|
||||||
func inlineEntity(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineEntity(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
|
|
||||||
end := 1
|
end := 1
|
||||||
|
@ -537,8 +537,8 @@ func inlineEntity(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
||||||
return 0 // lone '&'
|
return 0 // lone '&'
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.Entity != nil {
|
if parser.r.Entity != nil {
|
||||||
rndr.mk.Entity(out, data[:end], rndr.mk.Opaque)
|
parser.r.Entity(out, data[:end], parser.r.Opaque)
|
||||||
} else {
|
} else {
|
||||||
out.Write(data[:end])
|
out.Write(data[:end])
|
||||||
}
|
}
|
||||||
|
@ -546,9 +546,9 @@ func inlineEntity(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
||||||
return end
|
return end
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlineAutoLink(out *bytes.Buffer, rndr *render, data []byte, offset int) int {
|
func inlineAutoLink(out *bytes.Buffer, parser *Parser, data []byte, offset int) int {
|
||||||
// quick check to rule out most false hits on ':'
|
// quick check to rule out most false hits on ':'
|
||||||
if rndr.insideLink || len(data) < offset+3 || data[offset+1] != '/' || data[offset+2] != '/' {
|
if parser.insideLink || len(data) < offset+3 || data[offset+1] != '/' || data[offset+2] != '/' {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,11 +642,11 @@ func inlineAutoLink(out *bytes.Buffer, rndr *render, data []byte, offset int) in
|
||||||
out.Truncate(len(out.Bytes()) - rewind)
|
out.Truncate(len(out.Bytes()) - rewind)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.mk.AutoLink != nil {
|
if parser.r.AutoLink != nil {
|
||||||
var uLink bytes.Buffer
|
var uLink bytes.Buffer
|
||||||
unescapeText(&uLink, data[:linkEnd])
|
unescapeText(&uLink, data[:linkEnd])
|
||||||
|
|
||||||
rndr.mk.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL, rndr.mk.Opaque)
|
parser.r.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkEnd - rewind
|
return linkEnd - rewind
|
||||||
|
@ -860,10 +860,10 @@ func inlineHelperFindEmphChar(data []byte, c byte) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlineHelperEmph1(out *bytes.Buffer, rndr *render, data []byte, c byte) int {
|
func inlineHelperEmph1(out *bytes.Buffer, parser *Parser, data []byte, c byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
if rndr.mk.Emphasis == nil {
|
if parser.r.Emphasis == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,15 +889,15 @@ func inlineHelperEmph1(out *bytes.Buffer, rndr *render, data []byte, c byte) int
|
||||||
|
|
||||||
if data[i] == c && !isspace(data[i-1]) {
|
if data[i] == c && !isspace(data[i-1]) {
|
||||||
|
|
||||||
if rndr.flags&EXTENSION_NO_INTRA_EMPHASIS != 0 {
|
if parser.flags&EXTENSION_NO_INTRA_EMPHASIS != 0 {
|
||||||
if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) {
|
if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
parseInline(&work, rndr, data[:i])
|
parser.parseInline(&work, data[:i])
|
||||||
r := rndr.mk.Emphasis(out, work.Bytes(), rndr.mk.Opaque)
|
r := parser.r.Emphasis(out, work.Bytes(), parser.r.Opaque)
|
||||||
if r > 0 {
|
if r > 0 {
|
||||||
return i + 1
|
return i + 1
|
||||||
} else {
|
} else {
|
||||||
|
@ -909,10 +909,10 @@ func inlineHelperEmph1(out *bytes.Buffer, rndr *render, data []byte, c byte) int
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlineHelperEmph2(out *bytes.Buffer, rndr *render, data []byte, c byte) int {
|
func inlineHelperEmph2(out *bytes.Buffer, parser *Parser, data []byte, c byte) int {
|
||||||
renderMethod := rndr.mk.DoubleEmphasis
|
renderMethod := parser.r.DoubleEmphasis
|
||||||
if c == '~' {
|
if c == '~' {
|
||||||
renderMethod = rndr.mk.StrikeThrough
|
renderMethod = parser.r.StrikeThrough
|
||||||
}
|
}
|
||||||
|
|
||||||
if renderMethod == nil {
|
if renderMethod == nil {
|
||||||
|
@ -930,8 +930,8 @@ func inlineHelperEmph2(out *bytes.Buffer, rndr *render, data []byte, c byte) int
|
||||||
|
|
||||||
if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) {
|
if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) {
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
parseInline(&work, rndr, data[:i])
|
parser.parseInline(&work, data[:i])
|
||||||
r := renderMethod(out, work.Bytes(), rndr.mk.Opaque)
|
r := renderMethod(out, work.Bytes(), parser.r.Opaque)
|
||||||
if r > 0 {
|
if r > 0 {
|
||||||
return i + 2
|
return i + 2
|
||||||
} else {
|
} else {
|
||||||
|
@ -943,7 +943,7 @@ func inlineHelperEmph2(out *bytes.Buffer, rndr *render, data []byte, c byte) int
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlineHelperEmph3(out *bytes.Buffer, rndr *render, data []byte, offset int, c byte) int {
|
func inlineHelperEmph3(out *bytes.Buffer, parser *Parser, data []byte, offset int, c byte) int {
|
||||||
i := 0
|
i := 0
|
||||||
origData := data
|
origData := data
|
||||||
data = data[offset:]
|
data = data[offset:]
|
||||||
|
@ -961,12 +961,12 @@ func inlineHelperEmph3(out *bytes.Buffer, rndr *render, data []byte, offset int,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case (i+2 < len(data) && data[i+1] == c && data[i+2] == c && rndr.mk.TripleEmphasis != nil):
|
case (i+2 < len(data) && data[i+1] == c && data[i+2] == c && parser.r.TripleEmphasis != nil):
|
||||||
// triple symbol found
|
// triple symbol found
|
||||||
var work bytes.Buffer
|
var work bytes.Buffer
|
||||||
|
|
||||||
parseInline(&work, rndr, data[:i])
|
parser.parseInline(&work, data[:i])
|
||||||
r := rndr.mk.TripleEmphasis(out, work.Bytes(), rndr.mk.Opaque)
|
r := parser.r.TripleEmphasis(out, work.Bytes(), parser.r.Opaque)
|
||||||
if r > 0 {
|
if r > 0 {
|
||||||
return i + 3
|
return i + 3
|
||||||
} else {
|
} else {
|
||||||
|
@ -974,7 +974,7 @@ func inlineHelperEmph3(out *bytes.Buffer, rndr *render, data []byte, offset int,
|
||||||
}
|
}
|
||||||
case (i+1 < len(data) && data[i+1] == c):
|
case (i+1 < len(data) && data[i+1] == c):
|
||||||
// double symbol found, hand over to emph1
|
// double symbol found, hand over to emph1
|
||||||
length = inlineHelperEmph1(out, rndr, origData[offset-2:], c)
|
length = inlineHelperEmph1(out, parser, origData[offset-2:], c)
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -982,7 +982,7 @@ func inlineHelperEmph3(out *bytes.Buffer, rndr *render, data []byte, offset int,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// single symbol found, hand over to emph2
|
// single symbol found, hand over to emph2
|
||||||
length = inlineHelperEmph2(out, rndr, origData[offset-1:], c)
|
length = inlineHelperEmph2(out, parser, origData[offset-1:], c)
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
|
|
78
markdown.go
78
markdown.go
|
@ -143,10 +143,10 @@ type Renderer struct {
|
||||||
Opaque interface{}
|
Opaque interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type inlineParser func(out *bytes.Buffer, rndr *render, data []byte, offset int) int
|
type inlineParser func(out *bytes.Buffer, parser *Parser, data []byte, offset int) int
|
||||||
|
|
||||||
type render struct {
|
type Parser struct {
|
||||||
mk *Renderer
|
r *Renderer
|
||||||
refs map[string]*reference
|
refs map[string]*reference
|
||||||
inline [256]inlineParser
|
inline [256]inlineParser
|
||||||
flags int
|
flags int
|
||||||
|
@ -206,40 +206,40 @@ func Markdown(input []byte, renderer *Renderer, extensions int) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill in the render structure
|
// fill in the render structure
|
||||||
rndr := new(render)
|
parser := new(Parser)
|
||||||
rndr.mk = renderer
|
parser.r = renderer
|
||||||
rndr.flags = extensions
|
parser.flags = extensions
|
||||||
rndr.refs = make(map[string]*reference)
|
parser.refs = make(map[string]*reference)
|
||||||
rndr.maxNesting = 16
|
parser.maxNesting = 16
|
||||||
rndr.insideLink = false
|
parser.insideLink = false
|
||||||
|
|
||||||
// register inline parsers
|
// register inline parsers
|
||||||
if rndr.mk.Emphasis != nil || rndr.mk.DoubleEmphasis != nil || rndr.mk.TripleEmphasis != nil {
|
if parser.r.Emphasis != nil || parser.r.DoubleEmphasis != nil || parser.r.TripleEmphasis != nil {
|
||||||
rndr.inline['*'] = inlineEmphasis
|
parser.inline['*'] = inlineEmphasis
|
||||||
rndr.inline['_'] = inlineEmphasis
|
parser.inline['_'] = inlineEmphasis
|
||||||
if extensions&EXTENSION_STRIKETHROUGH != 0 {
|
if extensions&EXTENSION_STRIKETHROUGH != 0 {
|
||||||
rndr.inline['~'] = inlineEmphasis
|
parser.inline['~'] = inlineEmphasis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rndr.mk.CodeSpan != nil {
|
if parser.r.CodeSpan != nil {
|
||||||
rndr.inline['`'] = inlineCodeSpan
|
parser.inline['`'] = inlineCodeSpan
|
||||||
}
|
}
|
||||||
if rndr.mk.LineBreak != nil {
|
if parser.r.LineBreak != nil {
|
||||||
rndr.inline['\n'] = inlineLineBreak
|
parser.inline['\n'] = inlineLineBreak
|
||||||
}
|
}
|
||||||
if rndr.mk.Image != nil || rndr.mk.Link != nil {
|
if parser.r.Image != nil || parser.r.Link != nil {
|
||||||
rndr.inline['['] = inlineLink
|
parser.inline['['] = inlineLink
|
||||||
}
|
}
|
||||||
rndr.inline['<'] = inlineLAngle
|
parser.inline['<'] = inlineLAngle
|
||||||
rndr.inline['\\'] = inlineEscape
|
parser.inline['\\'] = inlineEscape
|
||||||
rndr.inline['&'] = inlineEntity
|
parser.inline['&'] = inlineEntity
|
||||||
|
|
||||||
if extensions&EXTENSION_AUTOLINK != 0 {
|
if extensions&EXTENSION_AUTOLINK != 0 {
|
||||||
rndr.inline[':'] = inlineAutoLink
|
parser.inline[':'] = inlineAutoLink
|
||||||
}
|
}
|
||||||
|
|
||||||
first := firstPass(rndr, input)
|
first := firstPass(parser, input)
|
||||||
second := secondPass(rndr, first)
|
second := secondPass(parser, first)
|
||||||
|
|
||||||
return second
|
return second
|
||||||
}
|
}
|
||||||
|
@ -249,15 +249,15 @@ func Markdown(input []byte, renderer *Renderer, extensions int) []byte {
|
||||||
// - expand tabs
|
// - expand tabs
|
||||||
// - normalize newlines
|
// - normalize newlines
|
||||||
// - copy everything else
|
// - copy everything else
|
||||||
func firstPass(rndr *render, input []byte) []byte {
|
func firstPass(parser *Parser, input []byte) []byte {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
tabSize := TAB_SIZE_DEFAULT
|
tabSize := TAB_SIZE_DEFAULT
|
||||||
if rndr.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
if parser.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
||||||
tabSize = TAB_SIZE_EIGHT
|
tabSize = TAB_SIZE_EIGHT
|
||||||
}
|
}
|
||||||
beg, end := 0, 0
|
beg, end := 0, 0
|
||||||
for beg < len(input) { // iterate over lines
|
for beg < len(input) { // iterate over lines
|
||||||
if end = isReference(rndr, input[beg:]); end > 0 {
|
if end = isReference(parser, input[beg:]); end > 0 {
|
||||||
beg += end
|
beg += end
|
||||||
} else { // skip to the next line
|
} else { // skip to the next line
|
||||||
end = beg
|
end = beg
|
||||||
|
@ -267,7 +267,7 @@ func firstPass(rndr *render, input []byte) []byte {
|
||||||
|
|
||||||
// add the line body if present
|
// add the line body if present
|
||||||
if end > beg {
|
if end > beg {
|
||||||
if rndr.flags&EXTENSION_NO_EXPAND_TABS == 0 {
|
if parser.flags&EXTENSION_NO_EXPAND_TABS == 0 {
|
||||||
expandTabs(&out, input[beg:end], tabSize)
|
expandTabs(&out, input[beg:end], tabSize)
|
||||||
} else {
|
} else {
|
||||||
out.Write(input[beg:end])
|
out.Write(input[beg:end])
|
||||||
|
@ -289,19 +289,19 @@ func firstPass(rndr *render, input []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// second pass: actual rendering
|
// second pass: actual rendering
|
||||||
func secondPass(rndr *render, input []byte) []byte {
|
func secondPass(parser *Parser, input []byte) []byte {
|
||||||
var output bytes.Buffer
|
var output bytes.Buffer
|
||||||
if rndr.mk.DocumentHeader != nil {
|
if parser.r.DocumentHeader != nil {
|
||||||
rndr.mk.DocumentHeader(&output, rndr.mk.Opaque)
|
parser.r.DocumentHeader(&output, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBlock(&output, rndr, input)
|
parser.parseBlock(&output, input)
|
||||||
|
|
||||||
if rndr.mk.DocumentFooter != nil {
|
if parser.r.DocumentFooter != nil {
|
||||||
rndr.mk.DocumentFooter(&output, rndr.mk.Opaque)
|
parser.r.DocumentFooter(&output, parser.r.Opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rndr.nesting != 0 {
|
if parser.nesting != 0 {
|
||||||
panic("Nesting level did not end at zero")
|
panic("Nesting level did not end at zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ type reference struct {
|
||||||
// (in the render struct).
|
// (in the render struct).
|
||||||
// Returns the number of bytes to skip to move past it,
|
// Returns the number of bytes to skip to move past it,
|
||||||
// or zero if the first line is not a reference.
|
// or zero if the first line is not a reference.
|
||||||
func isReference(rndr *render, data []byte) int {
|
func isReference(parser *Parser, data []byte) int {
|
||||||
// up to 3 optional leading spaces
|
// up to 3 optional leading spaces
|
||||||
if len(data) < 4 {
|
if len(data) < 4 {
|
||||||
return 0
|
return 0
|
||||||
|
@ -451,13 +451,13 @@ func isReference(rndr *render, data []byte) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// a valid ref has been found
|
// a valid ref has been found
|
||||||
if rndr == nil {
|
if parser == nil {
|
||||||
return lineEnd
|
return lineEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
// id matches are case-insensitive
|
// id matches are case-insensitive
|
||||||
id := string(bytes.ToLower(data[idOffset:idEnd]))
|
id := string(bytes.ToLower(data[idOffset:idEnd]))
|
||||||
rndr.refs[id] = &reference{
|
parser.refs[id] = &reference{
|
||||||
link: data[linkOffset:linkEnd],
|
link: data[linkOffset:linkEnd],
|
||||||
title: data[titleOffset:titleEnd],
|
title: data[titleOffset:titleEnd],
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user