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) { - + diff --git a/helpers_test.go b/helpers_test.go index 0320fe5..030caa5 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -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, }) } diff --git a/html.go b/html.go index d9de00f..740100c 100644 --- a/html.go +++ b/html.go @@ -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("\n") w.WriteString(" \n") @@ -739,6 +752,7 @@ func (r *HTMLRenderer) writeDocumentFooter(w *bytes.Buffer) { w.WriteString("\n\n\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) diff --git a/inline.go b/inline.go index 2428876..d051ead 100644 --- a/inline.go +++ b/inline.go @@ -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 diff --git a/latex.go b/latex.go index c0a1ad3..5b341ae 100644 --- a/latex.go +++ b/latex.go @@ -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") diff --git a/markdown.go b/markdown.go index a75dc38..2efab1e 100644 --- a/markdown.go +++ b/markdown.go @@ -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(`
`))) + finalizeHTMLBlock(p.addBlock(HTMLBlock, []byte(`
`))) 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("
"))) + finalizeHTMLBlock(p.addBlock(HTMLBlock, []byte("
"))) 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 diff --git a/node.go b/node.go index 58f399f..bcd2913 100644 --- a/node.go +++ b/node.go @@ -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

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]) }