Browse Source

Fix lists and headings

pull/293/head
Alex Kocharin 8 years ago
parent
commit
1ecf143db0
  1. 3
      lib/parser_block.js
  2. 6
      lib/rules_block/blockquote.js
  3. 12
      lib/rules_block/code.js
  4. 2
      lib/rules_block/heading.js
  5. 7
      lib/rules_block/lheading.js
  6. 13
      lib/rules_block/list.js
  7. 7
      lib/rules_block/paragraph.js
  8. 6
      lib/rules_block/reference.js
  9. 5
      lib/rules_block/state_block.js
  10. 158
      test/fixtures/commonmark/bad.txt
  11. 100
      test/fixtures/commonmark/good.txt

3
lib/parser_block.js

@ -94,9 +94,6 @@ ParserBlock.prototype.tokenize = function (state, startLine, endLine) {
if (line < endLine && state.isEmpty(line)) { if (line < endLine && state.isEmpty(line)) {
hasEmptyLines = true; hasEmptyLines = true;
line++; line++;
// two empty lines should stop the parser in list mode
if (line < endLine && state.parentType === 'list' && state.isEmpty(line)) { break; }
state.line = line; state.line = line;
} }
} }

6
lib/rules_block/blockquote.js

@ -57,6 +57,9 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
terminatorRules = state.md.block.ruler.getRules('blockquote'); terminatorRules = state.md.block.ruler.getRules('blockquote');
oldParentType = state.parentType;
state.parentType = 'blockquote';
// Search the end of the block // Search the end of the block
// //
// Block ends with either: // Block ends with either:
@ -146,9 +149,6 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
state.sCount[nextLine] = -1; state.sCount[nextLine] = -1;
} }
oldParentType = state.parentType;
state.parentType = 'blockquote';
token = state.push('blockquote_open', 'blockquote', 1); token = state.push('blockquote_open', 'blockquote', 1);
token.markup = '>'; token.markup = '>';
token.map = lines = [ startLine, 0 ]; token.map = lines = [ startLine, 0 ];

12
lib/rules_block/code.js

