diff --git a/Markdown/Markdown.sublime-syntax b/Markdown/Markdown.sublime-syntax index 027a5cebff..c573f3cbe6 100644 --- a/Markdown/Markdown.sublime-syntax +++ b/Markdown/Markdown.sublime-syntax @@ -27,7 +27,7 @@ variables: ) [ \t]*$ # followed by any number of tabs or spaces, followed by the end of the line ) - block_quote: (?:[ ]{,3}>(?:.|$)) # between 0 and 3 spaces, followed by a greater than sign, followed by any character or the end of the line + block_quote: (?:[ ]{,3}(>)[ ]?) # between 0 and 3 spaces, followed by a greater than sign, (followed by any character or the end of the line = "only care about optional space!") atx_heading: (?:[ ]{,3}[#]{1,6}(?:[ \t]|$)) # between 0 and 3 spaces, followed 1 to 6 hashes, followed by at least one space or tab or by end of the line atx_heading_space: (?:(?=[ \t]+#+[ \t]*$)|[ \t]+|$) # consume spaces only if heading is not empty to ensure `atx_heading_end` can fully match closing hashes atx_heading_end: (?:[ \t]+(#+))?[ \t]*($\n?) # \n is optional so ## is matched as end punctuation in new document (at eof) @@ -235,7 +235,7 @@ contexts: pattern will only match stuff matched by the sub-patterns. push: - meta_scope: meta.block-level.markdown - - include: block-quote + - include: block-quotes - include: ligatures - include: indented-code-block - include: atx-heading @@ -388,9 +388,10 @@ contexts: # >= >== >=== >=> >==> >===> >=< >==< >===< - match: '<<+|<>|>>+' # << <<< <<<< <> >>>> >>> >> - block-quote: - - match: '[ ]{,3}(>)[ ]?' - comment: | + block-quotes: + # https://spec.commonmark.org/0.30/#block-quotes + - match: ^{{block_quote}} + comment: |- We terminate the block quote when seeing an empty line, a separator or a line with leading > characters. The latter is to “reset” the quote level for quoted lines. @@ -401,62 +402,33 @@ contexts: captures: 1: punctuation.definition.blockquote.markdown push: - - meta_scope: markup.quote.markdown - - match: |- - (?x)^ - (?= \s*$ - | {{thematic_break}} - | {{block_quote}} - ) - pop: true - - match: |- - (?x) - (?= {{block_quote}} - ) - push: - - match: ^ - pop: true - - include: block-quote - - match: |- - (?x) - (?= {{indented_code_block}} - | {{atx_heading}} - | {{thematic_break}} - | {{list_item}} - ) - push: - - include: indented-code-block - - include: atx-heading - - include: thematic-break - - match: ([ ]{,3})(\d+([.)]))(\s) - captures: - 1: markup.list.numbered.markdown - 2: markup.list.numbered.bullet.markdown - 3: punctuation.definition.list_item.markdown - 4: markup.list.numbered.markdown - push: - - meta_content_scope: markup.list.numbered.markdown meta.paragraph.list.markdown - - include: list-content - - match: ([ ]{,3})([*+-])((?:[ ](\[[ xX]\]))?\s) - captures: - 1: markup.list.unnumbered.markdown - 2: markup.list.unnumbered.bullet.markdown punctuation.definition.list_item.markdown - 3: markup.list.unnumbered.markdown - 4: constant.language.checkbox.markdown-gfm - push: - - meta_content_scope: markup.list.unnumbered.markdown meta.paragraph.list.markdown - - include: list-content - - match: ^ - pop: true - - include: list-paragraph - - include: block-quote-code-blocks - - match: '' - push: - - match: ^ - pop: true - - include: inline-bold-italic-linebreak + - block-quote-meta + - block-quote-content - block-quote-code-blocks: + block-quote-nested: + - match: '{{block_quote}}' + captures: + 1: punctuation.definition.blockquote.markdown + set: + - block-quote-meta + - block-quote-content + + block-quote-meta: + - meta_include_prototype: false + - meta_scope: markup.quote.markdown + - include: immediately-pop + + block-quote-content: + - include: block-quote-nested + - include: block-quote-code-block + - include: block-quote-list-item + - include: atx-heading + - include: indented-code-block + - include: thematic-break + - match: '' + set: block-quote-text + + block-quote-code-block: - match: |- (?x) {{fenced_code_block_start}} @@ -466,22 +438,70 @@ contexts: 0: meta.code-fence.definition.begin.text.markdown-gfm 2: punctuation.definition.raw.code-fence.begin.markdown 5: constant.other.language-name.markdown - push: block-quote-code-block-content + set: block-quote-code-block-content block-quote-code-block-content: + - match: ^(?!\s*{{block_quote}}) + pop: true - match: '{{code_fence_end}}' captures: 0: meta.code-fence.definition.end.text.markdown-gfm 1: punctuation.definition.raw.code-fence.end.markdown pop: true - - match: '[ ]{,3}(>)[ ]?' + - match: '{{block_quote}}' captures: 1: punctuation.definition.blockquote.markdown - match: '' - push: - - meta_content_scope: markup.raw.code-fence.markdown-gfm - - match: ^ - pop: true + push: block-quote-code-block-text + + block-quote-code-block-text: + - meta_include_prototype: false + - meta_content_scope: markup.raw.code-fence.markdown-gfm + - match: ^ + pop: true + + block-quote-list-item: + - match: ([ ]{,3})(\d+)(\.)(\s) + captures: + 1: markup.list.numbered.markdown + 2: markup.list.numbered.bullet.markdown + 3: markup.list.numbered.bullet.markdown punctuation.definition.list_item.markdown + 4: markup.list.numbered.markdown + set: + - block-quote-ordered-list-content + - list-content + - match: ([ ]{,3})([*+-])((?:[ ](\[[ xX]\]))?\s) + captures: + 1: markup.list.unnumbered.markdown + 2: markup.list.unnumbered.bullet.markdown punctuation.definition.list_item.markdown + 3: markup.list.unnumbered.markdown + 4: constant.language.checkbox.markdown-gfm + set: + - block-quote-unordered-list-content + - list-content + + block-quote-ordered-list-content: + - meta_content_scope: markup.list.numbered.markdown meta.paragraph.list.markdown + - include: block-quote-text + + block-quote-unordered-list-content: + - meta_content_scope: markup.list.unnumbered.markdown meta.paragraph.list.markdown + - include: block-quote-text + + block-quote-text: + - match: |- + (?x) + ^ + (?= \s*$ + | {{atx_heading}} + | {{block_quote}} + | {{fenced_code_block_start}} + | {{list_item}} + | {{thematic_break}} + ) + pop: true + - include: inline-bold-italic-linebreak + - include: scope:text.html.basic indented-code-block: - match: '{{indented_code_block}}.*$\n?' @@ -1118,11 +1138,12 @@ contexts: - include: indented-code-block - match: $ pop: true - - match: '^(?=\s+{{block_quote}})' + - match: ^[ ]*{{block_quote}} + captures: + 1: punctuation.definition.blockquote.markdown push: - - include: block-quote - - match: $ - pop: true + - block-quote-meta + - block-quote-content - include: fenced-code-blocks - include: reference-link-definition - match: \s+(?=\S) diff --git a/Markdown/syntax_test_markdown.md b/Markdown/syntax_test_markdown.md index a64af277a4..30c5b2b716 100644 --- a/Markdown/syntax_test_markdown.md +++ b/Markdown/syntax_test_markdown.md @@ -740,55 +740,75 @@ non-disabled markdown non-disabled markdown | <- - meta.disable-markdown -> Quote + +# Block Quote Tests ########################################################### + +>= +| <- punctuation.definition.blockquote.markdown + +>== +| <- punctuation.definition.blockquote.markdown + + >= +| ^ punctuation.definition.blockquote.markdown + >= +| ^^ - punctuation.definition.blockquote.markdown + + >= +| ^^ - punctuation.definition.blockquote.markdown + +> Block quote | <- meta.block-level markup.quote punctuation.definition.blockquote -| ^^^^^^ meta.block-level markup.quote +| ^^^^^^^^^^^ meta.block-level markup.quote -> Quote followed by an empty block quote line +> Block quote followed by an empty block quote line > | <- meta.block-level markup.quote punctuation.definition.blockquote -> Quote followed by an empty block quote line +> Block quote followed by an empty block quote line > > Followed by more quoted text | <- meta.block-level markup.quote punctuation.definition.blockquote -> > Nested quote +> > Nested block quote | <- meta.block-level markup.quote punctuation.definition.blockquote -| ^ meta.block-level markup.quote markup.quote punctuation.definition.blockquote +| ^^^^^^^^^^^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown markup.quote.markdown +|^ - punctuation +| ^ punctuation.definition.blockquote +| ^ - punctuation > > Nested quote > Followed by more quoted text that is not nested | <- meta.block-level markup.quote punctuation.definition.blockquote - markup.quote markup.quote -> Here is a quote block -This quote continues on. Line breaking is OK in markdown -| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block-level markup.quote +> Here is a block quote +This quote continues on. Line breaking is OK in markdown +| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block-level markup.quote > Here it is again | <- punctuation.definition.blockquote paragraph | <- meta.paragraph - meta.block-level -> > this is code in a quote block, not a nested quote +> > this is a nested quote but no code in a block quote +| <- punctuation.definition.blockquote +| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown markup.quote.markdown + +> > this is code in a block quote, not a nested quote | <- punctuation.definition.blockquote | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ markup.raw.block - markup.quote markup.quote -> Here are fenced code blocks +> CommonMark expects following line to be indented code block (see: example 326) + > but all common parsers handle it as continued text. +| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown - markup.raw +| ^ - punctuation + +> Quoted fenced code block begin > ``` | <- meta.block-level.markdown markup.quote.markdown punctuation.definition.blockquote.markdown |^ meta.block-level.markdown markup.quote.markdown - meta.code-fence | ^^^^ meta.block-level.markdown markup.quote.markdown meta.code-fence.definition.begin.text.markdown-gfm | ^^^ punctuation.definition.raw.code-fence.begin.markdown -> code block -| <- meta.block-level.markdown markup.quote.markdown punctuation.definition.blockquote.markdown -|^ meta.block-level.markdown markup.quote.markdown - meta.code-fence -| ^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown markup.raw.code-fence.markdown-gfm -> ``` -| <- meta.block-level.markdown markup.quote.markdown punctuation.definition.blockquote.markdown -|^ meta.block-level.markdown markup.quote.markdown - meta.code-fence -| ^^^^ meta.block-level.markdown markup.quote.markdown meta.code-fence.definition.end.text.markdown-gfm -| ^^^ punctuation.definition.raw.code-fence.end.markdown > Quoted fenced code block language identifier > ```C++ @@ -796,7 +816,6 @@ paragraph |^ meta.block-level.markdown markup.quote.markdown - meta.code-fence | ^^^^^^^ meta.block-level.markdown markup.quote.markdown meta.code-fence.definition.begin.text.markdown-gfm | ^^^ constant.other.language-name.markdown -> ``` > Quoted fenced code block language identifier > ```C++ info string @@ -805,27 +824,90 @@ paragraph | ^^^^^^^^^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown meta.code-fence.definition.begin.text.markdown-gfm | ^^^ constant.other.language-name.markdown | ^^^^^^^^^^^^^ - constant + +> Quoted fenced code block content > ``` +> code block +| <- meta.block-level.markdown markup.quote.markdown punctuation.definition.blockquote.markdown +|^ meta.block-level.markdown markup.quote.markdown - meta.code-fence +| ^^^^^^^^^^^ meta.block-level.markdown markup.quote.markdown markup.raw.code-fence.markdown-gfm -> > 2nd level -> > +> Quoted fenced code block end +> ``` +> ``` +| <- meta.block-level.markdown markup.quote.markdown punctuation.definition.blockquote.markdown +|^ meta.block-level.markdown markup.quote.markdown - meta.code-fence +| ^^^^ meta.block-level.markdown markup.quote.markdown meta.code-fence.definition.end.text.markdown-gfm +| ^^^ punctuation.definition.raw.code-fence.end.markdown + +> > 2nd level quoted fenced code block > > ``` > > code block ``` -| ^^^ - punctuation > > ``` | <- meta.block-level.markdown markup.quote.markdown markup.quote.markdown punctuation.definition.blockquote.markdown |^^^ meta.block-level.markdown markup.quote.markdown markup.quote.markdown - meta.code-fence | ^^^^ meta.block-level.markdown markup.quote.markdown markup.quote.markdown meta.code-fence.definition.end.text.markdown-gfm ->= -| <- punctuation.definition.blockquote.markdown - >= -| ^ punctuation.definition.blockquote.markdown - >= -| ^^ - punctuation.definition.blockquote.markdown +> Block quote followed by fenced code block +``` +| <- meta.code-fence.definition.begin.text.markdown-gfm punctuation.definition.raw.code-fence.begin.markdown - meta.quote +``` +| <- meta.code-fence.definition.end.text.markdown-gfm punctuation.definition.raw.code-fence.end.markdown - meta.quote ->== -| <- punctuation.definition.blockquote.markdown +> Quoted fenced code block is terminated by missing > at bol +> ``` +no code block +| <- meta.paragraph.markdown - meta.quote - meta.code-fence +|^^^^^^^^^^^^^ meta.paragraph.markdown - meta.quote - meta.code-fence + +> Quoted fenced code block is terminated by missing > at bol +> ``` +> content +no code block +| <- meta.paragraph.markdown - meta.quote - meta.code-fence +|^^^^^^^^^^^^^ meta.paragraph.markdown - meta.quote - meta.code-fence + +> Unterminated quoted fenced code block followed by unquoted fenced code block +> ``` +``` +| <- meta.code-fence.definition.begin.text.markdown-gfm - markup.quote +``` +| <- meta.code-fence.definition.end.text.markdown-gfm - markup.quote + +> Block quote followed by heading +# heading +| <- meta.block-level.markdown markup.heading.1.markdown punctuation.definition.heading.begin.markdown +|^^^^^^^^^ meta.block-level.markdown markup.heading.1.markdown - meta.quote +| ^^^^^^^ entity.name.section.markdown + +> Block quote followed by list +* list item +| <- markup.list.unnumbered.bullet.markdown punctuation.definition.list_item.markdown +|^^^^^^^^^^^ markup.list.unnumbered.markdown - meta.quote + +> Block quote followed by list ++ list item +| <- markup.list.unnumbered.bullet.markdown punctuation.definition.list_item.markdown +|^^^^^^^^^^^ markup.list.unnumbered.markdown - meta.quote + +> Block quote followed by list +- list item +| <- markup.list.unnumbered.bullet.markdown punctuation.definition.list_item.markdown +|^^^^^^^^^^^ markup.list.unnumbered.markdown - meta.quote + +> Block quote followed by list +1. list item +| <- markup.list.numbered.bullet.markdown - punctuation +|^ markup.list.numbered.bullet.markdown punctuation.definition.list_item.markdown +| ^^^^^^^^^^ markup.list.numbered.markdown - meta.quote + +> Block quote followed by thematic break +*** +| <- meta.block-level.markdown meta.separator.thematic-break.markdown punctuation.definition.thematic-break.markdown - meta.quote + +> Block quote followed by thematic break +- - - +| <- meta.block-level.markdown meta.separator.thematic-break.markdown punctuation.definition.thematic-break.markdown - meta.quote Code block below: