Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed
https://markdown-it.github.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
5.0 KiB
208 lines
5.0 KiB
10 years ago
|
// Definition lists
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
|
||
|
// Search `[:~][\n ]`, returns next pos after marker on success
|
||
|
// or -1 on fail.
|
||
|
function skipMarker(state, line) {
|
||
|
var pos, marker,
|
||
|
start = state.bMarks[line] + state.tShift[line],
|
||
|
max = state.eMarks[line];
|
||
|
|
||
|
if (start >= max) { return -1; }
|
||
|
|
||
|
// Check bullet
|
||
|
marker = state.src.charCodeAt(start++);
|
||
|
if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1; }
|
||
|
|
||
|
pos = state.skipSpaces(start);
|
||
|
|
||
|
// require space after ":"
|
||
|
if (start === pos) { return -1; }
|
||
|
|
||
|
// no empty definitions, e.g. " : "
|
||
|
if (pos >= max) { return -1; }
|
||
|
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
function markTightParagraphs(state, idx) {
|
||
|
var i, l,
|
||
|
level = state.level + 2;
|
||
|
|
||
|
for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
|
||
|
if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {
|
||
|
state.tokens[i + 2].tight = true;
|
||
|
state.tokens[i].tight = true;
|
||
|
i += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = function deflist(state, startLine, endLine, silent) {
|
||
|
var contentStart,
|
||
|
ddLine,
|
||
|
dtLine,
|
||
|
itemLines,
|
||
|
listLines,
|
||
|
listTokIdx,
|
||
|
nextLine,
|
||
|
oldIndent,
|
||
|
oldDDIndent,
|
||
|
oldParentType,
|
||
|
oldTShift,
|
||
|
oldTight,
|
||
|
prevEmptyEnd,
|
||
|
tight;
|
||
|
|
||
|
if (silent) {
|
||
|
// quirk: validation mode validates a dd block only, not a whole deflist
|
||
|
if (state.ddIndent < 0) { return false; }
|
||
|
return skipMarker(state, startLine) >= 0;
|
||
|
}
|
||
|
|
||
|
nextLine = startLine + 1;
|
||
|
if (state.isEmpty(nextLine)) {
|
||
|
if (++nextLine > endLine) { return false; }
|
||
|
}
|
||
|
|
||
|
if (state.tShift[nextLine] < state.blkIndent) { return false; }
|
||
|
contentStart = skipMarker(state, nextLine);
|
||
|
if (contentStart < 0) { return false; }
|
||
|
|
||
|
if (state.level >= state.options.maxNesting) { return false; }
|
||
|
|
||
|
// Start list
|
||
|
listTokIdx = state.tokens.length;
|
||
|
|
||
|
state.tokens.push({
|
||
|
type: 'dl_open',
|
||
|
lines: listLines = [ startLine, 0 ],
|
||
|
level: state.level++
|
||
|
});
|
||
|
|
||
|
//
|
||
|
// Iterate list items
|
||
|
//
|
||
|
|
||
|
dtLine = startLine;
|
||
|
ddLine = nextLine;
|
||
|
|
||
|
// One definition list can contain multiple DTs,
|
||
|
// and one DT can be followed by multiple DDs.
|
||
|
//
|
||
|
// Thus, there is two loops here, and label is
|
||
|
// needed to break out of the second one
|
||
|
//
|
||
|
/*eslint no-labels:0,block-scoped-var:0*/
|
||
|
OUTER:
|
||
|
for (;;) {
|
||
|
tight = true;
|
||
|
prevEmptyEnd = false;
|
||
|
|
||
|
state.tokens.push({
|
||
|
type: 'dt_open',
|
||
|
lines: [ dtLine, dtLine ],
|
||
|
level: state.level++
|
||
|
});
|
||
|
state.tokens.push({
|
||
|
type: 'inline',
|
||
|
content: state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim(),
|
||
|
level: state.level + 1,
|
||
|
lines: [ dtLine, dtLine ],
|
||
|
children: []
|
||
|
});
|
||
|
state.tokens.push({
|
||
|
type: 'dt_close',
|
||
|
level: --state.level
|
||
|
});
|
||
|
|
||
|
for (;;) {
|
||
|
state.tokens.push({
|
||
|
type: 'dd_open',
|
||
|
lines: itemLines = [ nextLine, 0 ],
|
||
|
level: state.level++
|
||
|
});
|
||
|
|
||
|
oldTight = state.tight;
|
||
|
oldDDIndent = state.ddIndent;
|
||
|
oldIndent = state.blkIndent;
|
||
|
oldTShift = state.tShift[ddLine];
|
||
|
oldParentType = state.parentType;
|
||
|
state.blkIndent = state.ddIndent = state.tShift[ddLine] + 2;
|
||
|
state.tShift[ddLine] = contentStart - state.bMarks[ddLine];
|
||
|
state.tight = true;
|
||
|
state.parentType = 'deflist';
|
||
|
|
||
|
state.parser.tokenize(state, ddLine, endLine, true);
|
||
|
|
||
|
// If any of list item is tight, mark list as tight
|
||
|
if (!state.tight || prevEmptyEnd) {
|
||
|
tight = false;
|
||
|
}
|
||
|
// Item become loose if finish with empty line,
|
||
|
// but we should filter last element, because it means list finish
|
||
|
prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1);
|
||
|
|
||
|
state.tShift[ddLine] = oldTShift;
|
||
|
state.tight = oldTight;
|
||
|
state.parentType = oldParentType;
|
||
|
state.blkIndent = oldIndent;
|
||
|
state.ddIndent = oldDDIndent;
|
||
|
|
||
|
state.tokens.push({
|
||
|
type: 'dd_close',
|
||
|
level: --state.level
|
||
|
});
|
||
|
|
||
|
itemLines[1] = nextLine = state.line;
|
||
|
|
||
|
if (nextLine >= endLine) { break OUTER; }
|
||
|
|
||
|
if (state.tShift[nextLine] < state.blkIndent) { break OUTER; }
|
||
|
contentStart = skipMarker(state, nextLine);
|
||
|
if (contentStart < 0) { break; }
|
||
|
|
||
|
ddLine = nextLine;
|
||
|
|
||
|
// go to the next loop iteration:
|
||
|
// insert DD tag and repeat checking
|
||
|
}
|
||
|
|
||
|
if (nextLine >= endLine) { break; }
|
||
|
dtLine = nextLine;
|
||
|
|
||
|
if (state.isEmpty(dtLine)) { break; }
|
||
|
if (state.tShift[dtLine] < state.blkIndent) { break; }
|
||
|
|
||
|
ddLine = dtLine + 1;
|
||
|
if (ddLine >= endLine) { break; }
|
||
|
if (state.isEmpty(ddLine)) { ddLine++; }
|
||
|
if (ddLine >= endLine) { break; }
|
||
|
|
||
|
if (state.tShift[ddLine] < state.blkIndent) { break; }
|
||
|
contentStart = skipMarker(state, ddLine);
|
||
|
if (contentStart < 0) { break; }
|
||
|
|
||
|
// go to the next loop iteration:
|
||
|
// insert DT and DD tags and repeat checking
|
||
|
}
|
||
|
|
||
|
// Finilize list
|
||
|
state.tokens.push({
|
||
|
type: 'dl_close',
|
||
|
level: --state.level
|
||
|
});
|
||
|
listLines[1] = nextLine;
|
||
|
|
||
|
state.line = nextLine;
|
||
|
|
||
|
// mark paragraphs tight if needed
|
||
|
if (tight) {
|
||
|
markTightParagraphs(state, listTokIdx);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
};
|