@ -4,7 +4,7 @@
module.exports = function code(state, startLine, endLine/*, silent*/) { module.exports = function code(state, startLine, endLine/*, silent*/) {
var nextLine, last, token, emptyLines = 0; var nextLine, last, token;
if (state.sCount[startLine] - state.blkIndent < 4) { return false; } if (state.sCount[startLine] - state.blkIndent < 4) { return false; }
@ -12,20 +12,10 @@ module.exports = function code(state, startLine, endLine/*, silent*/) {
while (nextLine < endLine) { while (nextLine < endLine) {
if (state.isEmpty(nextLine)) { if (state.isEmpty(nextLine)) {
emptyLines++;
// workaround for lists: 2 blank lines should terminate indented
// code block, but not fenced code block
if (emptyLines >= 2 && state.parentType === 'list') {
break;
}
nextLine++; nextLine++;
continue; continue;
} }
emptyLines = 0;
if (state.sCount[nextLine] - state.blkIndent >= 4) { if (state.sCount[nextLine] - state.blkIndent >= 4) {
nextLine++; nextLine++;
last = nextLine; last = nextLine;

2
lib/rules_block/heading.js

@ -22,7 +22,7 @@ module.exports = function heading(state, startLine, endLine, silent) {
ch = state.src.charCodeAt(++pos); ch = state.src.charCodeAt(++pos);
} }
if (level > 6 || (pos < max && ch !== 0x20/* space */)) { return false; } if (level > 6 || (pos < max && !isSpace(ch))) { return false; }
if (silent) { return true; } if (silent) { return true; }

7
lib/rules_block/lheading.js

@ -5,9 +5,12 @@
module.exports = function lheading(state, startLine, endLine/*, silent*/) { module.exports = function lheading(state, startLine, endLine/*, silent*/) {
var content, terminate, i, l, token, pos, max, level, marker, var content, terminate, i, l, token, pos, max, level, marker,
nextLine = startLine + 1, nextLine = startLine + 1, oldParentType,
terminatorRules = state.md.block.ruler.getRules('paragraph'); terminatorRules = state.md.block.ruler.getRules('paragraph');
oldParentType = state.parentType;
state.parentType = 'paragraph'; // use paragraph to match terminatorRules
// jump line-by-line until empty one or EOF // jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
// this would be a code block normally, but after paragraph // this would be a code block normally, but after paragraph
@ -71,5 +74,7 @@ module.exports = function lheading(state, startLine, endLine/*, silent*/) {
token = state.push('heading_close', 'h' + String(level), -1); token = state.push('heading_close', 'h' + String(level), -1);
token.markup = String.fromCharCode(marker); token.markup = String.fromCharCode(marker);
state.parentType = oldParentType;
return true; return true;
}; };

13
lib/rules_block/list.js

@ -147,7 +147,6 @@ module.exports = function list(state, startLine, endLine, silent) {
if (isOrdered) { if (isOrdered) {
start = state.bMarks[startLine] + state.tShift[startLine]; start = state.bMarks[startLine] + state.tShift[startLine];
markerValue = Number(state.src.substr(start, posAfterMarker - start - 1)); markerValue = Number(state.src.substr(start, posAfterMarker - start - 1));
token = state.push('ordered_list_open', 'ol', 1); token = state.push('ordered_list_open', 'ol', 1);
if (markerValue !== 1) { if (markerValue !== 1) {
token.attrs = [ [ 'start', markerValue ] ]; token.attrs = [ [ 'start', markerValue ] ];
@ -168,6 +167,9 @@ module.exports = function list(state, startLine, endLine, silent) {
prevEmptyEnd = false; prevEmptyEnd = false;
terminatorRules = state.md.block.ruler.getRules('list'); terminatorRules = state.md.block.ruler.getRules('list');
oldParentType = state.parentType;
state.parentType = 'list';
while (nextLine < endLine) { while (nextLine < endLine) {
pos = posAfterMarker; pos = posAfterMarker;
max = state.eMarks[nextLine]; max = state.eMarks[nextLine];
@ -216,10 +218,8 @@ module.exports = function list(state, startLine, endLine, silent) {
oldTight = state.tight; oldTight = state.tight;
oldTShift = state.tShift[startLine]; oldTShift = state.tShift[startLine];
oldLIndent = state.sCount[startLine]; oldLIndent = state.sCount[startLine];
oldParentType = state.parentType;
state.blkIndent = indent; state.blkIndent = indent;
state.tight = true; state.tight = true;
state.parentType = 'list';
state.tShift[startLine] = contentStart - state.bMarks[startLine]; state.tShift[startLine] = contentStart - state.bMarks[startLine];
state.sCount[startLine] = offset; state.sCount[startLine] = offset;
@ -248,7 +248,6 @@ module.exports = function list(state, startLine, endLine, silent) {
state.tShift[startLine] = oldTShift; state.tShift[startLine] = oldTShift;
state.sCount[startLine] = oldLIndent; state.sCount[startLine] = oldLIndent;
state.tight = oldTight; state.tight = oldTight;
state.parentType = oldParentType;
token = state.push('list_item_close', 'li', -1); token = state.push('list_item_close', 'li', -1);
token.markup = String.fromCharCode(markerCharCode); token.markup = String.fromCharCode(markerCharCode);
@ -259,10 +258,6 @@ module.exports = function list(state, startLine, endLine, silent) {
if (nextLine >= endLine) { break; } if (nextLine >= endLine) { break; }
if (state.isEmpty(nextLine)) {
break;
}
// //
// Try to check if list is terminated or continued. // Try to check if list is terminated or continued.
// //
@ -301,6 +296,8 @@ module.exports = function list(state, startLine, endLine, silent) {
listLines[1] = nextLine; listLines[1] = nextLine;
state.line = nextLine; state.line = nextLine;
state.parentType = oldParentType;
// mark paragraphs tight if needed // mark paragraphs tight if needed
if (tight) { if (tight) {
markTightParagraphs(state, listTokIdx); markTightParagraphs(state, listTokIdx);

7
lib/rules_block/paragraph.js

@ -4,11 +4,14 @@
module.exports = function paragraph(state, startLine/*, endLine*/) { module.exports = function paragraph(state, startLine/*, endLine*/) {
var content, terminate, i, l, token, var content, terminate, i, l, token, oldParentType,
nextLine = startLine + 1, nextLine = startLine + 1,
terminatorRules = state.md.block.ruler.getRules('paragraph'), terminatorRules = state.md.block.ruler.getRules('paragraph'),
endLine = state.lineMax; endLine = state.lineMax;
oldParentType = state.parentType;
state.parentType = 'paragraph';
// jump line-by-line until empty one or EOF // jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
// this would be a code block normally, but after paragraph // this would be a code block normally, but after paragraph
@ -43,5 +46,7 @@ module.exports = function paragraph(state, startLine/*, endLine*/) {
token = state.push('paragraph_close', 'p', -1); token = state.push('paragraph_close', 'p', -1);
state.parentType = oldParentType;
return true; return true;
}; };

6
lib/rules_block/reference.js

@ -17,6 +17,7 @@ module.exports = function reference(state, startLine, _endLine, silent) {
l, l,
label, label,
labelEnd, labelEnd,
oldParentType,
res, res,
start, start,
str, str,
@ -46,6 +47,9 @@ module.exports = function reference(state, startLine, _endLine, silent) {
// jump line-by-line until empty one or EOF // jump line-by-line until empty one or EOF
terminatorRules = state.md.block.ruler.getRules('reference'); terminatorRules = state.md.block.ruler.getRules('reference');
oldParentType = state.parentType;
state.parentType = 'reference';
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
// this would be a code block normally, but after paragraph // this would be a code block normally, but after paragraph
// it's considered a lazy continuation regardless of what's there // it's considered a lazy continuation regardless of what's there
@ -186,6 +190,8 @@ module.exports = function reference(state, startLine, _endLine, silent) {
state.env.references[label] = { title: title, href: href }; state.env.references[label] = { title: title, href: href };
} }
state.parentType = oldParentType;
state.line = startLine + lines + 1; state.line = startLine + lines + 1;
return true; return true;
}; };

5
lib/rules_block/state_block.js

@ -33,9 +33,12 @@ function StateBlock(src, md, env, tokens) {
this.line = 0; // line index in src this.line = 0; // line index in src
this.lineMax = 0; // lines count this.lineMax = 0; // lines count
this.tight = false; // loose/tight mode for lists this.tight = false; // loose/tight mode for lists
this.parentType = 'root'; // if `list`, block parser stops on two newlines
this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any) this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any)
// can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'
// used in lists to determine if they interrupt a paragraph
this.parentType = 'root';
this.level = 0; this.level = 0;
// renderer // renderer

158
test/fixtures/commonmark/bad.txt

@ -18,81 +18,6 @@ error:
</blockquote> </blockquote>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 458
.
# Foo
.
<h1>Foo</h1>
.
error:
<p># Foo</p>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3821
.
- foo
bar
.
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>
.
error:
<ul>
<li>foo</li>
</ul>
<p>bar</p>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3866
.
- Foo
bar
baz
.
<ul>
<li>
<p>Foo</p>
<pre><code>bar
baz
</code></pre>
</li>
</ul>
.
error:
<ul>
<li>
<p>Foo</p>
<pre><code>bar
</code></pre>
</li>
</ul>
<pre><code> baz
</code></pre>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4214 src line: 4214
@ -140,89 +65,6 @@ error:
</ol> </ol>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4890
.
- foo
- bar
- baz
.
<ul>
<li>
<p>foo</p>
</li>
<li>
<p>bar</p>
</li>
<li>
<p>baz</p>
</li>
</ul>
.
error:
<ul>
<li>
<p>foo</p>
</li>
<li>
<p>bar</p>
</li>
</ul>
<ul>
<li>baz</li>
</ul>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4911
.
- foo
- bar
- baz
bim
.
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>
<p>baz</p>
<p>bim</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
.
error:
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>baz</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code> bim
</code></pre>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 6137 src line: 6137

100
test/fixtures/commonmark/good.txt

@ -110,6 +110,15 @@ src line: 440
</ul> </ul>
. .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 458
.
# Foo
.
<h1>Foo</h1>
.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 464 src line: 464
@ -3003,6 +3012,23 @@ src line: 3808
<p>2.two</p> <p>2.two</p>
. .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3821
.
- foo
bar
.
<ul>
<li>
<p>foo</p>
<p>bar</p>
</li>
</ul>
.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3838 src line: 3838
@ -3030,6 +3056,29 @@ src line: 3838
</ol> </ol>
. .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3866
.
- Foo
bar
baz
.
<ul>
<li>
<p>Foo</p>
<pre><code>bar
baz
</code></pre>
</li>
</ul>
.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 3888 src line: 3888
@ -3680,6 +3729,57 @@ The number of windows in my house is
</ol> </ol>
. .
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4890
.
- foo
- bar
- baz
.
<ul>
<li>
<p>foo</p>
</li>
<li>
<p>bar</p>
</li>
<li>
<p>baz</p>
</li>
</ul>
.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4911
.
- foo
- bar
- baz
bim
.
<ul>
<li>foo
<ul>
<li>bar
<ul>
<li>
<p>baz</p>
<p>bim</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src line: 4941 src line: 4941

Loading…
Cancel
Save