diff --git a/block.go b/block.go index a5f59a1..d78147b 100644 --- a/block.go +++ b/block.go @@ -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) { diff --git a/block_test.go b/block_test.go index 7b52c3c..eb56665 100644 --- a/block_test.go +++ b/block_test.go @@ -1572,7 +1572,7 @@ func TestCompletePage(t *testing.T) {
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) } diff --git a/smartypants.go b/smartypants.go index 8f50fb5..3f3151c 100644 --- a/smartypants.go +++ b/smartypants.go @@ -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("—") @@ -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("—") 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(""")) { 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("…") 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(""") } 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]) }