Skip to content

Commit

Permalink
Fix blockquote termination by list item
Browse files Browse the repository at this point in the history
close #338
  • Loading branch information
rlidwka committed Mar 6, 2017
1 parent bcfbe38 commit c57f593
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,9 @@
8.3.1 / WIP
------------------

- Fix blockquote termination by list item, #338.


8.3.0 / 2017-02-16
------------------

Expand Down
38 changes: 30 additions & 8 deletions lib/rules_block/blockquote.js
Expand Up @@ -10,6 +10,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
ch,
i,
initial,
isOutdented,
l,
lastLineEmpty,
lines,
Expand All @@ -25,19 +26,20 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
terminate,
terminatorRules,
token,
oldLineMax = state.lineMax,
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

// check the block quote marker
if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; }

// we know that it's going to be a valid blockquote,
// so no point trying to find the end of it in silent mode
if (silent) { return true; }

oldIndent = state.blkIndent;
state.blkIndent = 0;

// skip spaces after ">" and re-calculate offset
initial = offset = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]);

Expand Down Expand Up @@ -118,13 +120,21 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
// >
// test
// ```
// 3. another tag
// 3. another tag:
// ```
// > test
// - - -
// ```
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
if (state.sCount[nextLine] < oldIndent) { break; }
// check if it's outdented, i.e. it's inside list item and indented
// less than said list item:
//
// ```
// 1. anything
// > current blockquote
// 2. checking this line
// ```
isOutdented = state.sCount[nextLine] < state.blkIndent;

pos = state.bMarks[nextLine] + state.tShift[nextLine];
max = state.eMarks[nextLine];
Expand All @@ -134,7 +144,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
break;
}

if (state.src.charCodeAt(pos++) === 0x3E/* > */) {
if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {
// This line is inside the blockquote.

// skip spaces after ">" and re-calculate offset
Expand Down Expand Up @@ -214,20 +224,28 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
}

if (terminate) {
if (oldIndent !== 0) {
// Quirk to enforce "hard termination mode" for paragraphs;
// normally if you call `tokenize(state, startLine, nextLine)`,
// paragraphs will look below nextLine for paragraph continuation,
// but if blockquote is terminated by another tag, they shouldn't
state.lineMax = nextLine;

if (state.blkIndent !== 0) {
// state.blkIndent was non-zero, we now set it to zero,
// so we need to re-calculate all offsets to appear as
// if indent wasn't changed
oldBMarks.push(state.bMarks[nextLine]);
oldBSCount.push(state.bsCount[nextLine]);
oldTShift.push(state.tShift[nextLine]);
oldSCount.push(state.sCount[nextLine]);
state.sCount[nextLine] -= oldIndent;
state.sCount[nextLine] -= state.blkIndent;
}

break;
}

if (isOutdented) break;

oldBMarks.push(state.bMarks[nextLine]);
oldBSCount.push(state.bsCount[nextLine]);
oldTShift.push(state.tShift[nextLine]);
Expand All @@ -238,6 +256,9 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
state.sCount[nextLine] = -1;
}

oldIndent = state.blkIndent;
state.blkIndent = 0;

token = state.push('blockquote_open', 'blockquote', 1);
token.markup = '>';
token.map = lines = [ startLine, 0 ];
Expand All @@ -247,6 +268,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
token = state.push('blockquote_close', 'blockquote', -1);
token.markup = '>';

state.lineMax = oldLineMax;
state.parentType = oldParentType;
lines[1] = state.line;

Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/fence.js
Expand Up @@ -9,6 +9,9 @@ module.exports = function fence(state, startLine, endLine, silent) {
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

if (pos + 3 > max) { return false; }

marker = state.src.charCodeAt(pos);
Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/heading.js
Expand Up @@ -10,6 +10,9 @@ module.exports = function heading(state, startLine, endLine, silent) {
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

ch = state.src.charCodeAt(pos);

if (ch !== 0x23/* # */ || pos >= max) { return false; }
Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/hr.js
Expand Up @@ -10,6 +10,9 @@ module.exports = function hr(state, startLine, endLine, silent) {
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

marker = state.src.charCodeAt(pos++);

// Check hr marker
Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/html_block.js
Expand Up @@ -25,6 +25,9 @@ module.exports = function html_block(state, startLine, endLine, silent) {
pos = state.bMarks[startLine] + state.tShift[startLine],
max = state.eMarks[startLine];

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

if (!state.md.options.html) { return false; }

if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }
Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/lheading.js
Expand Up @@ -8,6 +8,9 @@ module.exports = function lheading(state, startLine, endLine/*, silent*/) {
nextLine = startLine + 1, oldParentType,
terminatorRules = state.md.block.ruler.getRules('paragraph');

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

oldParentType = state.parentType;
state.parentType = 'paragraph'; // use paragraph to match terminatorRules

Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/list.js
Expand Up @@ -129,6 +129,9 @@ module.exports = function list(state, startLine, endLine, silent) {
isTerminatingParagraph = false,
tight = true;

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

// limit conditions when list can interrupt
// a paragraph (validation mode only)
if (silent && state.parentType === 'paragraph') {
Expand Down
3 changes: 3 additions & 0 deletions lib/rules_block/reference.js
Expand Up @@ -27,6 +27,9 @@ module.exports = function reference(state, startLine, _endLine, silent) {
max = state.eMarks[startLine],
nextLine = startLine + 1;

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }

if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; }

// Simple check to quickly interrupt scan on [link](url) at the start of line.
Expand Down
43 changes: 43 additions & 0 deletions test/fixtures/markdown-it/commonmark_extras.txt
Expand Up @@ -202,6 +202,22 @@ foo2<br>
bar</p>
.

List item terminating quote should not be paragraph continuation
.
1. foo
> quote
2. bar
.
<ol>
<li>foo
<blockquote>
<p>quote</p>
</blockquote>
</li>
<li>bar</li>
</ol>
.

Coverage. Directive can terminate paragraph.
.
a
Expand Down Expand Up @@ -441,3 +457,30 @@ Coverage. Tabs in lists.
</li>
</ol>
.

Coverage. Various tags not interrupting blockquotes because of indentation:
.
> foo
- - - -

> foo
# not a heading

> foo
```
not a fence
```
.
<blockquote>
<p>foo
- - - -</p>
</blockquote>
<blockquote>
<p>foo
# not a heading</p>
</blockquote>
<blockquote>
<p>foo
<code>not a fence</code></p>
</blockquote>
.

0 comments on commit c57f593

Please sign in to comment.