Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix list tightness. #269

Merged
merged 1 commit into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 77 additions & 68 deletions lib/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,10 @@ var peek = function(ln, pos) {

// These are methods of a Parser object, defined below.

// Returns true if block ends with a blank line, descending if needed
// into lists and sublists.
// Returns true if block ends with a blank line.
var endsWithBlankLine = function(block) {
while (block) {
if (block._lastLineBlank) {
return true;
}
var t = block.type;
if (!block._lastLineChecked && (t === "list" || t === "item")) {
block._lastLineChecked = true;
block = block._lastChild;
} else {
block._lastLineChecked = true;
break;
}
}
return false;
return block.next &&
block.sourcepos[1][0] !== block.next.sourcepos[0][0] - 1;
};

// Add a line to the block at the tip. We assume the tip
Expand Down Expand Up @@ -221,6 +208,50 @@ var closeUnmatchedBlocks = function() {
}
};

// Remove link reference definitions from given tree.
var removeLinkReferenceDefinitions = function(parser, tree) {
var event, node;
var walker = tree.walker();
var emptyNodes = [];

while ((event = walker.next())) {
node = event.node;
if (event.entering && node.type === "paragraph") {
var pos;
var hasReferenceDefs = false;

// Try parsing the beginning as link reference definitions;
// Note that link reference definitions must be the beginning of a
// paragraph node since link reference definitions cannot interrupt
// paragraphs.
while (
peek(node._string_content, 0) === C_OPEN_BRACKET &&
(pos = parser.inlineParser.parseReference(
node._string_content,
parser.refmap
))
) {
const removedText = node._string_content.slice(0, pos);

node._string_content = node._string_content.slice(pos);
hasReferenceDefs = true;

const lines = removedText.split("\n");

// -1 for final newline.
node.sourcepos[0][0] += lines.length - 1;
}
if (hasReferenceDefs && isBlank(node._string_content)) {
emptyNodes.push(node);
}
}
}

for (node of emptyNodes) {
node.unlink();
}
};

// 'finalize' is run when the block is closed.
// 'continue' is run to check whether the block is continuing
// at a certain line and offset (e.g. whether a block quote
Expand All @@ -231,7 +262,8 @@ var blocks = {
continue: function() {
return 0;
},
finalize: function() {
finalize: function(parser, block) {
removeLinkReferenceDefinitions(parser, block);
return;
},
canContain: function(t) {
Expand All @@ -247,7 +279,7 @@ var blocks = {
var item = block._firstChild;
while (item) {
// check for non-final list item ending with blank line:
if (endsWithBlankLine(item) && item._next) {
if (item._next && endsWithBlankLine(item)) {
block._listData.tight = false;
break;
}
Expand All @@ -256,8 +288,8 @@ var blocks = {
var subitem = item._firstChild;
while (subitem) {
if (
endsWithBlankLine(subitem) &&
(item._next || subitem._next)
subitem._next &&
endsWithBlankLine(subitem)
) {
block._listData.tight = false;
break;
Expand All @@ -266,6 +298,7 @@ var blocks = {
}
item = item._next;
}
block.sourcepos[1] = block._lastChild.sourcepos[1];
},
canContain: function(t) {
return t === "item";
Expand Down Expand Up @@ -320,7 +353,16 @@ var blocks = {
}
return 0;
},
finalize: function() {
finalize: function(parser, block) {
if (block._lastChild) {
block.sourcepos[1] = block._lastChild.sourcepos[1];
} else {
// Empty list item
block.sourcepos[1][0] = block.sourcepos[0][0];
block.sourcepos[1][1] =
block._listData.markerOffset + block._listData.padding;
}

return;
},
canContain: function(t) {
Expand Down Expand Up @@ -402,10 +444,17 @@ var blocks = {
block._literal = rest;
} else {
// indented
block._literal = block._string_content.replace(
/(\n *)+$/,
"\n"
);
var lines = block._string_content.split("\n");
// Note that indented code block cannot be empty, so
// lines.length cannot be zero.
while (/^[ \t]*$/.test(lines[lines.length - 1])) {
lines.pop();
}
block._literal = lines.join("\n") + "\n";
block.sourcepos[1][0] =
block.sourcepos[0][0] + lines.length - 1;
block.sourcepos[1][1] =
block.sourcepos[0][1] + lines[lines.length - 1].length - 1;
}
block._string_content = null; // allow GC
},
Expand All @@ -423,7 +472,7 @@ var blocks = {
: 0;
},
finalize: function(parser, block) {
block._literal = block._string_content.replace(/(\n *)+$/, "");
block._literal = block._string_content.replace(/\n$/, '');
block._string_content = null; // allow GC
},
canContain: function() {
Expand All @@ -435,24 +484,8 @@ var blocks = {
continue: function(parser) {
return parser.blank ? 1 : 0;
},
finalize: function(parser, block) {
var pos;
var hasReferenceDefs = false;

// try parsing the beginning as link reference definitions:
while (
peek(block._string_content, 0) === C_OPEN_BRACKET &&
(pos = parser.inlineParser.parseReference(
block._string_content,
parser.refmap
))
) {
block._string_content = block._string_content.slice(pos);
hasReferenceDefs = true;
}
if (hasReferenceDefs && isBlank(block._string_content)) {
block.unlink();
}
finalize: function() {
return;
},
canContain: function() {
return false;
Expand Down Expand Up @@ -835,33 +868,9 @@ var incorporateLine = function(ln) {

// finalize any blocks not matched
this.closeUnmatchedBlocks();
if (this.blank && container.lastChild) {
container.lastChild._lastLineBlank = true;
}

t = container.type;

// Block quote lines are never blank as they start with >
// and we don't count blanks in fenced code for purposes of tight/loose
// lists or breaking out of lists. We also don't set _lastLineBlank
// on an empty list item, or if we just closed a fenced block.
var lastLineBlank =
this.blank &&
!(
t === "block_quote" ||
(t === "code_block" && container._isFenced) ||
(t === "item" &&
!container._firstChild &&
container.sourcepos[0][0] === this.lineNumber)
);

// propagate lastLineBlank up through parents:
var cont = container;
while (cont) {
cont._lastLineBlank = lastLineBlank;
cont = cont._parent;
}

if (this.blocks[t].acceptsLines) {
this.addLine();
// if HtmlBlock, check for end condition
Expand Down
2 changes: 0 additions & 2 deletions lib/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ var Node = function(nodeType, sourcepos) {
this._prev = null;
this._next = null;
this._sourcepos = sourcepos;
this._lastLineBlank = false;
this._lastLineChecked = false;
this._open = true;
this._string_content = null;
this._literal = null;
Expand Down
Loading
Loading