Improve fenced code block matching

The previous fenced code block matching did not support the syntax used
by [Kramdown][1] or fully support the syntax described in
[CommonMark][2].  The differences are:

* Kramdown requires \~ instead of \` in fences (CommonMark permits \~)
* Both permit code fences to have more than 3 \~ or \` characters
* Both require the closing fence to have as many chars as the opening
* Both permit the closing fence to have extra fence chars
* CommonMark explicitly forbids \` in the fence info string

This is likely the case with other Markdown variants, but these are the
only two that I have considered when authoring this commit.

This commit implements all of the above mentioned changes.  The change
is mostly straight-forward.  The only exception is that the end matching
is a little subtle since one of `\z2` and `\z3` will be empty, using the
more natural expression `\z2*\|\z3*` can hang the regex matcher.  The
`\%(\z2\z3)*` expression is a bit less obvious but works reliably.

Note that I did not include any changes relating to the Pandoc syntax
mentioned in #65 and #74.  If this syntax is desired, I can adjust this
commit to include it.

[1]:  http://kramdown.gettalong.org/syntax.html#fenced-code-blocks
[2]:  http://spec.commonmark.org/0.22/#code-fence

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
This commit is contained in:
Kevin Locke
2015-10-02 22:12:34 -07:00
parent ba294150d1
commit aff85c6411

View File

@@ -85,14 +85,14 @@ exe 'syn region markdownBoldItalic matchgroup=markdownBoldItalicDelimiter start=
syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart
syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*```.*$" end="^\s*```\ze\s*$" keepend syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*\z(\z(`\)\{3,}\|\z(\~\)\{3,}\)[^`]*$" end="^\s*\z1\%(\z2\z3\)*\ze\s*$" keepend
syn match markdownFootnote "\[^[^\]]\+\]" syn match markdownFootnote "\[^[^\]]\+\]"
syn match markdownFootnoteDefinition "^\[^[^\]]\+\]:" syn match markdownFootnoteDefinition "^\[^[^\]]\+\]:"
if main_syntax ==# 'markdown' if main_syntax ==# 'markdown'
for s:type in g:markdown_fenced_languages for s:type in g:markdown_fenced_languages
exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*```\s*'.matchstr(s:type,'[^=]*').'\>.*$" end="^\s*```\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g') exe 'syn region markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\..*','','').' matchgroup=markdownCodeDelimiter start="^\s*\z(\z(`\)\{3,}\|\z(\~\)\{3,}\)\s*'.matchstr(s:type,'[^=]*').'\>[^`]*$" end="^\s*\z1\%(\z2\z3\)*\ze\s*$" keepend contains=@markdownHighlight'.substitute(matchstr(s:type,'[^=]*$'),'\.','','g')
endfor endfor
unlet! s:type unlet! s:type
endif endif