|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
|
|
// parse sequence of markers,
|
|
|
|
// "start" should point at a valid marker
|
|
|
|
function scanDelims(state, start) {
|
|
|
|
var pos = start, lastChar, nextChar, count,
|
|
|
|
can_open = true,
|
|
|
|
can_close = true,
|
|
|
|
max = state.posMax,
|
|
|
|
marker = state.src.charCodeAt(start);
|
|
|
|
|
|
|
|
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1;
|
|
|
|
|
|
|
|
while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; }
|
|
|
|
if (pos >= max) { can_open = false; }
|
|
|
|
count = pos - start;
|
|
|
|
|
|
|
|
nextChar = pos < max ? state.src.charCodeAt(pos) : -1;
|
|
|
|
|
|
|
|
// check whitespace conditions
|
|
|
|
if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; }
|
|
|
|
if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; }
|
|
|
|
|
|
|
|
return {
|
|
|
|
can_open: can_open,
|
|
|
|
can_close: can_close,
|
|
|
|
delims: count
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = function(state, silent) {
|
|
|
|
var startCount,
|
|
|
|
count,
|
|
|
|
tagCount,
|
|
|
|
found,
|
|
|
|
stack,
|
|
|
|
res,
|
|
|
|
max = state.posMax,
|
|
|
|
start = state.pos,
|
|
|
|
marker = state.src.charCodeAt(start);
|
|
|
|
|
|
|
|
if (marker !== 0x7E/* ~ */) { return false; }
|
|
|
|
if (silent) { return false; } // don't run any pairs in validation mode
|
|
|
|
|
|
|
|
res = scanDelims(state, start);
|
|
|
|
startCount = res.delims;
|
|
|
|
if (!res.can_open) {
|
|
|
|
state.pos += startCount;
|
|
|
|
if (!silent) { state.pending += state.src.slice(start, state.pos); }
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.level >= state.options.maxNesting) { return false; }
|
|
|
|
stack = Math.floor(startCount / 2);
|
|
|
|
if (stack <= 0) { return false; }
|
|
|
|
state.pos = start + startCount;
|
|
|
|
|
|
|
|
while (state.pos < max) {
|
|
|
|
if (state.src.charCodeAt(state.pos) === marker) {
|
|
|
|
res = scanDelims(state, state.pos);
|
|
|
|
count = res.delims;
|
|
|
|
tagCount = Math.floor(count / 2);
|
|
|
|
if (res.can_close) {
|
|
|
|
if (tagCount >= stack) {
|
|
|
|
state.pos += count - 2;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
stack -= tagCount;
|
|
|
|
state.pos += count;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res.can_open) { stack += tagCount; }
|
|
|
|
state.pos += count;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
state.parser.skipToken(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
// parser failed to find ending tag, so it's not valid emphasis
|
|
|
|
state.pos = start;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// found!
|
|
|
|
state.posMax = state.pos;
|
|
|
|
state.pos = start + 2;
|
|
|
|
|
|
|
|
if (!silent) {
|
|
|
|
state.push({ type: 'del_open', level: state.level++ });
|
|
|
|
state.parser.tokenize(state);
|
|
|
|
state.push({ type: 'del_close', level: --state.level });
|
|
|
|
}
|
|
|
|
|
|
|
|
state.pos = state.posMax + 2;
|
|
|
|
state.posMax = max;
|
|
|
|
return true;
|
|
|
|
};
|