Alex Kocharin
10 years ago
5 changed files with 373 additions and 0 deletions
@ -0,0 +1,207 @@ |
|||||
|
// 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; |
||||
|
}; |
@ -0,0 +1,144 @@ |
|||||
|
|
||||
|
Pandoc (with slightly changed indents): |
||||
|
|
||||
|
. |
||||
|
Term 1 |
||||
|
|
||||
|
: Definition 1 |
||||
|
|
||||
|
Term 2 with *inline markup* |
||||
|
|
||||
|
: Definition 2 |
||||
|
|
||||
|
{ some code, part of Definition 2 } |
||||
|
|
||||
|
Third paragraph of definition 2. |
||||
|
. |
||||
|
<dl> |
||||
|
<dt>Term 1</dt> |
||||
|
<dd><p>Definition 1</p> |
||||
|
</dd> |
||||
|
<dt>Term 2 with <em>inline markup</em></dt> |
||||
|
<dd><p>Definition 2</p> |
||||
|
<pre><code>{ some code, part of Definition 2 } |
||||
|
</code></pre> |
||||
|
<p>Third paragraph of definition 2.</p> |
||||
|
</dd> |
||||
|
</dl> |
||||
|
. |
||||
|
|
||||
|
Pandoc again: |
||||
|
|
||||
|
. |
||||
|
Term 1 |
||||
|
|
||||
|
: Definition |
||||
|
with lazy continuation. |
||||
|
|
||||
|
Second paragraph of the definition. |
||||
|
. |
||||
|
<dl> |
||||
|
<dt>Term 1</dt> |
||||
|
<dd><p>Definition |
||||
|
with lazy continuation.</p> |
||||
|
<p>Second paragraph of the definition.</p> |
||||
|
</dd> |
||||
|
</dl> |
||||
|
. |
||||
|
|
||||
|
Well, I might just copy-paste the third one while I'm at it: |
||||
|
|
||||
|
. |
||||
|
Term 1 |
||||
|
~ Definition 1 |
||||
|
|
||||
|
Term 2 |
||||
|
~ Definition 2a |
||||
|
~ Definition 2b |
||||
|
. |
||||
|
<dl> |
||||
|
<dt>Term 1</dt> |
||||
|
<dd>Definition 1 |
||||
|
</dd> |
||||
|
<dt>Term 2</dt> |
||||
|
<dd>Definition 2a |
||||
|
</dd> |
||||
|
<dd>Definition 2b |
||||
|
</dd> |
||||
|
</dl> |
||||
|
. |
||||
|
|
||||
|
Now, with our custom ones. Spaces after a colon: |
||||
|
|
||||
|
. |
||||
|
Term 1 |
||||
|
: paragraph |
||||
|
|
||||
|
Term 2 |
||||
|
: code block |
||||
|
. |
||||
|
<dl> |
||||
|
<dt>Term 1</dt> |
||||
|
<dd>paragraph |
||||
|
</dd> |
||||
|
<dt>Term 2</dt> |
||||
|
<dd><pre><code>code block |
||||
|
</code></pre> |
||||
|
</dd> |
||||
|
</dl> |
||||
|
. |
||||
|
|
||||
|
There should be something after a colon by the way: |
||||
|
|
||||
|
. |
||||
|
Non-term 1 |
||||
|
: |
||||
|
|
||||
|
Non-term 2 |
||||
|
: |
||||
|
. |
||||
|
<p>Non-term 1 |
||||
|
:</p> |
||||
|
<p>Non-term 2 |
||||
|
:</p> |
||||
|
. |
||||
|
|
||||
|
Definition lists should be second last in the queue. Exemplī grātiā, this isn't a valid one: |
||||
|
|
||||
|
. |
||||
|
# test |
||||
|
: just a paragraph with a colon |
||||
|
. |
||||
|
<h1>test</h1> |
||||
|
<p>: just a paragraph with a colon</p> |
||||
|
. |
||||
|
|
||||
|
Nested definition lists: |
||||
|
|
||||
|
. |
||||
|
test |
||||
|
: foo |
||||
|
: bar |
||||
|
: baz |
||||
|
: bar |
||||
|
: foo |
||||
|
. |
||||
|
<dl> |
||||
|
<dt>test</dt> |
||||
|
<dd><dl> |
||||
|
<dt>foo</dt> |
||||
|
<dd><dl> |
||||
|
<dt>bar</dt> |
||||
|
<dd>baz |
||||
|
</dd> |
||||
|
</dl> |
||||
|
</dd> |
||||
|
<dd>bar |
||||
|
</dd> |
||||
|
</dl> |
||||
|
</dd> |
||||
|
<dd>foo |
||||
|
</dd> |
||||
|
</dl> |
||||
|
. |
||||
|
|
Loading…
Reference in new issue