From 0411b14cf504ad621e10042bb4d088d36af8a650 Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Sat, 25 Oct 2014 12:45:20 +0400 Subject: [PATCH] Added support --- demo/sample.md | 2 + lib/parser_inline.js | 5 +- lib/renderer.js | 8 +++ lib/rules_inline/mark.js | 78 ++++++++++++++++++++++++++ test/fixtures/remarkable/mark.txt | 92 +++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 lib/rules_inline/mark.js create mode 100644 test/fixtures/remarkable/mark.txt diff --git a/demo/sample.md b/demo/sample.md index cebf727..b8aa7b2 100644 --- a/demo/sample.md +++ b/demo/sample.md @@ -58,6 +58,8 @@ _This is italic text_ ++Inserted text++ +==Marked text== + ## Blockquotes diff --git a/lib/parser_inline.js b/lib/parser_inline.js index d327acf..af3246a 100644 --- a/lib/parser_inline.js +++ b/lib/parser_inline.js @@ -19,6 +19,7 @@ rules.push(require('./rules_inline/escape')); rules.push(require('./rules_inline/backticks')); rules.push(require('./rules_inline/del')); rules.push(require('./rules_inline/ins')); +rules.push(require('./rules_inline/mark')); rules.push(require('./rules_inline/emphasis')); rules.push(require('./rules_inline/links')); rules.push(require('./rules_inline/autolink')); @@ -49,9 +50,9 @@ function ParserInline() { this._rules = []; // Rule to skip pure text - // - '{$%@}' reserved for extentions + // - '{}$%@+=' reserved for extentions // - '<>"' added for internal html escaping - this.textMatch = /^[^\n\\`*_\[\]!&{}$%@<>"~+]+/; + this.textMatch = /^[^\n\\`*_\[\]!&{}$%@<>"~+=]+/; // By default CommonMark allows too much in links // If you need to restrict it - override this with your validator. diff --git a/lib/renderer.js b/lib/renderer.js index b0b6c9f..41d2747 100644 --- a/lib/renderer.js +++ b/lib/renderer.js @@ -208,6 +208,14 @@ rules.ins_close = function(/*tokens, idx, options*/) { }; +rules.mark_open = function(/*tokens, idx, options*/) { + return ''; +}; +rules.mark_close = function(/*tokens, idx, options*/) { + return ''; +}; + + rules.hardbreak = function (tokens, idx, options) { return options.xhtmlOut ? '
\n' : '
\n'; }; diff --git a/lib/rules_inline/mark.js b/lib/rules_inline/mark.js new file mode 100644 index 0000000..6f153a7 --- /dev/null +++ b/lib/rules_inline/mark.js @@ -0,0 +1,78 @@ +// Process ++inserted text++ + +'use strict'; + +module.exports = function mark(state, silent) { + var found, + pos, + max = state.posMax, + start = state.pos, + lastChar, + nextChar; + + if (state.src.charCodeAt(start) !== 0x3D/* = */) { return false; } + if (start + 4 >= max) { return false; } + if (state.src.charCodeAt(start + 1) !== 0x3D/* = */) { return false; } + + // make ins lower a priority tag with respect to links, same as ; + // this code also prevents recursion + if (silent && state.isInLabel) { 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 (lastChar === 0x3D/* = */) { return false; } + if (nextChar === 0x3D/* = */) { return false; } + if (nextChar === 0x20 || nextChar === 0x0A) { return false; } + + pos = start + 2; + while (pos < max && state.src.charCodeAt(pos) === 0x3D/* = */) { pos++; } + if (pos !== start + 2) { + // sequence of 3+ markers taking as literal, same as in a emphasis + state.pos += pos - start; + if (!silent) { state.pending += state.src.slice(start, pos); } + return true; + } + + state.pos = start + 2; + + while (state.pos + 1 < max) { + if (state.src.charCodeAt(state.pos) === 0x3D/* = */) { + if (state.src.charCodeAt(state.pos + 1) === 0x3D/* = */) { + lastChar = state.src.charCodeAt(state.pos - 1); + nextChar = state.pos + 2 < max ? state.src.charCodeAt(state.pos + 2) : -1; + if (nextChar !== 0x3D/* = */ && lastChar !== 0x3D/* = */) { + if (lastChar !== 0x20 && lastChar !== 0x0A) { + // closing '++' + found = true; + break; + } + } + } + } + + 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: 'mark_open', level: state.level++ }); + state.parser.tokenize(state); + state.push({ type: 'mark_close', level: --state.level }); + } + + state.pos = state.posMax + 2; + state.posMax = max; + return true; +}; diff --git a/test/fixtures/remarkable/mark.txt b/test/fixtures/remarkable/mark.txt new file mode 100644 index 0000000..a88341f --- /dev/null +++ b/test/fixtures/remarkable/mark.txt @@ -0,0 +1,92 @@ +. +==Mark== +. +

Mark

+. + + +These are not marks, you have to use exactly two "==": +. +x ===foo=== + +x ==foo=== + +x ===foo== +. +

x ===foo===

+

x ==foo===

+

x ===foo==

+. + +Marks have the same priority as emphases: + +. +**==test**== + +==**test==** +. +

**test**

+

==test==

+. + +Marks have the same priority as emphases with respect to links: +. +[==link]()== + +==[link==]() +. +

==link==

+

==link==

+. + +Marks have the same priority as emphases with respect to backticks: +. +==`code==` + +`==code`== +. +

==code==

+

==code==

+. + +Nested marks: +. +==foo ==bar== baz== +. +

foo bar baz

+. + +. +==f **o ==o b== a** r== +. +

f o o b a r

+. + +Should not have a whitespace between text and "==": +. +foo == bar == baz +. +

foo == bar == baz

+. + + +Newline should be considered a whitespace: + +. +==test +== + +== +test== + +== +test +== +. +

==test

+

== +test==

+

== +test +==

+.