all repos — grayfriday @ 3af64a90ad74a0c4bd13fc63b41b298b8a09ac21

blackfriday fork with a few changes

fixed headers nested in lists, added prefix header unit tests
Russ Ross russ@dixie.edu
Mon, 27 Jun 2011 10:13:13 -0600
commit

3af64a90ad74a0c4bd13fc63b41b298b8a09ac21

parent

e22e43bf764e159538364a61a0a0d8c111599990

4 files changed, 205 insertions(+), 38 deletions(-)

jump to
M block.goblock.go

@@ -940,7 +940,7 @@ work.Write(data[beg:end])

beg = end // process the following lines - in_empty, has_inside_empty := false, false + contains_blank_line, contains_block := false, false for beg < len(data) { end++

@@ -950,7 +950,7 @@ }

// process an empty line if isEmpty(data[beg:end]) > 0 { - in_empty = true + contains_blank_line = true beg = end continue }

@@ -967,11 +967,12 @@ i = 1

pre = 8 } - // check for a new item chunk := data[beg+i : end] + + // check for a nested list item if (blockUliPrefix(chunk) > 0 && !isHRule(chunk)) || blockOliPrefix(chunk) > 0 { - if in_empty { - has_inside_empty = true + if contains_blank_line { + contains_block = true } if pre == orgpre { // the following item must have the same indentation

@@ -982,19 +983,29 @@ if sublist == 0 {

sublist = work.Len() } } else { - // only join indented stuff after empty lines - if in_empty && i < 4 && data[beg] != '\t' { - *flags |= LIST_ITEM_END_OF_LIST - break + // how about a nested prefix header? + if isPrefixHeader(rndr, chunk) { + // only nest headers that are indented + if contains_blank_line && i < 4 && data[beg] != '\t' { + *flags |= LIST_ITEM_END_OF_LIST + break + } + contains_block = true } else { - if in_empty { - work.WriteByte('\n') - has_inside_empty = true + // only join stuff after empty lines when indented + if contains_blank_line && i < 4 && data[beg] != '\t' { + *flags |= LIST_ITEM_END_OF_LIST + break + } else { + if contains_blank_line { + work.WriteByte('\n') + contains_block = true + } } } } - in_empty = false + contains_blank_line = false // add the line into the working buffer without prefix work.Write(data[beg+i : end])

@@ -1002,7 +1013,7 @@ beg = end

} // render li contents - if has_inside_empty { + if contains_block { *flags |= LIST_ITEM_CONTAINS_BLOCK }
A block_test.go

@@ -0,0 +1,162 @@

+// +// Black Friday Markdown Processor +// Originally based on http://github.com/tanoku/upskirt +// by Russ Ross <russ@russross.com> +// + +// +// Unit tests for block parsing +// + +package blackfriday + +import ( + "testing" +) + +func runMarkdownBlock(input string, extensions uint32) string { + html_flags := 0 + html_flags |= HTML_USE_XHTML + + renderer := HtmlRenderer(html_flags) + + return string(Markdown([]byte(input), renderer, extensions)) +} + +func doTestsBlock(t *testing.T, tests []string, extensions uint32) { + for i := 0; i+1 < len(tests); i += 2 { + input := tests[i] + expected := tests[i+1] + actual := runMarkdownBlock(input, extensions) + if actual != expected { + t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", + input, expected, actual) + } + } +} + +func TestPrefixHeaderNoExtensions(t *testing.T) { + var tests = []string{ + "# Header 1\n", + "<h1>Header 1</h1>\n", + + "## Header 2\n", + "<h2>Header 2</h2>\n", + + "### Header 3\n", + "<h3>Header 3</h3>\n", + + "#### Header 4\n", + "<h4>Header 4</h4>\n", + + "##### Header 5\n", + "<h5>Header 5</h5>\n", + + "###### Header 6\n", + "<h6>Header 6</h6>\n", + + "####### Header 7\n", + "<h6># Header 7</h6>\n", + + "#Header 1\n", + "<h1>Header 1</h1>\n", + + "##Header 2\n", + "<h2>Header 2</h2>\n", + + "###Header 3\n", + "<h3>Header 3</h3>\n", + + "####Header 4\n", + "<h4>Header 4</h4>\n", + + "#####Header 5\n", + "<h5>Header 5</h5>\n", + + "######Header 6\n", + "<h6>Header 6</h6>\n", + + "#######Header 7\n", + "<h6>#Header 7</h6>\n", + + "Hello\n# Header 1\nGoodbye\n", + "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n", + + "* List\n# Header\n* List\n", + "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n", + + "* List\n#Header\n* List\n", + "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n", + + "* List\n * Nested list\n # Nested header\n", + "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + + "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n", + + "* List\n * Sublist\n Not a header\n ------\n", + "<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n", + } + doTestsBlock(t, tests, 0) +} + +func TestPrefixHeaderSpaceExtension(t *testing.T) { + var tests = []string{ + "# Header 1\n", + "<h1>Header 1</h1>\n", + + "## Header 2\n", + "<h2>Header 2</h2>\n", + + "### Header 3\n", + "<h3>Header 3</h3>\n", + + "#### Header 4\n", + "<h4>Header 4</h4>\n", + + "##### Header 5\n", + "<h5>Header 5</h5>\n", + + "###### Header 6\n", + "<h6>Header 6</h6>\n", + + "####### Header 7\n", + "<p>####### Header 7</p>\n", + + "#Header 1\n", + "<p>#Header 1</p>\n", + + "##Header 2\n", + "<p>##Header 2</p>\n", + + "###Header 3\n", + "<p>###Header 3</p>\n", + + "####Header 4\n", + "<p>####Header 4</p>\n", + + "#####Header 5\n", + "<p>#####Header 5</p>\n", + + "######Header 6\n", + "<p>######Header 6</p>\n", + + "#######Header 7\n", + "<p>#######Header 7</p>\n", + + "Hello\n# Header 1\nGoodbye\n", + "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n", + + "* List\n# Header\n* List\n", + "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n", + + "* List\n#Header\n* List\n", + "<ul>\n<li>List\n#Header</li>\n<li>List</li>\n</ul>\n", + + "* List\n * Nested list\n # Nested header\n", + "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + + "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n", + + "* List\n * Sublist\n Not a header\n ------\n", + "<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n", + } + doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS) +}
M inline_test.goinline_test.go

