1
0
mirror of https://github.com/danog/blackfriday.git synced 2024-11-30 04:29:13 +01:00

Merge pull request #284 from russross/fix-lint

Fix most of lint errors on v2
This commit is contained in:
Vytautas Šaltenis 2016-07-28 19:45:39 +03:00 committed by GitHub
commit ca4bf013e8
9 changed files with 142 additions and 107 deletions

View File

@ -22,13 +22,13 @@ import (
)
const (
Entity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});"
Escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]"
charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});"
escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]"
)
var (
reBackslashOrAmp = regexp.MustCompile("[\\&]")
reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + Escapable + "|" + Entity)
reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity)
reTrailingWhitespace = regexp.MustCompile("(\n *)+$")
)
@ -279,9 +279,8 @@ func (p *parser) isUnderlinedHeader(data []byte) int {
i = skipChar(data, i, ' ')
if data[i] == '\n' {
return 1
} else {
return 0
}
return 0
}
// test of level 2 header
@ -290,9 +289,8 @@ func (p *parser) isUnderlinedHeader(data []byte) int {
i = skipChar(data, i, ' ')
if data[i] == '\n' {
return 2
} else {
return 0
}
return 0
}
return 0
@ -414,20 +412,20 @@ func (p *parser) html(data []byte, doRender bool) int {
for end > 0 && data[end-1] == '\n' {
end--
}
finalizeHtmlBlock(p.addBlock(HTMLBlock, data[:end]))
finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
}
return i
}
func finalizeHtmlBlock(block *Node) {
func finalizeHTMLBlock(block *Node) {
block.Literal = reTrailingWhitespace.ReplaceAll(block.content, []byte{})
block.content = []byte{}
}
// HTML comment, lax form
func (p *parser) htmlComment(data []byte, doRender bool) int {
i := p.inlineHtmlComment(data)
i := p.inlineHTMLComment(data)
// needs to end with a blank line
if j := p.isEmpty(data[i:]); j > 0 {
size := i + j
@ -438,7 +436,7 @@ func (p *parser) htmlComment(data []byte, doRender bool) int {
end--
}
block := p.addBlock(HTMLBlock, data[:end])
finalizeHtmlBlock(block)
finalizeHTMLBlock(block)
}
return size
}
@ -470,7 +468,7 @@ func (p *parser) htmlHr(data []byte, doRender bool) int {
for end > 0 && data[end-1] == '\n' {
end--
}
finalizeHtmlBlock(p.addBlock(HTMLBlock, data[:end]))
finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
}
return size
}
@ -729,9 +727,8 @@ func unescapeChar(str []byte) []byte {
func unescapeString(str []byte) []byte {
if reBackslashOrAmp.Match(str) {
return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar)
} else {
return str
}
return str
}
func finalizeCodeBlock(block *Node) {

View File

@ -1572,7 +1572,7 @@ func TestCompletePage(t *testing.T) {
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta name="GENERATOR" content="Blackfriday Markdown Processor v1.4" />
<meta name="GENERATOR" content="Blackfriday Markdown Processor v2.0" />
<meta charset="utf-8" />
</head>
<body>

View File

@ -54,7 +54,7 @@ func doTests(t *testing.T, tests []string) {
doTestsParam(t, tests, TestParams{
Options: DefaultOptions,
HTMLRendererParameters: HTMLRendererParameters{
Flags: CommonHtmlFlags,
Flags: CommonHTMLFlags,
Extensions: CommonExtensions,
},
})
@ -106,7 +106,7 @@ func doLinkTestsInline(t *testing.T, tests []string) {
HTMLRendererParameters: params,
})
doTestsInlineParam(t, transformTests, TestParams{
HTMLFlags: CommonHtmlFlags,
HTMLFlags: CommonHTMLFlags,
HTMLRendererParameters: params,
})
}

24
html.go
View File

@ -24,6 +24,7 @@ import (
"strings"
)
// HTMLFlags control optional behavior of HTML renderer.
type HTMLFlags int
// HTML renderer configuration options.
@ -63,6 +64,8 @@ var (
htmlTagRe = regexp.MustCompile("(?i)^" + HTMLTag)
)
// HTMLRendererParameters is a collection of supplementary parameters tweaking
// the behavior of various parts of HTML renderer.
type HTMLRendererParameters struct {
// Prepend this text to each relative URL.
AbsolutePrefix string
@ -126,8 +129,8 @@ func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer {
}
}
func isHtmlTag(tag []byte, tagname string) bool {
found, _ := findHtmlTagPos(tag, tagname)
func isHTMLTag(tag []byte, tagname string) bool {
found, _ := findHTMLTagPos(tag, tagname)
return found
}
@ -154,7 +157,7 @@ func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
return start
}
func findHtmlTagPos(tag []byte, tagname string) (bool, int) {
func findHTMLTagPos(tag []byte, tagname string) (bool, int) {
i := 0
if i < len(tag) && tag[0] != '<' {
return false, -1
@ -384,6 +387,16 @@ func (r *HTMLRenderer) cr(w io.Writer) {
}
}
// RenderNode is a default renderer of a single node of a syntax tree. For
// block nodes it will be called twice: first time with entering=true, second
// time with entering=false, so that it could know when it's working on an open
// tag and when on close. It writes the result to w.
//
// The return value is a way to tell the calling walker to adjust its walk
// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
// can ask the walker to skip a subtree of this node by returning SkipChildren.
// The typical behavior is to return GoToNext, which asks for the usual
// traversal to the next node.
func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
attrs := []string{}
switch node.Type {
@ -420,7 +433,7 @@ func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkSt
if r.Flags&SkipHTML != 0 {
break
}
if r.Flags&SkipStyle != 0 && isHtmlTag(node.Literal, "style") {
if r.Flags&SkipStyle != 0 && isHTMLTag(node.Literal, "style") {
break
}
//if options.safe {
@ -714,7 +727,7 @@ func (r *HTMLRenderer) writeDocumentHeader(w *bytes.Buffer, sr *SPRenderer) {
}
w.WriteString("</title>\n")
w.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
w.WriteString(VERSION)
w.WriteString(Version)
w.WriteString("\"")
w.WriteString(ending)
w.WriteString(">\n")
@ -739,6 +752,7 @@ func (r *HTMLRenderer) writeDocumentFooter(w *bytes.Buffer) {
w.WriteString("\n</body>\n</html>\n")
}
// Render walks the specified syntax (sub)tree and returns a HTML document.
func (r *HTMLRenderer) Render(ast *Node) []byte {
//println("render_Blackfriday")
//dump(ast)

View File

@ -266,13 +266,13 @@ func link(p *parser, data []byte, offset int) int {
// ![alt] == image
case offset >= 0 && data[offset] == '!':
t = linkImg
offset += 1
offset++
// ^[text] == inline footnote
// [^refId] == deferred footnote
case p.flags&Footnotes != 0:
if offset >= 0 && data[offset] == '^' {
t = linkInlineFootnote
offset += 1
offset++
} else if len(data)-1 > offset && data[offset+1] == '^' {
t = linkDeferredFootnote
}
@ -285,7 +285,7 @@ func link(p *parser, data []byte, offset int) int {
var (
i = 1
noteId int
noteID int
title, link, altContent []byte
textHasNl = false
)
@ -501,7 +501,7 @@ func link(p *parser, data []byte, offset int) int {
if t == linkInlineFootnote {
// create a new reference
noteId = len(p.notes) + 1
noteID = len(p.notes) + 1
var fragment []byte
if len(id) > 0 {
@ -512,11 +512,11 @@ func link(p *parser, data []byte, offset int) int {
}
copy(fragment, slugify(id))
} else {
fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteId))...)
fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteID))...)
}
ref := &reference{
noteId: noteId,
noteID: noteID,
hasBlock: false,
link: fragment,
title: id,
@ -534,7 +534,7 @@ func link(p *parser, data []byte, offset int) int {
}
if t == linkDeferredFootnote {
lr.noteId = len(p.notes) + 1
lr.noteID = len(p.notes) + 1
p.notes = append(p.notes, lr)
}
@ -542,7 +542,7 @@ func link(p *parser, data []byte, offset int) int {
link = lr.link
// if inline footnote, title == footnote contents
title = lr.title
noteId = lr.noteId
noteID = lr.noteID
}
// rewind the whitespace
@ -590,13 +590,13 @@ func link(p *parser, data []byte, offset int) int {
linkNode.Title = title
p.currBlock.appendChild(linkNode)
linkNode.appendChild(text(data[1:txtE]))
i += 1
i++
case linkInlineFootnote, linkDeferredFootnote:
linkNode := NewNode(Link)
linkNode.Destination = link
linkNode.Title = title
linkNode.NoteID = noteId
linkNode.NoteID = noteID
p.currBlock.appendChild(linkNode)
if t == linkInlineFootnote {
i++
@ -609,7 +609,7 @@ func link(p *parser, data []byte, offset int) int {
return i
}
func (p *parser) inlineHtmlComment(data []byte) int {
func (p *parser) inlineHTMLComment(data []byte) int {
if len(data) < 5 {
return 0
}
@ -643,7 +643,7 @@ func leftAngle(p *parser, data []byte, offset int) int {
data = data[offset:]
altype := LinkTypeNotAutolink
end := tagLength(data, &altype)
if size := p.inlineHtmlComment(data); size > 0 {
if size := p.inlineHTMLComment(data); size > 0 {
end = size
}
if end > 2 {
@ -1026,9 +1026,8 @@ func isMailtoAutoLink(data []byte) int {
case '>':
if nb == 1 {
return i + 1
} else {
return 0
}
return 0
default:
return 0
}
@ -1091,9 +1090,8 @@ func helperFindEmphChar(data []byte, c byte) int {
if data[i] != '[' && data[i] != '(' { // not a link
if tmpI > 0 {
return tmpI
} else {
continue
}
continue
}
cc := data[i]
i++
@ -1218,17 +1216,15 @@ func helperTripleEmphasis(p *parser, data []byte, offset int, c byte) int {
length = helperEmphasis(p, origData[offset-2:], c)
if length == 0 {
return 0
} else {
return length - 2
}
return length - 2
default:
// single symbol found, hand over to emph2
length = helperDoubleEmphasis(p, origData[offset-1:], c)
if length == 0 {
return 0
} else {
return length - 1
}
return length - 1
}
}
return 0

View File

@ -311,7 +311,7 @@ func (r *Latex) DocumentHeader() {
r.w.WriteString(" pdfstartview=FitH,%\n")
r.w.WriteString(" breaklinks=true,%\n")
r.w.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
r.w.WriteString(VERSION)
r.w.WriteString(Version)
r.w.WriteString("}}\n")
r.w.WriteString("\n")
r.w.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")

View File

@ -13,7 +13,7 @@
//
//
// Blackfriday markdown processor.
// Package blackfriday is a markdown processor.
//
// Translates plain text with simple formatting rules into HTML or LaTeX.
package blackfriday
@ -26,8 +26,11 @@ import (
"unicode/utf8"
)
const VERSION = "1.4"
// Version string of the package.
const Version = "2.0"
// Extensions is a bitwise or'ed collection of enabled Blackfriday's
// extensions.
type Extensions int
// These are the supported markdown parsing extensions.
@ -58,7 +61,7 @@ const (
TOC // Generate a table of contents
OmitContents // Skip the main contents (for a standalone table of contents)
CommonHtmlFlags HTMLFlags = UseXHTML
CommonHTMLFlags HTMLFlags = UseXHTML
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
Autolink | Strikethrough | SpaceHeaders | HeaderIDs |
@ -66,10 +69,13 @@ const (
SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
)
// DefaultOptions is a convenience variable with all the options that are
// enabled by default.
var DefaultOptions = Options{
Extensions: CommonExtensions,
}
// TODO: this should probably be unexported. Or moved to node.go
type LinkType int
// These are the possible flag values for the link renderer.
@ -81,6 +87,7 @@ const (
LinkTypeEmail
)
// ListType contains bitwise or'ed flags for list and list item objects.
type ListType int
// These are the possible flag values for the ListItem renderer.
@ -96,6 +103,7 @@ const (
ListItemEndOfList
)
// CellAlignFlags holds a type of alignment in a table cell.
type CellAlignFlags int
// These are the possible flag values for the table cell renderer.
@ -213,7 +221,7 @@ func (p *parser) getRef(refid string) (ref *reference, found bool) {
return &reference{
link: []byte(r.Link),
title: []byte(r.Title),
noteId: 0,
noteID: 0,
hasBlock: false,
text: []byte(r.Text)}, true
}
@ -312,9 +320,8 @@ func MarkdownBasic(input []byte) []byte {
return Markdown(input, renderer, Options{})
}
// Call Markdown with most useful extensions enabled
// MarkdownCommon is a convenience function for simple rendering.
// It processes markdown input with common extensions enabled, including:
// MarkdownCommon is a convenience function for simple rendering. It calls
// Markdown with most useful extensions enabled, including:
//
// * Smartypants processing with smart fractions and LaTeX dashes
//
@ -334,7 +341,7 @@ func MarkdownBasic(input []byte) []byte {
func MarkdownCommon(input []byte) []byte {
// set up the HTML renderer
renderer := NewHTMLRenderer(HTMLRendererParameters{
Flags: CommonHtmlFlags,
Flags: CommonHTMLFlags,
Extensions: CommonExtensions,
})
return Markdown(input, renderer, DefaultOptions)
@ -354,6 +361,10 @@ func Markdown(input []byte, renderer Renderer, options Options) []byte {
return renderer.Render(Parse(input, options))
}
// Parse is an entry point to the parsing part of Blackfriday. It takes an
// input markdown document and produces a syntax tree for its contents. This
// tree can then be rendered with a default or custom renderer, or
// analyzed/transformed by the caller to whatever non-standard needs they have.
func Parse(input []byte, opts Options) *Node {
extensions := opts.Extensions
@ -488,7 +499,7 @@ func (p *parser) parseRefsToAST() {
return
}
p.tip = p.doc
finalizeHtmlBlock(p.addBlock(HTMLBlock, []byte(`<div class="footnotes">`)))
finalizeHTMLBlock(p.addBlock(HTMLBlock, []byte(`<div class="footnotes">`)))
p.addBlock(HorizontalRule, nil)
block := p.addBlock(List, nil)
block.ListFlags = ListTypeOrdered
@ -514,7 +525,7 @@ func (p *parser) parseRefsToAST() {
above := block.Parent
finalizeList(block)
p.tip = above
finalizeHtmlBlock(p.addBlock(HTMLBlock, []byte("</div>")))
finalizeHTMLBlock(p.addBlock(HTMLBlock, []byte("</div>")))
block.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Paragraph || node.Type == Header {
p.currBlock = node
@ -592,7 +603,7 @@ func secondPass(p *parser, input []byte) {
if p.flags&Footnotes != 0 && len(p.notes) > 0 {
flags := ListItemBeginningOfList
for i := 0; i < len(p.notes); i += 1 {
for i := 0; i < len(p.notes); i++ {
ref := p.notes[i]
if ref.hasBlock {
flags |= ListItemContainsBlock
@ -642,14 +653,14 @@ func secondPass(p *parser, input []byte) {
type reference struct {
link []byte
title []byte
noteId int // 0 if not a footnote ref
noteID int // 0 if not a footnote ref
hasBlock bool
text []byte
}
func (r *reference) String() string {
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteId: %d, hasBlock: %v}",
r.link, r.title, r.text, r.noteId, r.hasBlock)
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}",
r.link, r.title, r.text, r.noteID, r.hasBlock)
}
// Check whether or not data starts with a reference link.
@ -667,7 +678,7 @@ func isReference(p *parser, data []byte, tabSize int) int {
i++
}
noteId := 0
noteID := 0
// id part: anything but a newline between brackets
if data[i] != '[' {
@ -678,7 +689,7 @@ func isReference(p *parser, data []byte, tabSize int) int {
if i < len(data) && data[i] == '^' {
// we can set it to anything here because the proper noteIds will
// be assigned later during the second pass. It just has to be != 0
noteId = 1
noteID = 1
i++
}
}
@ -721,7 +732,7 @@ func isReference(p *parser, data []byte, tabSize int) int {
hasBlock bool
)
if p.flags&Footnotes != 0 && noteId != 0 {
if p.flags&Footnotes != 0 && noteID != 0 {
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
lineEnd = linkEnd
} else {
@ -734,11 +745,11 @@ func isReference(p *parser, data []byte, tabSize int) int {
// a valid ref has been found
ref := &reference{
noteId: noteId,
noteID: noteID,
hasBlock: hasBlock,
}
if noteId > 0 {
if noteID > 0 {
// reusing the link field for the id since footnotes don't have links
ref.link = data[idOffset:idEnd]
// if footnote, it's not really a title, it's the contained text

52
node.go
View File

@ -5,8 +5,12 @@ import (
"fmt"
)
// NodeType specifies a type of a single node of a syntax tree. Usually one
// node (and its type) corresponds to a single markdown feature, e.g. emphasis
// or code block.
type NodeType int
// Constants for identifying different types of nodes. See NodeType.
const (
Document NodeType = iota
BlockQuote
@ -65,6 +69,7 @@ func (t NodeType) String() string {
return nodeTypeNames[t]
}
// ListData contains fields relevant to a List node type.
type ListData struct {
ListFlags ListType
Tight bool // Skip <p>s around list item data if true
@ -73,12 +78,14 @@ type ListData struct {
RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
}
// LinkData contains fields relevant to a Link node type.
type LinkData struct {
Destination []byte
Title []byte
NoteID int
}
// CodeBlockData contains fields relevant to a CodeBlock node type.
type CodeBlockData struct {
IsFenced bool // Specifies whether it's a fenced code block or an indented one
Info []byte // This holds the info string
@ -87,11 +94,13 @@ type CodeBlockData struct {
FenceOffset int
}
// TableCellData contains fields relevant to a TableCell node type.
type TableCellData struct {
IsHeader bool // This tells if it's under the header row
Align CellAlignFlags // This holds the value for align attribute
}
// HeaderData contains fields relevant to a Header node type.
type HeaderData struct {
Level int // This holds the heading level number
HeaderID string // This might hold header ID, if present
@ -111,16 +120,17 @@ type Node struct {
Literal []byte // Text contents of the leaf nodes
HeaderData // Populated if Type == Header
ListData // Populated if Type == List
CodeBlockData // Populated if Type == CodeBlock
LinkData // Populated if Type == Link
TableCellData // Populated if Type == TableCell
HeaderData // Populated if Type is Header
ListData // Populated if Type is List
CodeBlockData // Populated if Type is CodeBlock
LinkData // Populated if Type is Link
TableCellData // Populated if Type is TableCell
content []byte // Markdown content of the block nodes
open bool // Specifies an open block node that has not been finished to process yet
}
// NewNode allocates a node of a specified type.
func NewNode(typ NodeType) *Node {
return &Node{
Type: typ,
@ -218,7 +228,6 @@ func (n *Node) isContainer() bool {
default:
return false
}
return false
}
func (n *Node) canContain(t NodeType) bool {
@ -246,9 +255,12 @@ func (n *Node) canContain(t NodeType) bool {
type WalkStatus int
const (
GoToNext WalkStatus = iota // The default traversal of every node.
SkipChildren // Skips all children of current node.
Terminate // Terminates the traversal.
// GoToNext is the default traversal of every node.
GoToNext WalkStatus = iota
// SkipChildren tells walker to skip all children of current node.
SkipChildren
// Terminate tells walker to terminate the traversal.
Terminate
)
// NodeVisitor is a callback to be called when traversing the syntax tree.
@ -256,8 +268,10 @@ const (
// first visited, then with entering=false after all the children are done.
type NodeVisitor func(node *Node, entering bool) WalkStatus
func (root *Node) Walk(visitor NodeVisitor) {
walker := NewNodeWalker(root)
// Walk is a convenience method that instantiates a walker and starts a
// traversal of subtree rooted at n.
func (n *Node) Walk(visitor NodeVisitor) {
walker := newNodeWalker(n)
node, entering := walker.next()
for node != nil {
status := visitor(node, entering)
@ -272,21 +286,21 @@ func (root *Node) Walk(visitor NodeVisitor) {
}
}
type NodeWalker struct {
type nodeWalker struct {
current *Node
root *Node
entering bool
}
func NewNodeWalker(root *Node) *NodeWalker {
return &NodeWalker{
func newNodeWalker(root *Node) *nodeWalker {
return &nodeWalker{
current: root,
root: nil,
entering: true,
}
}
func (nw *NodeWalker) next() (*Node, bool) {
func (nw *nodeWalker) next() (*Node, bool) {
if nw.current == nil {
return nil, false
}
@ -314,7 +328,7 @@ func (nw *NodeWalker) next() (*Node, bool) {
return nw.current, nw.entering
}
func (nw *NodeWalker) resumeAt(node *Node, entering bool) (*Node, bool) {
func (nw *nodeWalker) resumeAt(node *Node, entering bool) (*Node, bool) {
nw.current = node
nw.entering = entering
return nw.next()
@ -324,7 +338,7 @@ func dump(ast *Node) {
fmt.Println(dumpString(ast))
}
func dump_r(ast *Node, depth int) string {
func dumpR(ast *Node, depth int) string {
if ast == nil {
return ""
}
@ -335,11 +349,11 @@ func dump_r(ast *Node, depth int) string {
}
result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content)
for n := ast.FirstChild; n != nil; n = n.Next {
result += dump_r(n, depth+1)
result += dumpR(n, depth+1)
}
return result
}
func dumpString(ast *Node) string {
return dump_r(ast, 0)
return dumpR(ast, 0)
}

View File

@ -19,6 +19,7 @@ import (
"bytes"
)
// SPRenderer is a struct containing state of a Smartypants renderer.
type SPRenderer struct {
inSingleQuote bool
inDoubleQuote bool
@ -108,7 +109,7 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
return true
}
func (smrt *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 2 {
t1 := tolower(text[1])
@ -117,7 +118,7 @@ func (smrt *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, t
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote) {
return 1
}
}
@ -142,7 +143,7 @@ func (smrt *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, t
if len(text) > 1 {
nextChar = text[1]
}
if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) {
if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote) {
return 0
}
@ -150,7 +151,7 @@ func (smrt *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, t
return 0
}
func (smrt *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 3 {
t1 := tolower(text[1])
t2 := tolower(text[2])
@ -175,7 +176,7 @@ func (smrt *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text [
return 0
}
func (smrt *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 2 {
if text[1] == '-' {
out.WriteString("&mdash;")
@ -192,7 +193,7 @@ func (smrt *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []b
return 0
}
func (smrt *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
out.WriteString("&mdash;")
return 2
@ -206,13 +207,13 @@ func (smrt *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, tex
return 0
}
func (smrt *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
if bytes.HasPrefix(text, []byte("&quot;")) {
nextChar := byte(0)
if len(text) >= 7 {
nextChar = text[6]
}
if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote) {
return 5
}
}
@ -225,15 +226,15 @@ func (smrt *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, te
return 0
}
func (smrt *SPRenderer) smartAmp(out *bytes.Buffer, previousChar byte, text []byte) int {
return smrt.smartAmpVariant(out, previousChar, text, 'd')
func (r *SPRenderer) smartAmp(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartAmpVariant(out, previousChar, text, 'd')
}
func (smrt *SPRenderer) smartAmpAngledQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return smrt.smartAmpVariant(out, previousChar, text, 'a')
func (r *SPRenderer) smartAmpAngledQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartAmpVariant(out, previousChar, text, 'a')
}
func (smrt *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
out.WriteString("&hellip;")
return 2
@ -248,13 +249,13 @@ func (smrt *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text [
return 0
}
func (smrt *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int {
if len(text) >= 2 && text[1] == '`' {
nextChar := byte(0)
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote) {
return 1
}
}
@ -263,7 +264,7 @@ func (smrt *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text
return 0
}
func (smrt *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
// note: check for regular slash (/) or fraction slash (, 0x2044, or 0xe2 81 84 in utf-8)
@ -305,7 +306,7 @@ func (smrt *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte,
return 0
}
func (smrt *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
if text[0] == '1' && text[1] == '/' && text[2] == '2' {
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
@ -333,27 +334,27 @@ func (smrt *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text [
return 0
}
func (smrt *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
nextChar := byte(0)
if len(text) > 1 {
nextChar = text[1]
}
if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote) {
out.WriteString("&quot;")
}
return 0
}
func (smrt *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return smrt.smartDoubleQuoteVariant(out, previousChar, text, 'd')
func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartDoubleQuoteVariant(out, previousChar, text, 'd')
}
func (smrt *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return smrt.smartDoubleQuoteVariant(out, previousChar, text, 'a')
func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartDoubleQuoteVariant(out, previousChar, text, 'a')
}
func (smrt *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int {
func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int {
i := 0
for i < len(text) && text[i] != '>' {
@ -366,6 +367,7 @@ func (smrt *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, tex
type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
// NewSmartypantsRenderer constructs a Smartypants renderer object.
func NewSmartypantsRenderer(flags Extensions) *SPRenderer {
var r SPRenderer
if flags&SmartypantsAngledQuotes == 0 {
@ -398,13 +400,14 @@ func NewSmartypantsRenderer(flags Extensions) *SPRenderer {
return &r
}
func (sr *SPRenderer) Process(text []byte) []byte {
// Process is the entry point of the Smartypants renderer.
func (r *SPRenderer) Process(text []byte) []byte {
var buff bytes.Buffer
// first do normal entity escaping
text = esc(text)
mark := 0
for i := 0; i < len(text); i++ {
if action := sr.callbacks[text[i]]; action != nil {
if action := r.callbacks[text[i]]; action != nil {
if i > mark {
buff.Write(text[mark:i])
}