Browse Source

Fix backtick algorithm

now it more closely matches one in `cmark`
pull/745/head
Alex Kocharin 4 years ago
parent
commit
fece91e265
  1. 51
      lib/rules_inline/backticks.js
  2. 1
      lib/rules_inline/state_inline.js
  3. 8
      test/fixtures/markdown-it/commonmark_extras.txt

51
lib/rules_inline/backticks.js

@ -3,17 +3,8 @@
'use strict';
function addCodeToken(state, marker, pos, matchStart) {
var token = state.push('code_inline', 'code', 0);
token.markup = marker;
token.content = state.src.slice(pos, matchStart)
.replace(/\n/g, ' ')
.replace(/^ (.+) $/, '$1');
}
module.exports = function backtick(state, silent) {
var start, max, marker, matchStart, matchEnd, startLength, endLength,
var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength,
pos = state.pos,
ch = state.src.charCodeAt(pos);
@ -27,17 +18,11 @@ module.exports = function backtick(state, silent) {
while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; }
marker = state.src.slice(start, pos);
startLength = marker.length;
// Look for required marker length in the cache first
if (state.backticks[startLength] && state.backticks[startLength] > start) {
if (state.backticks[startLength] === Infinity) {
if (!silent) state.pending += marker;
state.pos += startLength;
} else {
if (!silent) addCodeToken(state, marker, pos, state.backticks[startLength]);
state.pos = matchEnd;
}
openerLength = marker.length;
if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {
if (!silent) state.pending += marker;
state.pos += openerLength;
return true;
}
@ -50,27 +35,31 @@ module.exports = function backtick(state, silent) {
// scan marker length
while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; }
endLength = matchEnd - matchStart;
closerLength = matchEnd - matchStart;
if (endLength === marker.length) {
if (closerLength === openerLength) {
// Found matching closer length.
if (!silent) addCodeToken(state, marker, pos, matchStart);
if (!silent) {
token = state.push('code_inline', 'code', 0);
token.markup = marker;
token.content = state.src.slice(pos, matchStart)
.replace(/\n/g, ' ')
.replace(/^ (.+) $/, '$1');
}
state.pos = matchEnd;
return true;
}
// Some different length found, put it in cache just in case
if (!state.backticks[endLength] || state.backticks[endLength] <= start) {
state.backticks[endLength] = matchStart;
}
// Some different length found, put it in cache as upper limit of where closer can be found
state.backticks[closerLength] = matchStart;
// Scanned through the end, didn't find anything. Mark "no matches" for this length;
// Scanned through the end, didn't find anything
if (matchEnd >= max) {
state.backticks[startLength] = Infinity;
state.backticksScanned = true;
}
}
if (!silent) state.pending += marker;
state.pos += startLength;
state.pos += openerLength;
return true;
};

1
lib/rules_inline/state_inline.js

@ -34,6 +34,7 @@ function StateInline(src, md, env, outTokens) {
// backtick length => last seen position
this.backticks = {};
this.backticksScanned = false;
}

8
test/fixtures/markdown-it/commonmark_extras.txt

@ -304,6 +304,14 @@ Coverage. Unpaired nested backtick (silent mode)
.
Coverage. Should continue scanning after closing "```" despite cache
.
```aaa``bbb``ccc```ddd``eee``
.
<p><code>aaa``bbb``ccc</code>ddd<code>eee</code></p>
.
Coverage. Entities.
.
*&*

Loading…
Cancel
Save