@@ -14,7 +14,7 @@ import (

"testing" ) -func runMarkdown(input string) string { +func runMarkdownInline(input string) string { var extensions uint32 extensions |= EXTENSION_NO_INTRA_EMPHASIS extensions |= EXTENSION_TABLES

@@ -35,11 +35,11 @@

return string(Markdown([]byte(input), renderer, extensions)) } -func doTests(t *testing.T, tests []string) { +func doTestsInline(t *testing.T, tests []string) { for i := 0; i+1 < len(tests); i += 2 { input := tests[i] expected := tests[i+1] - actual := runMarkdown(input) + actual := runMarkdownInline(input) if actual != expected { t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", input, expected, actual)

@@ -97,7 +97,7 @@

"mix of *markers_\n", "<p>mix of *markers_</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestStrong(t *testing.T) {

@@ -150,7 +150,7 @@

"mix of **markers__\n", "<p>mix of **markers__</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestEmphasisMix(t *testing.T) {

@@ -179,7 +179,7 @@

"*improper **nesting* is** bad\n", "<p><em>improper **nesting</em> is** bad</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestStrikeThrough(t *testing.T) {

@@ -208,7 +208,7 @@

"odd ~~number\nof~~ markers~~ here\n", "<p>odd <del>number\nof</del> markers~~ here</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestCodeSpan(t *testing.T) {

@@ -246,7 +246,7 @@

"```multiple ticks `with` ticks inside```\n", "<p><code>multiple ticks `with` ticks inside</code></p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestLineBreak(t *testing.T) {

@@ -260,7 +260,7 @@

"this has an \nextra space\n", "<p>this has an<br />\nextra space</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestInlineLink(t *testing.T) {

@@ -355,7 +355,7 @@

"[link](/url/&query)\n", "<p><a href=\"/url/&amp;query\">link</a></p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestReferenceLink(t *testing.T) {

@@ -387,7 +387,7 @@

"[ref]\n [ref]: /url/ \"title\"\n", "<p><a href=\"/url/\" title=\"title\">ref</a></p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestTags(t *testing.T) {

@@ -404,7 +404,7 @@

"a <singleton /> tag\n", "<p>a <singleton /> tag</p>\n", } - doTests(t, tests) + doTestsInline(t, tests) } func TestAutoLink(t *testing.T) {

@@ -448,5 +448,5 @@ "even a > can be escaped <http://new.com?q=\\>&etc>\n",

"<p>even a &gt; can be escaped <a href=\"http://new.com?q=&gt;&amp;etc\">" + "http://new.com?q=&gt;&amp;etc</a></p>\n", } - doTests(t, tests) + doTestsInline(t, tests) }
M upskirtref_test.goupskirtref_test.go

@@ -13,21 +13,15 @@

import ( "io/ioutil" "path/filepath" - "strings" "testing" ) -func runReferenceMarkdown(input string) string { +func runMarkdownReference(input string) string { renderer := HtmlRenderer(0) return string(Markdown([]byte(input), renderer, 0)) } -// disregard dos vs. unix line endings differences -func normalizeEol(s string) string { - return strings.Replace(s, "\r\n", "\n", -1) -} - -func doFileTests(t *testing.T, files []string) { +func doTestsReference(t *testing.T, files []string) { for _, basename := range files { fn := filepath.Join("upskirtref", basename+".text") actualdata, err := ioutil.ReadFile(fn)

@@ -43,8 +37,8 @@ continue

} actual := string(actualdata) - actual = normalizeEol(string(runReferenceMarkdown(actual))) - expected := normalizeEol(string(expecteddata)) + actual = string(runMarkdownReference(actual)) + expected := string(expecteddata) if actual != expected { t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]", basename+".text", expected, actual)

@@ -77,5 +71,5 @@ "Strong and em together",

"Tabs", "Tidyness", } - doFileTests(t, files) + doTestsReference(t, files) }