Browse Source

Fix spaces in subscript and superscript

pull/14/head
Alex Kocharin 10 years ago
parent
commit
74602dba90
  1. 14
      lib/renderer.js
  2. 4
      lib/rules_inline/del.js
  3. 53
      lib/rules_inline/sub.js
  4. 55
      lib/rules_inline/sup.js
  5. 14
      test/fixtures/remarkable/del.txt
  6. 32
      test/fixtures/remarkable/sub.txt
  7. 36
      test/fixtures/remarkable/sup.txt

14
lib/renderer.js

@ -240,17 +240,11 @@ rules.mark_close = function(/*tokens, idx, options*/) {
}; };
rules.sub_open = function(/*tokens, idx, options*/) { rules.sub = function(tokens, idx/*, options*/) {
return '<sub>'; return '<sub>' + escapeHtml(tokens[idx].content) + '</sub>';
}; };
rules.sub_close = function(/*tokens, idx, options*/) { rules.sup = function(tokens, idx/*, options*/) {
return '</sub>'; return '<sup>' + escapeHtml(tokens[idx].content) + '</sup>';
};
rules.sup_open = function(/*tokens, idx, options*/) {
return '<sup>';
};
rules.sup_close = function(/*tokens, idx, options*/) {
return '</sup>';
}; };

4
lib/rules_inline/del.js

@ -26,8 +26,8 @@ module.exports = function del(state, silent) {
pos = start + 2; pos = start + 2;
while (pos < max && state.src.charCodeAt(pos) === 0x7E/* ~ */) { pos++; } while (pos < max && state.src.charCodeAt(pos) === 0x7E/* ~ */) { pos++; }
if (pos !== start + 2) { if (pos > start + 3) {
// sequence of 3+ markers taking as literal, same as in a emphasis // sequence of 4+ markers taking as literal, same as in a emphasis
state.pos += pos - start; state.pos += pos - start;
if (!silent) { state.pending += state.src.slice(start, pos); } if (!silent) { state.pending += state.src.slice(start, pos); }
return true; return true;

53
lib/rules_inline/sub.js

@ -2,53 +2,40 @@
'use strict'; 'use strict';
// same as UNESCAPE_MD_RE plus a space
var UNESCAPE_RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;
module.exports = function sub(state, silent) { module.exports = function sub(state, silent) {
var found, var found,
stack, content,
max = state.posMax, max = state.posMax,
start = state.pos, start = state.pos;
lastChar,
nextChar;
if (state.src.charCodeAt(start) !== 0x7E/* ~ */) { return false; } if (state.src.charCodeAt(start) !== 0x7E/* ~ */) { return false; }
if (silent) { return false; } // don't run any pairs in validation mode if (silent) { return false; } // don't run any pairs in validation mode
if (start + 2 >= max) { return false; } if (start + 2 >= max) { return false; }
if (state.level >= state.options.maxNesting) { return false; } if (state.level >= state.options.maxNesting) { return false; }
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1;
nextChar = state.src.charCodeAt(start + 2);
if (nextChar === 0x20 || nextChar === 0x0A) { return false; }
state.pos = start + 1; state.pos = start + 1;
stack = 1;
while (state.pos < max) { while (state.pos < max) {
if (state.src.charCodeAt(state.pos) === 0x7E/* ~ */) { if (state.src.charCodeAt(state.pos) === 0x7E/* ~ */) {
lastChar = state.src.charCodeAt(state.pos - 1); found = true;
nextChar = state.pos + 1 < max ? state.src.charCodeAt(state.pos + 1) : -1; break;
if (nextChar !== 0x7E/* ~ */ && lastChar !== 0x7E/* ~ */) {
if (lastChar !== 0x20 && lastChar !== 0x0A) {
// closing '~'
stack--;
} else if (nextChar !== 0x20 && nextChar !== 0x0A) {
// opening '~'
stack++;
} // else {
// // standalone ' ~ ' indented with spaces
//}
if (stack <= 0) {
found = true;
break;
}
}
} }
state.parser.skipToken(state); state.parser.skipToken(state);
} }
if (!found) { if (!found || start + 1 === state.pos) {
// parser failed to find ending tag, so it's not valid emphasis state.pos = start;
return false;
}
content = state.src.slice(start + 1, state.pos);
// don't allow unescaped spaces/newlines inside
if (content.match(/(^|[^\\])(\\\\)*\s/)) {
state.pos = start; state.pos = start;
return false; return false;
} }
@ -58,9 +45,11 @@ module.exports = function sub(state, silent) {
state.pos = start + 1; state.pos = start + 1;
if (!silent) { if (!silent) {
state.push({ type: 'sub_open', level: state.level++ }); state.push({
state.parser.tokenize(state); type: 'sub',
state.push({ type: 'sub_close', level: --state.level }); level: state.level,
content: content.replace(UNESCAPE_RE, '$1')
});
} }
state.pos = state.posMax + 1; state.pos = state.posMax + 1;

55
lib/rules_inline/sup.js

@ -1,54 +1,41 @@
// Process ~superscript~ // Process ^superscript^
'use strict'; 'use strict';
// same as UNESCAPE_MD_RE plus a space
var UNESCAPE_RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;
module.exports = function sup(state, silent) { module.exports = function sup(state, silent) {
var found, var found,
stack, content,
max = state.posMax, max = state.posMax,
start = state.pos, start = state.pos;
lastChar,
nextChar;
if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; } if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; }
if (silent) { return false; } // don't run any pairs in validation mode if (silent) { return false; } // don't run any pairs in validation mode
if (start + 2 >= max) { return false; } if (start + 2 >= max) { return false; }
if (state.level >= state.options.maxNesting) { return false; } if (state.level >= state.options.maxNesting) { return false; }
lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1;
nextChar = state.src.charCodeAt(start + 2);
if (nextChar === 0x20 || nextChar === 0x0A) { return false; }
state.pos = start + 1; state.pos = start + 1;
stack = 1;
while (state.pos < max) { while (state.pos < max) {
if (state.src.charCodeAt(state.pos) === 0x5E/* ^ */) { if (state.src.charCodeAt(state.pos) === 0x5E/* ^ */) {
lastChar = state.src.charCodeAt(state.pos - 1); found = true;
nextChar = state.pos + 1 < max ? state.src.charCodeAt(state.pos + 1) : -1; break;
if (nextChar !== 0x5E/* ^ */ && lastChar !== 0x5E/* ^ */) {
if (lastChar !== 0x20 && lastChar !== 0x0A) {
// closing '^'
stack--;
} else if (nextChar !== 0x20 && nextChar !== 0x0A) {
// opening '^'
stack++;
} // else {
// // standalone ' ^ ' indented with spaces
//}
if (stack <= 0) {
found = true;
break;
}
}
} }
state.parser.skipToken(state); state.parser.skipToken(state);
} }
if (!found) { if (!found || start + 1 === state.pos) {
// parser failed to find ending tag, so it's not valid emphasis state.pos = start;
return false;
}
content = state.src.slice(start + 1, state.pos);
// don't allow unescaped spaces/newlines inside
if (content.match(/(^|[^\\])(\\\\)*\s/)) {
state.pos = start; state.pos = start;
return false; return false;
} }
@ -58,9 +45,11 @@ module.exports = function sup(state, silent) {
state.pos = start + 1; state.pos = start + 1;
if (!silent) { if (!silent) {
state.push({ type: 'sup_open', level: state.level++ }); state.push({
state.parser.tokenize(state); type: 'sup',
state.push({ type: 'sup_close', level: --state.level }); level: state.level,
content: content.replace(UNESCAPE_RE, '$1')
});
} }
state.pos = state.posMax + 1; state.pos = state.posMax + 1;

14
test/fixtures/remarkable/del.txt

@ -4,20 +4,6 @@
<p><del>Strikeout</del></p> <p><del>Strikeout</del></p>
. .
These are not strikeouts, you have to use exactly two "~~":
.
x ~~~foo~~~
x ~~foo~~~
x ~~~foo~~
.
<p>x ~~~foo~~~</p>
<p>x ~~foo~~~</p>
<p>x ~~~foo~~</p>
.
Strikeouts have the same priority as emphases: Strikeouts have the same priority as emphases:
. .

32
test/fixtures/remarkable/sub.txt

@ -1,12 +1,36 @@
. .
~foo ~bar~ baz~ ~foo\~
. .
<p><sub>foo <sub>bar</sub> baz</sub></p> <p>~foo~</p>
. .
. .
this ~ is ~ not ~ subscript ~foo bar~
. .
<p>this ~ is ~ not ~ subscript</p> <p>~foo bar~</p>
.
.
~foo\ bar\ baz~
.
<p><sub>foo bar baz</sub></p>
.
.
~\ foo\ ~
.
<p><sub> foo </sub></p>
.
.
~foo\\\\\\\ bar~
.
<p><sub>foo\\\ bar</sub></p>
.
.
~foo\\\\\\ bar~
.
<p>~foo\\\ bar~</p>
. .

36
test/fixtures/remarkable/sup.txt

@ -1,18 +1,42 @@
. .
^foo ^bar^ baz^ ^test^
. .
<p><sup>foo <sup>bar</sup> baz</sup></p> <p><sup>test</sup></p>
. .
. .
^foo ~bar~ baz^ ^foo\^
. .
<p><sup>foo <sub>bar</sub> baz</sup></p> <p>^foo^</p>
. .
. .
this ^ is ^ not ^ superscript 2^4 + 3^5
. .
<p>this ^ is ^ not ^ superscript</p> <p>2^4 + 3^5</p>
.
.
^foo~bar^baz^bar~foo^
.
<p><sup>foo~bar</sup>baz<sup>bar~foo</sup></p>
.
.
^\ foo\ ^
.
<p><sup> foo </sup></p>
.
.
^foo\\\\\\\ bar^
.
<p><sup>foo\\\ bar</sup></p>
.
.
^foo\\\\\\ bar^
.
<p>^foo\\\ bar^</p>
. .

Loading…
Cancel
Save