Factor Smartypants to HTML Smartypants is HTML-specific. There is no need to run Smartypants from `Render()`. This simplifies extensions built upon the HTML renderer.
@@ -106,7 +106,7 @@ doTestsInlineParam(t, transformTests, TestParams{
HTMLRendererParameters: params, }) doTestsInlineParam(t, transformTests, TestParams{ - HTMLFlags: CommonHTMLFlags, + HTMLFlags: UseXHTML, HTMLRendererParameters: params, }) }
@@ -29,18 +29,23 @@ type HTMLFlags int
// HTML renderer configuration options. const ( - HTMLFlagsNone HTMLFlags = 0 - SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks - SkipStyle // Skip embedded <style> elements - SkipImages // Skip embedded images - SkipLinks // Skip all links - Safelink // Only link to trusted protocols - NofollowLinks // Only link with rel="nofollow" - NoreferrerLinks // Only link with rel="noreferrer" - HrefTargetBlank // Add a blank target - CompletePage // Generate a complete HTML page - UseXHTML // Generate XHTML output instead of HTML - FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source + HTMLFlagsNone HTMLFlags = 0 + SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks + SkipStyle // Skip embedded <style> elements + SkipImages // Skip embedded images + SkipLinks // Skip all links + Safelink // Only link to trusted protocols + NofollowLinks // Only link with rel="nofollow" + NoreferrerLinks // Only link with rel="noreferrer" + HrefTargetBlank // Add a blank target + CompletePage // Generate a complete HTML page + UseXHTML // Generate XHTML output instead of HTML + FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source + Smartypants // Enable smart punctuation substitutions + SmartypantsFractions // Enable smart fractions (with Smartypants) + SmartypantsDashes // Enable smart dashes (with Smartypants) + SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) + SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering TagName = "[A-Za-z][A-Za-z0-9-]*" AttributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"@@ -102,6 +107,8 @@ headerIDs map[string]int
lastOutputLen int disableTags int + + sr *SPRenderer } const (@@ -127,6 +134,8 @@ HTMLRendererParameters: params,
closeTag: closeTag, headerIDs: make(map[string]int), + + sr: NewSmartypantsRenderer(params.Flags), } }@@ -402,6 +411,10 @@ func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
attrs := []string{} switch node.Type { case Text: + node.Literal = esc(node.Literal) + if r.Flags&Smartypants != 0 { + node.Literal = r.sr.Process(node.Literal) + } r.out(w, node.Literal) break case Softbreak:@@ -705,7 +718,7 @@ }
return GoToNext } -func (r *HTMLRenderer) writeDocumentHeader(w *bytes.Buffer, sr *SPRenderer) { +func (r *HTMLRenderer) writeDocumentHeader(w *bytes.Buffer) { if r.Flags&CompletePage == 0 { return }@@ -721,8 +734,8 @@ w.WriteString("<html>\n")
} w.WriteString("<head>\n") w.WriteString(" <title>") - if r.Extensions&Smartypants != 0 { - w.Write(sr.Process([]byte(r.Title))) + if r.Flags&Smartypants != 0 { + w.Write(r.sr.Process([]byte(r.Title))) } else { w.Write(esc([]byte(r.Title))) }@@ -817,20 +830,8 @@ // Render walks the specified syntax (sub)tree and returns a HTML document.
func (r *HTMLRenderer) Render(ast *Node) []byte { //println("render_Blackfriday") //dump(ast) - // Run Smartypants if it's enabled or simply escape text if not - sr := NewSmartypantsRenderer(r.Extensions) - ast.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Text { - if r.Extensions&Smartypants != 0 { - node.Literal = sr.Process(node.Literal) - } else { - node.Literal = esc(node.Literal) - } - } - return GoToNext - }) var buff bytes.Buffer - r.writeDocumentHeader(&buff, sr) + r.writeDocumentHeader(&buff) if r.Extensions&TOC != 0 || r.Extensions&OmitContents != 0 { r.writeTOC(&buff, ast) if r.Extensions&OmitContents != 0 {
@@ -1012,11 +1012,7 @@
"blahblah\n<!--- foo -->\nrhubarb\n", "<p>blahblah\n<!--- foo -->\nrhubarb</p>\n", } - doTestsInlineParam(t, tests, TestParams{ - Options: Options{ - Extensions: Smartypants | SmartypantsDashes, - }, - }) + doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsDashes}) } func TestSmartDoubleQuotes(t *testing.T) {@@ -1028,11 +1024,7 @@ "<p>this “ single double</p>\n",
"two pair of \"some\" quoted \"text\".\n", "<p>two pair of “some” quoted “text”.</p>\n"} - doTestsInlineParam(t, tests, TestParams{ - Options: Options{ - Extensions: Smartypants, - }, - }) + doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants}) } func TestSmartAngledDoubleQuotes(t *testing.T) {@@ -1044,11 +1036,7 @@ "<p>this « single double</p>\n",
"two pair of \"some\" quoted \"text\".\n", "<p>two pair of «some» quoted «text».</p>\n"} - doTestsInlineParam(t, tests, TestParams{ - Options: Options{ - Extensions: Smartypants | SmartypantsAngledQuotes, - }, - }) + doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsAngledQuotes}) } func TestSmartFractions(t *testing.T) {@@ -1058,11 +1046,7 @@ "<p>½, ¼ and ¾; ¼th and ¾ths</p>\n",
"1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n", "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"} - doTestsInlineParam(t, tests, TestParams{ - Options: Options{ - Extensions: Smartypants, - }, - }) + doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants}) tests = []string{ "1/2, 2/3, 81/100 and 1000000/1048576.\n",@@ -1070,11 +1054,7 @@ "<p><sup>1</sup>⁄<sub>2</sub>, <sup>2</sup>⁄<sub>3</sub>, <sup>81</sup>⁄<sub>100</sub> and <sup>1000000</sup>⁄<sub>1048576</sub>.</p>\n",
"1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n", "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"} - doTestsInlineParam(t, tests, TestParams{ - Options: Options{ - Extensions: Smartypants | SmartypantsFractions, - }, - }) + doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsFractions}) } func TestDisableSmartDashes(t *testing.T) {@@ -1093,7 +1073,7 @@ "foo -- bar\n",
"<p>foo — bar</p>\n", "foo --- bar\n", "<p>foo —– bar</p>\n", - }, TestParams{Options: Options{Extensions: Smartypants | SmartypantsDashes}}) + }, TestParams{HTMLFlags: Smartypants | SmartypantsDashes}) doTestsInlineParam(t, []string{ "foo - bar\n", "<p>foo - bar</p>\n",@@ -1101,11 +1081,7 @@ "foo -- bar\n",
"<p>foo – bar</p>\n", "foo --- bar\n", "<p>foo — bar</p>\n", - }, TestParams{ - Options: Options{ - Extensions: Smartypants | SmartypantsLatexDashes | SmartypantsDashes, - }, - }) + }, TestParams{HTMLFlags: Smartypants | SmartypantsLatexDashes | SmartypantsDashes}) doTestsInlineParam(t, []string{ "foo - bar\n", "<p>foo - bar</p>\n",@@ -1113,9 +1089,7 @@ "foo -- bar\n",
"<p>foo -- bar</p>\n", "foo --- bar\n", "<p>foo --- bar</p>\n", - }, TestParams{ - Options: Options{Extensions: Smartypants | SmartypantsLatexDashes}, - }) + }, TestParams{HTMLFlags: Smartypants | SmartypantsLatexDashes}) } func TestSkipLinks(t *testing.T) {
@@ -36,37 +36,32 @@
// These are the supported markdown parsing extensions. // OR these values together to select multiple extensions. const ( - NoExtensions Extensions = 0 - NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words - Tables // Render tables - FencedCode // Render fenced code blocks - Autolink // Detect embedded URLs that are not explicitly marked - Strikethrough // Strikethrough text using ~~test~~ - LaxHTMLBlocks // Loosen up HTML block parsing rules - SpaceHeaders // Be strict about prefix header rules - HardLineBreak // Translate newlines into line breaks - TabSizeEight // Expand tabs to eight spaces instead of four - Footnotes // Pandoc-style footnotes - NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block - HeaderIDs // specify header IDs with {#id} - Titleblock // Titleblock ala pandoc - AutoHeaderIDs // Create the header ID from the text - BackslashLineBreak // Translate trailing backslashes into line breaks - DefinitionLists // Render definition lists - Smartypants // Enable smart punctuation substitutions - SmartypantsFractions // Enable smart fractions (with Smartypants) - SmartypantsDashes // Enable smart dashes (with Smartypants) - SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) - SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering - TOC // Generate a table of contents - OmitContents // Skip the main contents (for a standalone table of contents) + NoExtensions Extensions = 0 + NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words + Tables // Render tables + FencedCode // Render fenced code blocks + Autolink // Detect embedded URLs that are not explicitly marked + Strikethrough // Strikethrough text using ~~test~~ + LaxHTMLBlocks // Loosen up HTML block parsing rules + SpaceHeaders // Be strict about prefix header rules + HardLineBreak // Translate newlines into line breaks + TabSizeEight // Expand tabs to eight spaces instead of four + Footnotes // Pandoc-style footnotes + NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block + HeaderIDs // specify header IDs with {#id} + Titleblock // Titleblock ala pandoc + AutoHeaderIDs // Create the header ID from the text + BackslashLineBreak // Translate trailing backslashes into line breaks + DefinitionLists // Render definition lists + TOC // Generate a table of contents + OmitContents // Skip the main contents (for a standalone table of contents) - CommonHTMLFlags HTMLFlags = UseXHTML + CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | + SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | Autolink | Strikethrough | SpaceHeaders | HeaderIDs | - BackslashLineBreak | DefinitionLists | Smartypants | - SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes + BackslashLineBreak | DefinitionLists ) // DefaultOptions is a convenience variable with all the options that are
@@ -368,7 +368,7 @@
type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int // NewSmartypantsRenderer constructs a Smartypants renderer object. -func NewSmartypantsRenderer(flags Extensions) *SPRenderer { +func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer { var r SPRenderer if flags&SmartypantsAngledQuotes == 0 { r.callbacks['"'] = r.smartDoubleQuote@@ -403,8 +403,6 @@
// 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 := r.callbacks[text[i]]; action != nil {