Hello community, here is the log from the commit of package golang-github-russross-blackfriday for openSUSE:Factory checked in at 2016-01-21 23:44:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/golang-github-russross-blackfriday (Old) and /work/SRC/openSUSE:Factory/.golang-github-russross-blackfriday.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "golang-github-russross-blackfriday" Changes: -------- --- /work/SRC/openSUSE:Factory/golang-github-russross-blackfriday/golang-github-russross-blackfriday.changes 2015-08-01 11:37:44.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.golang-github-russross-blackfriday.new/golang-github-russross-blackfriday.changes 2016-01-22 01:10:07.000000000 +0100 @@ -1,0 +2,23 @@ +Sun Jan 17 09:55:17 UTC 2016 - i@marguerite.su + +- Update to version 1.4.0+git20151230.c8875c0: + + remove check that brace is > 0 + + Use more idiomatic form for set of strings + + Add a few missing HTML5 block tags + + Fix footnote following an exclamation point + + Add String() method to reference struct + + Fix nested footnotes + + Fix fenced code processing inside blockquotes + + Refix fenced code blocks w/o preceding blank lines + + Fix escaping asterisks within emphasis + + Fix footnote followed by a reference style link + + Fix bug parsing emphasis + + Add HTML_SMARTYPANTS_DASHES for togging smart dashes + + LaTex backend: add # to list of characters requiring + backslash-escaping + + Don't require the input to end with a newline + + Implement support for CDATA section + + Convert constant variables into consts + + Fix bug with gathering list item lines + +------------------------------------------------------------------- Old: ---- blackfriday-1.2.0+git20150720.8cec3a8.tar.xz New: ---- _servicedata blackfriday-1.4.0+git20151230.c8875c0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ golang-github-russross-blackfriday.spec ++++++ --- /var/tmp/diff_new_pack.4h9UD3/_old 2016-01-22 01:10:08.000000000 +0100 +++ /var/tmp/diff_new_pack.4h9UD3/_new 2016-01-22 01:10:08.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package golang-github-russross-blackfriday # -# Copyright (c) 2015 SUSE LLC +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,20 +17,21 @@ Name: golang-github-russross-blackfriday -Version: 1.2.0+git20150720.8cec3a8 +Version: 1.4.0+git20151230.c8875c0 Release: 0 Summary: Markdown processor implemented in Go License: BSD-2-Clause -Group: Development/Languages/Other -URL: https://github.com/russross/blackfriday +Group: Development/Languages/Golang +Url: https://github.com/russross/blackfriday Source: blackfriday-%{version}.tar.xz -BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: golang-packaging -BuildRequires: golang(github.com/shurcooL/sanitized_anchor_name) BuildRequires: findutils +BuildRequires: golang-packaging BuildRequires: sed +BuildRequires: xz +BuildRequires: golang(github.com/shurcooL/sanitized_anchor_name) Provides: go-blackfriday = %{version} Obsoletes: go-blackfriday < %{version} +BuildRoot: %{_tmppath}/%{name}-%{version}-build %{go_provides} %description @@ -38,29 +39,22 @@ HTML output is currently supported, along with Smartypants extensions. An experimental LaTeX output engine is also included. -%gosrc_package - %prep %setup -q -n blackfriday-%{version} %build -%goprep github.com/russross/blackfriday -%gobuild ... +%{goprep} github.com/russross/blackfriday +%{gobuild} ... %install -%goinstall -%gosrc +%{goinstall} +%{go_filelist} %check -%gotest github.com/russross/blackfriday +%{gotest} github.com/russross/blackfriday -%files +%files -f file.lst %defattr(-,root,root,-) %doc README.md -%{go_contribdir}/* - -%files source -%defattr(-,root,root,-) -%{go_contribsrcdir}/* %changelog ++++++ _service ++++++ --- /var/tmp/diff_new_pack.4h9UD3/_old 2016-01-22 01:10:08.000000000 +0100 +++ /var/tmp/diff_new_pack.4h9UD3/_new 2016-01-22 01:10:08.000000000 +0100 @@ -1,16 +1,17 @@ <services> - <service name="tar_scm" mode="localonly"> - <param name="url">http://github.com/russross/blackfriday</param> + <service name="tar_scm" mode="disabled"> + <param name="url">https://github.com/russross/blackfriday</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="versionformat">1.2.0+git%cd.%h</param> + <param name="versionformat">1.4.0+git%cd.%h</param> <param name="revision">master</param> + <param name="changesgenerate">enable</param> </service> - <service name="recompress" mode="localonly"> + <service name="recompress" mode="disabled"> <param name="file">blackfriday-*.tar</param> <param name="compression">xz</param> </service> - <service name="set_version" mode="localonly"> + <service name="set_version" mode="disabled"> <param name="basename">blackfriday</param> </service> </services> ++++++ _servicedata ++++++ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/russross/blackfriday</param> <param name="changesrevision">c8875c0ed47e07b063c3628e2e4d4c9826721795</param></service></servicedata>++++++ blackfriday-1.2.0+git20150720.8cec3a8.tar.xz -> blackfriday-1.4.0+git20151230.c8875c0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/.travis.yml new/blackfriday-1.4.0+git20151230.c8875c0/.travis.yml --- old/blackfriday-1.2.0+git20150720.8cec3a8/.travis.yml 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/.travis.yml 2016-01-17 10:55:17.000000000 +0100 @@ -8,6 +8,7 @@ - 1.2 - 1.3 - 1.4 + - 1.5 install: - go get -d -t -v ./... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/README.md new/blackfriday-1.4.0+git20151230.c8875c0/README.md --- old/blackfriday-1.2.0+git20150720.8cec3a8/README.md 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/README.md 2016-01-17 10:55:17.000000000 +0100 @@ -169,6 +169,25 @@ You can use 3 or more backticks to mark the beginning of the block, and the same number to mark the end of the block. +* **Definition lists**. A simple definition list is made of a single-line + term followed by a colon and the definition for that term. + + Cat + : Fluffy animal everyone likes + + Internet + : Vector of transmission for pictures of cats + + Terms must be separated from the previous definition by a blank line. + +* **Footnotes**. A marker in the text that will become a superscript number; + a footnote definition that will be placed in a list of footnotes at the + end of the document. A footnote looks like this: + + This is a footnote.[^1] + + [^1]: the footnote text. + * **Autolinking**. Blackfriday can find URLs that have not been explicitly marked as links and turn them into links. @@ -223,6 +242,8 @@ point. In particular, it does not do any inline escaping, so input that happens to look like LaTeX code will be passed through without modification. + +* [Md2Vim](https://github.com/FooSoft/md2vim): transforms markdown files into vimdoc format. Todo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/block.go new/blackfriday-1.4.0+git20151230.c8875c0/block.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/block.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/block.go 2016-01-17 10:55:17.000000000 +0100 @@ -320,6 +320,11 @@ return size } + // check for HTML CDATA + if size := p.htmlCDATA(out, data, doRender); size > 0 { + return size + } + // no special case recognized return 0 } @@ -397,40 +402,50 @@ return i } +func (p *parser) renderHTMLBlock(out *bytes.Buffer, data []byte, start int, doRender bool) int { + // html block needs to end with a blank line + if i := p.isEmpty(data[start:]); i > 0 { + size := start + i + if doRender { + // trim trailing newlines + end := size + for end > 0 && data[end-1] == '\n' { + end-- + } + p.r.BlockHtml(out, data[:end]) + } + return size + } + return 0 +} + // HTML comment, lax form func (p *parser) htmlComment(out *bytes.Buffer, data []byte, doRender bool) int { - if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { + i := p.inlineHTMLComment(out, data) + return p.renderHTMLBlock(out, data, i, doRender) +} + +// HTML CDATA section +func (p *parser) htmlCDATA(out *bytes.Buffer, data []byte, doRender bool) int { + const cdataTag = "<![cdata[" + const cdataTagLen = len(cdataTag) + if len(data) < cdataTagLen+1 { return 0 } - - i := 5 - + if !bytes.Equal(bytes.ToLower(data[:cdataTagLen]), []byte(cdataTag)) { + return 0 + } + i := cdataTagLen // scan for an end-of-comment marker, across lines if necessary - for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { + for i < len(data) && !(data[i-2] == ']' && data[i-1] == ']' && data[i] == '>') { i++ } i++ - // no end-of-comment marker if i >= len(data) { return 0 } - - // needs to end with a blank line - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim trailing newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - p.r.BlockHtml(out, data[:end]) - } - return size - } - - return 0 + return p.renderHTMLBlock(out, data, i, doRender) } // HR, which is the only self-closing block tag considered @@ -449,19 +464,7 @@ } if data[i] == '>' { - i++ - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - p.r.BlockHtml(out, data[:end]) - } - return size - } + return p.renderHTMLBlock(out, data, i+1, doRender) } return 0 @@ -473,7 +476,7 @@ i++ } key := string(data[:i]) - if blockTags[key] { + if _, ok := blockTags[key]; ok { return key, true } return "", false @@ -908,13 +911,35 @@ return 0 } +// blockquote ends with at least one blank line +// followed by something without a blockquote prefix +func (p *parser) terminateBlockquote(data []byte, beg, end int) bool { + if p.isEmpty(data[beg:]) <= 0 { + return false + } + if end >= len(data) { + return true + } + return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 +} + // parse a blockquote fragment func (p *parser) quote(out *bytes.Buffer, data []byte) int { var raw bytes.Buffer beg, end := 0, 0 for beg < len(data) { end = beg + // Step over whole lines, collecting them. While doing that, check for + // fenced code and if one's found, incorporate it altogether, + // irregardless of any contents inside it for data[end] != '\n' { + if p.flags&EXTENSION_FENCED_CODE != 0 { + if i := p.fencedCode(out, data[end:], false); i > 0 { + // -1 to compensate for the extra end++ after the loop: + end += i - 1 + break + } + } end++ } end++ @@ -922,11 +947,7 @@ if pre := p.quotePrefix(data[beg:]); pre > 0 { // skip the prefix beg += pre - } else if p.isEmpty(data[beg:]) > 0 && - (end >= len(data) || - (p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0)) { - // blockquote ends with at least one blank line - // followed by something without a blockquote prefix + } else if p.terminateBlockquote(data, beg, end) { break } @@ -1132,6 +1153,7 @@ // and move on to the next line if p.isEmpty(data[line:i]) > 0 { containsBlankLine = true + raw.Write(data[line:i]) line = i continue } @@ -1199,17 +1221,10 @@ // a blank line means this should be parsed as a block case containsBlankLine: - raw.WriteByte('\n') *flags |= LIST_ITEM_CONTAINS_BLOCK } - // if this line was preceeded by one or more blanks, - // re-introduce the blank into the buffer - if containsBlankLine { - containsBlankLine = false - raw.WriteByte('\n') - - } + containsBlankLine = false // add the line into the working buffer without prefix raw.Write(data[line+indent : i]) @@ -1359,6 +1374,14 @@ return i } + // if there's a fenced code block, paragraph is over + if p.flags&EXTENSION_FENCED_CODE != 0 { + if p.fencedCode(out, current, false) > 0 { + p.renderParagraph(out, data[:i]) + return i + } + } + // if there's a definition list item, prev line is a definition term if p.flags&EXTENSION_DEFINITION_LISTS != 0 { if p.dliPrefix(current) != 0 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/block_test.go new/blackfriday-1.4.0+git20151230.c8875c0/block_test.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/block_test.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/block_test.go 2016-01-17 10:55:17.000000000 +0100 @@ -14,6 +14,7 @@ package blackfriday import ( + "strings" "testing" ) @@ -701,10 +702,41 @@ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n", "<ul>\n<li><p>List</p>\n\n<ul>\n<li>sublist</li>\n</ul>\n\n<p>normal text</p>\n\n<ul>\n<li>another sublist</li>\n</ul></li>\n</ul>\n", + + `* Foo + + bar + + qux +`, + `<ul> +<li><p>Foo</p> + +<pre><code>bar + +qux +</code></pre></li> +</ul> +`, } doTestsBlock(t, tests, 0) } +func TestFencedCodeBlockWithinList(t *testing.T) { + doTestsBlock(t, []string{ + "* Foo\n\n ```\n bar\n\n qux\n ```\n", + `<ul> +<li><p>Foo</p> + +<pre><code>bar + +qux +</code></pre></li> +</ul> +`, + }, EXTENSION_FENCED_CODE) +} + func TestOrderedList(t *testing.T) { var tests = []string{ "1. Hello\n", @@ -797,6 +829,26 @@ "1. numbers\n1. are ignored\n", "<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n", + + `1. Foo + + bar + + + + qux +`, + `<ol> +<li><p>Foo</p> + +<pre><code>bar + + + +qux +</code></pre></li> +</ol> +`, } doTestsBlock(t, tests, 0) } @@ -1065,6 +1117,118 @@ doTestsBlock(t, tests, EXTENSION_FENCED_CODE) } +func TestFencedCodeInsideBlockquotes(t *testing.T) { + cat := func(s ...string) string { return strings.Join(s, "\n") } + var tests = []string{ + cat("> ```go", + "package moo", + "", + "```", + ""), + `<blockquote> +<pre><code class="language-go">package moo + +</code></pre> +</blockquote> +`, + // ------------------------------------------- + cat("> foo", + "> ", + "> ```go", + "package moo", + "```", + "> ", + "> goo.", + ""), + `<blockquote> +<p>foo</p> + +<pre><code class="language-go">package moo +</code></pre> + +<p>goo.</p> +</blockquote> +`, + // ------------------------------------------- + cat("> foo", + "> ", + "> quote", + "continues", + "```", + ""), + `<blockquote> +<p>foo</p> + +<p>quote +continues +` + "```" + `</p> +</blockquote> +`, + // ------------------------------------------- + cat("> foo", + "> ", + "> ```go", + "package moo", + "```", + "> ", + "> goo.", + "> ", + "> ```go", + "package zoo", + "```", + "> ", + "> woo.", + ""), + `<blockquote> +<p>foo</p> + +<pre><code class="language-go">package moo +</code></pre> + +<p>goo.</p> + +<pre><code class="language-go">package zoo +</code></pre> + +<p>woo.</p> +</blockquote> +`, + } + + // These 2 alternative forms of blockquoted fenced code blocks should produce same output. + forms := [2]string{ + cat("> plain quoted text", + "> ```fenced", + "code", + " with leading single space correctly preserved", + "okay", + "```", + "> rest of quoted text"), + cat("> plain quoted text", + "> ```fenced", + "> code", + "> with leading single space correctly preserved", + "> okay", + "> ```", + "> rest of quoted text"), + } + want := `<blockquote> +<p>plain quoted text</p> + +<pre><code class="language-fenced">code + with leading single space correctly preserved +okay +</code></pre> + +<p>rest of quoted text</p> +</blockquote> +` + tests = append(tests, forms[0], want) + tests = append(tests, forms[1], want) + + doTestsBlock(t, tests, EXTENSION_FENCED_CODE) +} + func TestTable(t *testing.T) { var tests = []string{ "a | b\n---|---\nc | d\n", @@ -1401,7 +1565,57 @@ "Yep, more here too\n" + "</h1>", } - doTestsBlock(t, tests, EXTENSION_TITLEBLOCK) +} + +func TestBlockComments(t *testing.T) { + var tests = []string{ + "Some text\n\n<!-- comment -->\n", + "<p>Some text</p>\n\n<!-- comment -->\n", + + "Some text\n\n<!--\n\nmultiline\ncomment\n-->\n", + "<p>Some text</p>\n\n<!--\n\nmultiline\ncomment\n-->\n", + + "Some text\n\n<!--\n\n<div><p>Commented</p>\n<span>html</span></div>\n-->\n", + "<p>Some text</p>\n\n<!--\n\n<div><p>Commented</p>\n<span>html</span></div>\n-->\n", + } + doTestsBlock(t, tests, 0) +} + +func TestCDATA(t *testing.T) { + var tests = []string{ + "Some text\n\n<![CDATA[foo]]>\n", + "<p>Some text</p>\n\n<![CDATA[foo]]>\n", + + "CDATA ]]\n\n<![CDATA[]]]]>\n", + "<p>CDATA ]]</p>\n\n<![CDATA[]]]]>\n", + "CDATA >\n\n<![CDATA[>]]>\n", + "<p>CDATA ></p>\n\n<![CDATA[>]]>\n", + + "Lots of text\n\n<![CDATA[lots of te><t\non\nseveral\nlines]]>\n", + "<p>Lots of text</p>\n\n<![CDATA[lots of te><t\non\nseveral\nlines]]>\n", + + "<![CDATA[>]]>\n", + "<![CDATA[>]]>\n", + } + doTestsBlock(t, tests, 0) + doTestsBlock(t, []string{ + "``` html\n<![CDATA[foo]]>\n```\n", + "<pre><code class=\"language-html\"><![CDATA[foo]]>\n</code></pre>\n", + + "<![CDATA[\n``` python\ndef func():\n pass\n```\n]]>\n", + "<![CDATA[\n``` python\ndef func():\n pass\n```\n]]>\n", + + `<![CDATA[ +> def func(): +> pass +]]> +`, + `<![CDATA[ +> def func(): +> pass +]]> +`, + }, EXTENSION_FENCED_CODE) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/html.go new/blackfriday-1.4.0+git20151230.c8875c0/html.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/html.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/html.go 2016-01-17 10:55:17.000000000 +0100 @@ -39,7 +39,8 @@ HTML_USE_XHTML // generate XHTML output instead of HTML HTML_USE_SMARTYPANTS // enable smart punctuation substitutions HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS) - HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS) + HTML_SMARTYPANTS_DASHES // enable smart dashes (with HTML_USE_SMARTYPANTS) + HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS and HTML_SMARTYPANTS_DASHES) HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/inline.go new/blackfriday-1.4.0+git20151230.c8875c0/inline.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/inline.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/inline.go 2016-01-17 10:55:17.000000000 +0100 @@ -191,6 +191,13 @@ linkInlineFootnote ) +func isReferenceStyleLink(data []byte, pos int, t linkType) bool { + if t == linkDeferredFootnote { + return false + } + return pos < len(data)-1 && data[pos] == '[' && data[pos+1] != '^' +} + // '[': parse a link or an image or a footnote func link(p *parser, out *bytes.Buffer, data []byte, offset int) int { // no links allowed inside regular links, footnote, and deferred footnotes @@ -198,19 +205,26 @@ return 0 } - // [text] == regular link + var t linkType + switch { + // special case: ![^text] == deferred footnote (that follows something with + // an exclamation point) + case p.flags&EXTENSION_FOOTNOTES != 0 && len(data)-1 > offset && data[offset+1] == '^': + t = linkDeferredFootnote // ![alt] == image + case offset > 0 && data[offset-1] == '!': + t = linkImg // ^[text] == inline footnote // [^refId] == deferred footnote - var t linkType - if offset > 0 && data[offset-1] == '!' { - t = linkImg - } else if p.flags&EXTENSION_FOOTNOTES != 0 { + case p.flags&EXTENSION_FOOTNOTES != 0: if offset > 0 && data[offset-1] == '^' { t = linkInlineFootnote } else if len(data)-1 > offset && data[offset+1] == '^' { t = linkDeferredFootnote } + // [text] == regular link + default: + t = linkNormal } data = data[offset:] @@ -226,6 +240,8 @@ i++ } + brace := 0 + // look for the matching closing bracket for level := 1; level > 0 && i < len(data); i++ { switch { @@ -259,8 +275,8 @@ i++ } - // inline style link switch { + // inline style link case i < len(data) && data[i] == '(': // skip initial whitespace i++ @@ -271,14 +287,27 @@ linkB := i - // look for link end: ' " ) + // look for link end: ' " ), check for new opening braces and take this + // into account, this may lead for overshooting and probably will require + // some fine-tuning. findlinkend: for i < len(data) { switch { case data[i] == '\\': i += 2 - case data[i] == ')' || data[i] == '\'' || data[i] == '"': + case data[i] == '(': + brace++ + i++ + + case data[i] == ')': + if brace <= 0 { + break findlinkend + } + brace-- + i++ + + case data[i] == '\'' || data[i] == '"': break findlinkend default: @@ -353,7 +382,7 @@ i++ // reference style link - case i < len(data)-1 && data[i] == '[' && data[i+1] != '^': + case isReferenceStyleLink(data, i, t): var id []byte altContentConsidered := false @@ -395,7 +424,6 @@ lr, ok := p.getRef(string(id)) if !ok { return 0 - } // keep link and title from reference @@ -547,12 +575,33 @@ return i } +func (p *parser) inlineHTMLComment(out *bytes.Buffer, data []byte) int { + if len(data) < 5 { + return 0 + } + if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { + return 0 + } + i := 5 + // scan for an end-of-comment marker, across lines if necessary + for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { + i++ + } + // no end-of-comment marker + if i >= len(data) { + return 0 + } + return i + 1 +} + // '<' when tags or autolinks are allowed func leftAngle(p *parser, out *bytes.Buffer, data []byte, offset int) int { data = data[offset:] altype := LINK_TYPE_NOT_AUTOLINK end := tagLength(data, &altype) - + if size := p.inlineHTMLComment(out, data); size > 0 { + end = size + } if end > 2 { if altype != LINK_TYPE_NOT_AUTOLINK { var uLink bytes.Buffer @@ -634,10 +683,7 @@ func linkEndsWithEntity(data []byte, linkEnd int) bool { entityRanges := htmlEntity.FindAllIndex(data[:linkEnd], -1) - if entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd { - return true - } - return false + return entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd } func autoLink(p *parser, out *bytes.Buffer, data []byte, offset int) int { @@ -910,7 +956,7 @@ // look for the next emph char, skipping other constructs func helperFindEmphChar(data []byte, c byte) int { - i := 1 + i := 0 for i < len(data) { for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { @@ -919,15 +965,14 @@ if i >= len(data) { return 0 } - if data[i] == c { - return i - } - // do not count escaped chars if i != 0 && data[i-1] == '\\' { i++ continue } + if data[i] == c { + return i + } if data[i] == '`' { // skip a code span diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/inline_test.go new/blackfriday-1.4.0+git20151230.c8875c0/inline_test.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/inline_test.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/inline_test.go 2016-01-17 10:55:17.000000000 +0100 @@ -15,9 +15,8 @@ import ( "regexp" - "testing" - "strings" + "testing" ) func runMarkdownInline(input string, opts Options, htmlFlags int, params HtmlRendererParameters) string { @@ -153,10 +152,38 @@ "mix of *markers_\n", "<p>mix of *markers_</p>\n", + + "*What is A\\* algorithm?*\n", + "<p><em>What is A* algorithm?</em></p>\n", + + "some para_graph with _emphasised_ text.\n", + "<p>some para_graph with <em>emphasised</em> text.</p>\n", + + "some paragraph with _emphasised_ te_xt.\n", + "<p>some paragraph with <em>emphasised</em> te_xt.</p>\n", + + "some paragraph with t_wo bi_ts of _emphasised_ text.\n", + "<p>some paragraph with t<em>wo bi</em>ts of <em>emphasised</em> text.</p>\n", + + "un*frigging*believable\n", + "<p>un<em>frigging</em>believable</p>\n", } doTestsInline(t, tests) } +func TestNoIntraEmphasis(t *testing.T) { + tests := []string{ + "some para_graph with _emphasised_ text.\n", + "<p>some para_graph with <em>emphasised</em> text.</p>\n", + + "un*frigging*believable\n", + "<p>un*frigging*believable</p>\n", + } + doTestsInlineParam(t, tests, Options{ + Extensions: EXTENSION_NO_INTRA_EMPHASIS}, + 0, HtmlRendererParameters{}) +} + func TestReferenceOverride(t *testing.T) { var tests = []string{ "test [ref1][]\n", @@ -263,6 +290,12 @@ "mix of **markers__\n", "<p>mix of **markers__</p>\n", + + "**`/usr`** : this folder is named `usr`\n", + "<p><strong><code>/usr</code></strong> : this folder is named <code>usr</code></p>\n", + + "**`/usr`** :\n\n this folder is named `usr`\n", + "<p><strong><code>/usr</code></strong> :</p>\n\n<p>this folder is named <code>usr</code></p>\n", } doTestsInline(t, tests) } @@ -291,7 +324,7 @@ "<p><strong>improper *nesting</strong> is* bad</p>\n", "*improper **nesting* is** bad\n", - "<p><em>improper **nesting</em> is** bad</p>\n", + "<p>*improper <strong>nesting* is</strong> bad</p>\n", } doTestsInline(t, tests) } @@ -532,6 +565,20 @@ "[link](<../>)\n", "<p><a href=\"../\">link</a></p>\n", + + // Issue 116 in blackfriday + "![](http://www.broadgate.co.uk/Content/Upload/DetailImages/Cyclus700(1).jpg)", + "<p><img src=\"http://www.broadgate.co.uk/Content/Upload/DetailImages/Cyclus700(1).jpg\" alt=\"\" /></p>\n", + + // no closing ), autolinking detects the url next + "[disambiguation](http://en.wikipedia.org/wiki/Disambiguation_(disambiguation) is the", + "<p>[disambiguation](<a href=\"http://en.wikipedia.org/wiki/Disambiguation_(disambiguation\">http://en.wikipedia.org/wiki/Disambiguation_(disambiguation</a>) is the</p>\n", + + "[disambiguation](http://en.wikipedia.org/wiki/Disambiguation_(disambiguation)) is the", + "<p><a href=\"http://en.wikipedia.org/wiki/Disambiguation_(disambiguation)\">disambiguation</a> is the</p>\n", + + "[disambiguation](http://en.wikipedia.org/wiki/Disambiguation_(disambiguation))", + "<p><a href=\"http://en.wikipedia.org/wiki/Disambiguation_(disambiguation)\">disambiguation</a></p>\n", } doLinkTestsInline(t, tests) @@ -672,6 +719,9 @@ "[ref]\n [ref]: ../url/ \"title\"\n", "<p><a href=\"../url/\" title=\"title\">ref</a></p>\n", + + "[link][ref]\n [ref]: /url/", + "<p><a href=\"/url/\">link</a></p>\n", } doLinkTestsInline(t, tests) } @@ -942,6 +992,40 @@ "Some text.[^note1][^note2]\n\n[^note1]: fn1\n[^note2]: fn2\n", "<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup><sup class=\"footnote-ref\" id=\"fnref:note2\"><a rel=\"footnote\" href=\"#fn:note2\">2</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n<li id=\"fn:note2\">fn2\n</li>\n</ol>\n</div>\n", + + `Bla bla [^1] [WWW][w3] + +[^1]: This is a footnote + +[w3]: http://www.w3.org/ +`, + `<p>Bla bla <sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup> <a href="http://www.w3.org/">WWW</a></p> +<div class="footnotes"> + +<hr /> + +<ol> +<li id="fn:1">This is a footnote +</li> +</ol> +</div> +`, + + `This is exciting![^fn1] + +[^fn1]: Fine print +`, + `<p>This is exciting!<sup class="footnote-ref" id="fnref:fn1"><a rel="footnote" href="#fn:fn1">1</a></sup></p> +<div class="footnotes"> + +<hr /> + +<ol> +<li id="fn:fn1">Fine print +</li> +</ol> +</div> +`, } func TestFootnotes(t *testing.T) { @@ -973,6 +1057,62 @@ doTestsInlineParam(t, tests, Options{Extensions: EXTENSION_FOOTNOTES}, HTML_FOOTNOTE_RETURN_LINKS, params) } +func TestNestedFootnotes(t *testing.T) { + var tests = []string{ + `Paragraph.[^fn1] + +[^fn1]: + Asterisk[^fn2] + +[^fn2]: + Obelisk`, + `<p>Paragraph.<sup class="footnote-ref" id="fnref:fn1"><a rel="footnote" href="#fn:fn1">1</a></sup></p> +<div class="footnotes"> + +<hr /> + +<ol> +<li id="fn:fn1">Asterisk<sup class="footnote-ref" id="fnref:fn2"><a rel="footnote" href="#fn:fn2">2</a></sup> +</li> +<li id="fn:fn2">Obelisk +</li> +</ol> +</div> +`, + } + doTestsInlineParam(t, tests, Options{Extensions: EXTENSION_FOOTNOTES}, 0, + HtmlRendererParameters{}) +} + +func TestInlineComments(t *testing.T) { + var tests = []string{ + "Hello <!-- there ->\n", + "<p>Hello <!— there –></p>\n", + + "Hello <!-- there -->\n", + "<p>Hello <!-- there --></p>\n", + + "Hello <!-- there -->", + "<p>Hello <!-- there --></p>\n", + + "Hello <!---->\n", + "<p>Hello <!----></p>\n", + + "Hello <!-- there -->\na", + "<p>Hello <!-- there -->\na</p>\n", + + "* list <!-- item -->\n", + "<ul>\n<li>list <!-- item --></li>\n</ul>\n", + + "<!-- Front --> comment\n", + "<p><!-- Front --> comment</p>\n", + + "blahblah\n<!--- foo -->\nrhubarb\n", + "<p>blahblah\n<!--- foo -->\nrhubarb</p>\n", + } + doTestsInlineParam(t, tests, Options{}, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_DASHES, HtmlRendererParameters{}) +} + func TestSmartDoubleQuotes(t *testing.T) { var tests = []string{ "this should be normal \"quoted\" text.\n", @@ -1014,3 +1154,41 @@ doTestsInlineParam(t, tests, Options{}, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_FRACTIONS, HtmlRendererParameters{}) } + +func TestDisableSmartDashes(t *testing.T) { + doTestsInlineParam(t, []string{ + "foo - bar\n", + "<p>foo - bar</p>\n", + "foo -- bar\n", + "<p>foo -- bar</p>\n", + "foo --- bar\n", + "<p>foo --- bar</p>\n", + }, Options{}, 0, HtmlRendererParameters{}) + doTestsInlineParam(t, []string{ + "foo - bar\n", + "<p>foo – bar</p>\n", + "foo -- bar\n", + "<p>foo — bar</p>\n", + "foo --- bar\n", + "<p>foo —– bar</p>\n", + }, Options{}, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_DASHES, HtmlRendererParameters{}) + doTestsInlineParam(t, []string{ + "foo - bar\n", + "<p>foo - bar</p>\n", + "foo -- bar\n", + "<p>foo – bar</p>\n", + "foo --- bar\n", + "<p>foo — bar</p>\n", + }, Options{}, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_LATEX_DASHES|HTML_SMARTYPANTS_DASHES, + HtmlRendererParameters{}) + doTestsInlineParam(t, []string{ + "foo - bar\n", + "<p>foo - bar</p>\n", + "foo -- bar\n", + "<p>foo -- bar</p>\n", + "foo --- bar\n", + "<p>foo --- bar</p>\n", + }, Options{}, + HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_LATEX_DASHES, + HtmlRendererParameters{}) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/markdown.go new/blackfriday-1.4.0+git20151230.c8875c0/markdown.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/markdown.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/markdown.go 2016-01-17 10:55:17.000000000 +0100 @@ -20,11 +20,12 @@ import ( "bytes" + "fmt" "strings" "unicode/utf8" ) -const VERSION = "1.1" +const VERSION = "1.5" // These are the supported markdown parsing extensions. // OR these values together to select multiple extensions. @@ -50,6 +51,7 @@ HTML_USE_XHTML | HTML_USE_SMARTYPANTS | HTML_SMARTYPANTS_FRACTIONS | + HTML_SMARTYPANTS_DASHES | HTML_SMARTYPANTS_LATEX_DASHES commonExtensions = 0 | @@ -100,45 +102,49 @@ TAB_SIZE_EIGHT = 8 ) -// These are the tags that are recognized as HTML block tags. +// blockTags is a set of tags that are recognized as HTML block tags. // Any of these can be included in markdown text without special escaping. -var blockTags = map[string]bool{ - "p": true, - "dl": true, - "h1": true, - "h2": true, - "h3": true, - "h4": true, - "h5": true, - "h6": true, - "ol": true, - "ul": true, - "del": true, - "div": true, - "ins": true, - "pre": true, - "form": true, - "math": true, - "table": true, - "iframe": true, - "script": true, - "fieldset": true, - "noscript": true, - "blockquote": true, +var blockTags = map[string]struct{}{ + "blockquote": struct{}{}, + "del": struct{}{}, + "div": struct{}{}, + "dl": struct{}{}, + "fieldset": struct{}{}, + "form": struct{}{}, + "h1": struct{}{}, + "h2": struct{}{}, + "h3": struct{}{}, + "h4": struct{}{}, + "h5": struct{}{}, + "h6": struct{}{}, + "iframe": struct{}{}, + "ins": struct{}{}, + "math": struct{}{}, + "noscript": struct{}{}, + "ol": struct{}{}, + "pre": struct{}{}, + "p": struct{}{}, + "script": struct{}{}, + "style": struct{}{}, + "table": struct{}{}, + "ul": struct{}{}, // HTML5 - "video": true, - "aside": true, - "canvas": true, - "figure": true, - "footer": true, - "header": true, - "hgroup": true, - "output": true, - "article": true, - "section": true, - "progress": true, - "figcaption": true, + "address": struct{}{}, + "article": struct{}{}, + "aside": struct{}{}, + "canvas": struct{}{}, + "figcaption": struct{}{}, + "figure": struct{}{}, + "footer": struct{}{}, + "header": struct{}{}, + "hgroup": struct{}{}, + "main": struct{}{}, + "nav": struct{}{}, + "output": struct{}{}, + "progress": struct{}{}, + "section": struct{}{}, + "video": struct{}{}, } // Renderer is the rendering interface. @@ -384,7 +390,6 @@ // - expand tabs // - normalize newlines // - copy everything else -// - add missing newlines before fenced code blocks func firstPass(p *parser, input []byte) []byte { var out bytes.Buffer tabSize := TAB_SIZE_DEFAULT @@ -392,7 +397,6 @@ tabSize = TAB_SIZE_EIGHT } beg, end := 0, 0 - lastLineWasBlank := false lastFencedCodeBlockEnd := 0 for beg < len(input) { // iterate over lines if end = isReference(p, input[beg:], tabSize); end > 0 { @@ -404,16 +408,13 @@ } if p.flags&EXTENSION_FENCED_CODE != 0 { - // when last line was none blank and a fenced code block comes after + // track fenced code block boundaries to suppress tab expansion + // inside them: if beg >= lastFencedCodeBlockEnd { if i := p.fencedCode(&out, input[beg:], false); i > 0 { - if !lastLineWasBlank { - out.WriteByte('\n') // need to inject additional linebreak - } lastFencedCodeBlockEnd = beg + i } } - lastLineWasBlank = end == beg } // add the line body if present @@ -455,7 +456,8 @@ if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 { p.r.Footnotes(&output, func() bool { flags := LIST_ITEM_BEGINNING_OF_LIST - for _, ref := range p.notes { + for i := 0; i < len(p.notes); i += 1 { + ref := p.notes[i] var buf bytes.Buffer if ref.hasBlock { flags |= LIST_ITEM_CONTAINS_BLOCK @@ -518,6 +520,11 @@ 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) +} + // Check whether or not data starts with a reference link. // If so, it is parsed and stored in the list of references // (in the render struct). @@ -631,9 +638,6 @@ for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { i++ } - if i == len(data) { - return - } linkEnd = i if data[linkOffset] == '<' && data[linkEnd-1] == '>' { linkOffset++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blackfriday-1.2.0+git20150720.8cec3a8/smartypants.go new/blackfriday-1.4.0+git20151230.c8875c0/smartypants.go --- old/blackfriday-1.2.0+git20150720.8cec3a8/smartypants.go 2015-07-28 14:23:19.000000000 +0200 +++ new/blackfriday-1.4.0+git20151230.c8875c0/smartypants.go 2016-01-17 10:55:17.000000000 +0100 @@ -378,10 +378,12 @@ } r['\''] = smartSingleQuote r['('] = smartParens - if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 { - r['-'] = smartDash - } else { - r['-'] = smartDashLatex + if flags&HTML_SMARTYPANTS_DASHES != 0 { + if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 { + r['-'] = smartDash + } else { + r['-'] = smartDashLatex + } } r['.'] = smartPeriod if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {