diff --git a/src/components/common/base.scss b/src/components/common/base.scss index bd24f2ef..7aee98e5 100644 --- a/src/components/common/base.scss +++ b/src/components/common/base.scss @@ -165,6 +165,14 @@ img { max-width: 100%; } +.task-list-item { + list-style-type: none; +} + +.task-list-item-checkbox { + margin: 0 0.2em 0 -1.3em; +} + .footnote { font-size: 0.8em; position: relative; diff --git a/src/components/common/markdownHighlighting.scss b/src/components/common/markdownHighlighting.scss index 6e9486f7..48e7fa51 100644 --- a/src/components/common/markdownHighlighting.scss +++ b/src/components/common/markdownHighlighting.scss @@ -241,6 +241,11 @@ text-decoration: line-through; } + .cl-mark-text { + background-color: #ff0; + color: $editor-color-light-low; + } + .url, .email, .cl-underlined-text { diff --git a/src/extensions/katexExtension.js b/src/extensions/katexExtension.js index 08e99baf..4eb3d198 100644 --- a/src/extensions/katexExtension.js +++ b/src/extensions/katexExtension.js @@ -1,71 +1,14 @@ import katex from 'katex'; +import markdownItMath from './libs/markdownItMath'; import extensionSvc from '../services/extensionSvc'; -function texMath(state, silent) { - let startMathPos = state.pos; - if (state.src.charCodeAt(startMathPos) !== 0x24 /* $ */) { - return false; - } - - // Parse tex math according to http://pandoc.org/README.html#math - let endMarker = '$'; - startMathPos += 1; - const afterStartMarker = state.src.charCodeAt(startMathPos); - if (afterStartMarker === 0x24 /* $ */) { - endMarker = '$$'; - startMathPos += 1; - if (state.src.charCodeAt(startMathPos) === 0x24 /* $ */) { - // 3 markers are too much - return false; - } - } else if ( - // Skip if opening $ is succeeded by a space character - afterStartMarker === 0x20 /* space */ - || afterStartMarker === 0x09 /* \t */ - || afterStartMarker === 0x0a /* \n */ - ) { - return false; - } - const endMarkerPos = state.src.indexOf(endMarker, startMathPos); - if (endMarkerPos === -1) { - return false; - } - if (state.src.charCodeAt(endMarkerPos - 1) === 0x5C /* \ */) { - return false; - } - const nextPos = endMarkerPos + endMarker.length; - if (endMarker.length === 1) { - // Skip if $ is preceded by a space character - const beforeEndMarker = state.src.charCodeAt(endMarkerPos - 1); - if (beforeEndMarker === 0x20 /* space */ - || beforeEndMarker === 0x09 /* \t */ - || beforeEndMarker === 0x0a /* \n */) { - return false; - } - // Skip if closing $ is succeeded by a digit (eg $5 $10 ...) - const suffix = state.src.charCodeAt(nextPos); - if (suffix >= 0x30 && suffix < 0x3A) { - return false; - } - } - - if (!silent) { - const token = state.push(endMarker.length === 1 ? 'inline_math' : 'display_math', '', 0); - token.content = state.src.slice(startMathPos, endMarkerPos); - } - state.pos = nextPos; - return true; -} - extensionSvc.onGetOptions((options, properties) => { options.math = properties.extensions.katex.enabled; }); extensionSvc.onInitConverter(2, (markdown, options) => { if (options.math) { - markdown.use((md) => { - md.inline.ruler.push('texMath', texMath); - }); + markdown.use(markdownItMath); markdown.renderer.rules.inline_math = (tokens, idx) => `${markdown.utils.escapeHtml(tokens[idx].content)}`; markdown.renderer.rules.display_math = (tokens, idx) => diff --git a/src/extensions/libs/markdownItMath.js b/src/extensions/libs/markdownItMath.js new file mode 100644 index 00000000..528c126a --- /dev/null +++ b/src/extensions/libs/markdownItMath.js @@ -0,0 +1,59 @@ +function texMath(state, silent) { + let startMathPos = state.pos; + if (state.src.charCodeAt(startMathPos) !== 0x24 /* $ */) { + return false; + } + + // Parse tex math according to http://pandoc.org/README.html#math + let endMarker = '$'; + startMathPos += 1; + const afterStartMarker = state.src.charCodeAt(startMathPos); + if (afterStartMarker === 0x24 /* $ */) { + endMarker = '$$'; + startMathPos += 1; + if (state.src.charCodeAt(startMathPos) === 0x24 /* $ */) { + // 3 markers are too much + return false; + } + } else if ( + // Skip if opening $ is succeeded by a space character + afterStartMarker === 0x20 /* space */ + || afterStartMarker === 0x09 /* \t */ + || afterStartMarker === 0x0a /* \n */ + ) { + return false; + } + const endMarkerPos = state.src.indexOf(endMarker, startMathPos); + if (endMarkerPos === -1) { + return false; + } + if (state.src.charCodeAt(endMarkerPos - 1) === 0x5C /* \ */) { + return false; + } + const nextPos = endMarkerPos + endMarker.length; + if (endMarker.length === 1) { + // Skip if $ is preceded by a space character + const beforeEndMarker = state.src.charCodeAt(endMarkerPos - 1); + if (beforeEndMarker === 0x20 /* space */ + || beforeEndMarker === 0x09 /* \t */ + || beforeEndMarker === 0x0a /* \n */) { + return false; + } + // Skip if closing $ is succeeded by a digit (eg $5 $10 ...) + const suffix = state.src.charCodeAt(nextPos); + if (suffix >= 0x30 && suffix < 0x3A) { + return false; + } + } + + if (!silent) { + const token = state.push(endMarker.length === 1 ? 'inline_math' : 'display_math', '', 0); + token.content = state.src.slice(startMathPos, endMarkerPos); + } + state.pos = nextPos; + return true; +} + +export default (md) => { + md.inline.ruler.push('texMath', texMath); +}; diff --git a/src/extensions/libs/markdownItTasklist.js b/src/extensions/libs/markdownItTasklist.js new file mode 100644 index 00000000..93540f4a --- /dev/null +++ b/src/extensions/libs/markdownItTasklist.js @@ -0,0 +1,41 @@ +function attrSet(token, name, value) { + const index = token.attrIndex(name); + const attr = [name, value]; + + if (index < 0) { + token.attrPush(attr); + } else { + token.attrs[index] = attr; + } +} + +module.exports = (md) => { + md.core.ruler.after('inline', 'tasklist', (state) => { + const tokens = state.tokens; + for (let i = 2; i < tokens.length; i += 1) { + const token = tokens[i]; + if (token.content + && token.content.charCodeAt(0) === 0x5b /* [ */ + && token.content.charCodeAt(2) === 0x5d /* ] */ + && token.content.charCodeAt(3) === 0x20 /* space */ + && token.type === 'inline' + && tokens[i - 1].type === 'paragraph_open' + && tokens[i - 2].type === 'list_item_open' + ) { + const cross = token.content[1].toLowerCase(); + if (cross === ' ' || cross === 'x') { + const checkbox = new state.Token('html_inline', '', 0); + if (cross === ' ') { + checkbox.content = ''; + } else { + checkbox.content = ''; + } + token.children.unshift(checkbox); + token.children[1].content = token.children[1].content.slice(3); + token.content = token.content.slice(3); + attrSet(tokens[i - 2], 'class', 'task-list-item'); + } + } + } + }); +}; diff --git a/src/extensions/markdownExtension.js b/src/extensions/markdownExtension.js index d9aab82a..7a449b74 100644 --- a/src/extensions/markdownExtension.js +++ b/src/extensions/markdownExtension.js @@ -5,7 +5,7 @@ import markdownitFootnote from 'markdown-it-footnote'; import markdownitSub from 'markdown-it-sub'; import markdownitSup from 'markdown-it-sup'; import markdownitMark from 'markdown-it-mark'; -import markdownitTasklist from 'markdown-it-task-lists'; +import markdownitTasklist from './libs/markdownItTasklist'; import extensionSvc from '../services/extensionSvc'; const coreBaseRules = [ @@ -185,10 +185,21 @@ extensionSvc.onInitConverter(0, (markdown, options) => { }); extensionSvc.onSectionPreview((elt) => { + // Highlight with Prism elt.querySelectorAll('.prism').cl_each((prismElt) => { if (!prismElt.highlightedWithPrism) { Prism.highlightElement(prismElt); prismElt.highlightedWithPrism = true; } }); + + // Transform task list spans into checkboxes + elt.querySelectorAll('span.task-list-item-checkbox').cl_each((spanElt) => { + const checkboxElt = document.createElement('input'); + checkboxElt.type = 'checkbox'; + checkboxElt.className = 'task-list-item-checkbox'; + checkboxElt.checked = spanElt.classList.contains('checked'); + checkboxElt.disabled = 'disabled'; + spanElt.parentNode.replaceChild(checkboxElt, spanElt); + }); }); diff --git a/src/libs/markdownItTasklist.js b/src/libs/markdownItTasklist.js deleted file mode 100644 index 4f49ac69..00000000 --- a/src/libs/markdownItTasklist.js +++ /dev/null @@ -1,97 +0,0 @@ -// Credit: https://github.com/revin/markdown-it-task-lists - -module.exports = (md) => { - md.core.ruler.after('inline', 'github-task-lists', (state) => { - const tokens = state.tokens; - for (let i = 2; i < tokens.length; i += 1) { - const token = tokens[i]; - if (token.type === 'inline' && - tokens[i - 1].type === 'paragraph_open' && - tokens[i - 2].type === 'list_item_open' && - startsWithTodoMarkdown(tokens[i]) - ) { - todoify(tokens[i], state.Token); - attrSet(tokens[i-2], 'class', 'task-list-item' + (!disableCheckboxes ? ' enabled' : '')); - attrSet(tokens[parentToken(tokens, i-2)], 'class', 'contains-task-list'); - } - } - }); -}; - -function attrSet(token, name, value) { - var index = token.attrIndex(name); - var attr = [name, value]; - - if (index < 0) { - token.attrPush(attr); - } else { - token.attrs[index] = attr; - } -} - -function parentToken(tokens, index) { - var targetLevel = tokens[index].level - 1; - for (var i = index - 1; i >= 0; i--) { - if (tokens[i].level === targetLevel) { - return i; - } - } - return -1; -} - -function todoify(token, TokenConstructor) { - token.children.unshift(makeCheckbox(token, TokenConstructor)); - token.children[1].content = token.children[1].content.slice(3); - token.content = token.content.slice(3); - - if (useLabelWrapper) { - if (useLabelAfter) { - token.children.pop(); - - // Use large random number as id property of the checkbox. - var id = 'task-item-' + Math.ceil(Math.random() * (10000 * 1000) - 1000); - token.children[0].content = token.children[0].content.slice(0, -1) + ' id="' + id + '">'; - token.children.push(afterLabel(token.content, id, TokenConstructor)); - } else { - token.children.unshift(beginLabel(TokenConstructor)); - token.children.push(endLabel(TokenConstructor)); - } - } -} - -function makeCheckbox(token, TokenConstructor) { - var checkbox = new TokenConstructor('html_inline', '', 0); - var disabledAttr = disableCheckboxes ? ' disabled="" ' : ''; - if (token.content.indexOf('[ ] ') === 0) { - checkbox.content = ''; - } else if (token.content.indexOf('[x] ') === 0 || token.content.indexOf('[X] ') === 0) { - checkbox.content = ''; - } - return checkbox; -} - -// these next two functions are kind of hacky; probably should really be a -// true block-level token with .tag=='label' -function beginLabel(TokenConstructor) { - var token = new TokenConstructor('html_inline', '', 0); - token.content = ''; - return token; -} - -function afterLabel(content, id, TokenConstructor) { - var token = new TokenConstructor('html_inline', '', 0); - token.content = ''; - token.attrs = [{for: id}]; - return token; -} - -function startsWithTodoMarkdown(token) { - // leading whitespace in a list item is already trimmed off by markdown-it - return token.content.indexOf('[ ] ') === 0 || token.content.indexOf('[x] ') === 0 || token.content.indexOf('[X] ') === 0; -} diff --git a/src/libs/mdGrammar.js b/src/libs/mdGrammar.js deleted file mode 100644 index 5a049781..00000000 --- a/src/libs/mdGrammar.js +++ /dev/null @@ -1,422 +0,0 @@ -var charInsideUrl = '(&|[-A-Z0-9+@#/%?=~_|[\\]()!:,.;])' -var charEndingUrl = '(&|[-A-Z0-9+@#/%=~_|[\\])])' -var urlPattern = new RegExp('(https?|ftp)(://' + charInsideUrl + '*' + charEndingUrl + ')(?=$|\\W)', 'gi') -var emailPattern = /(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)/gi - -var markup = { - 'comment': //g, - 'tag': { - pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi, - inside: { - 'tag': { - pattern: /^<\/?[\w:-]+/i, - inside: { - 'punctuation': /^<\/?/, - 'namespace': /^[\w-]+?:/ - } - }, - 'attr-value': { - pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi, - inside: { - 'punctuation': /=|>|"/g - } - }, - 'punctuation': /\/?>/g, - 'attr-name': { - pattern: /[\w:-]+/g, - inside: { - 'namespace': /^[\w-]+?:/ - } - } - } - }, - 'entity': /&#?[\da-z]{1,8};/gi -} - -var latex = { - // A tex command e.g. \foo - 'keyword': /\\(?:[^a-zA-Z]|[a-zA-Z]+)/g, - // Curly and square braces - 'lparen': /[[({]/g, - // Curly and square braces - 'rparen': /[\])}]/g, - // A comment. Tex comments start with % and go to - // the end of the line - 'comment': /%.*/g -} - -module.exports = function (options) { - options = options || {} - var grammar = {} - var insideFences = options.insideFences || {} - insideFences['cl cl-pre'] = /`{3}|~{3}/ - if (options.fences) { - grammar['pre gfm'] = { - pattern: /^(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1 *$/gm, - inside: insideFences - } - } - grammar.li = { - pattern: new RegExp( - [ - '^ {0,3}(?:[*+\\-]|\\d+\\.)[ \\t].+\\n', // Item line - '(?:', - '(?:', - '.*\\S.*\\n', // Non-empty line - '|', - '[ \\t]*\\n(?! ?\\S)', // Or empty line not followed by unindented line - ')', - ')*' - ].join(''), - 'gm' - ), - inside: { - 'cl cl-li': /^[ \t]*([*+\-]|\d+\.)[ \t]/gm - } - } - if (options.fences) { - grammar.li.inside['pre gfm'] = { - pattern: /^((?: {4}|\t)+)(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1\2\s*$/gm, - inside: insideFences - } - } - grammar.blockquote = { - pattern: /^ {0,3}>.+(?:\n[ \t]*\S.*)*/gm, - inside: { - 'cl cl-gt': /^\s*>/gm, - 'li': grammar.li - } - } - grammar['h1 alt'] = { - pattern: /^.+\n=+[ \t]*$/gm, - inside: { - 'cl cl-hash': /=+[ \t]*$/ - } - } - grammar['h2 alt'] = { - pattern: /^.+\n-+[ \t]*$/gm, - inside: { - 'cl cl-hash': /-+[ \t]*$/ - } - } - for (var i = 6; i >= 1; i--) { - grammar['h' + i] = { - pattern: new RegExp('^#{' + i + '}[ \t].+$', 'gm'), - inside: { - 'cl cl-hash': new RegExp('^#{' + i + '}') - } - } - } - if (options.tables) { - grammar.table = { - pattern: new RegExp( - [ - '^', - '[ ]{0,3}', - '[|]', // Initial pipe - '.+\\n', // Header Row - '[ ]{0,3}', - '[|][ ]*[-:]+[-| :]*\\n', // Separator - '(?:[ \t]*[|].*\\n?)*', // Table rows - '$' - ].join(''), - 'gm' - ), - inside: {} - } - grammar['table alt'] = { - pattern: new RegExp( - [ - '^', - '[ ]{0,3}', - '\\S.*[|].*\\n', // Header Row - '[ ]{0,3}', - '[-:]+[ ]*[|][-| :]*\\n', // Separator - '(?:.*[|].*\\n?)*', // Table rows - '$' // Stop at final newline - ].join(''), - 'gm' - ), - inside: {} - } - } - if (options.deflists) { - grammar.deflist = { - pattern: new RegExp( - [ - '^ {0,3}\\S.*\\n', // Description line - '(?:[ \\t]*\\n)?', // Optional empty line - '(?:', - '[ \\t]*:[ \\t].*\\n', // Colon line - '(?:', - '(?:', - '.*\\S.*\\n', // Non-empty line - '|', - '[ \\t]*\\n(?! ?\\S)', // Or empty line not followed by unindented line - ')', - ')*', - '(?:[ \\t]*\\n)*', // Empty lines - ')+' - ].join(''), - 'gm' - ), - inside: { - 'deflist-desc': { - pattern: /( {0,3}\S.*\n(?:[ \t]*\n)?)[\s\S]*/, - lookbehind: true, - inside: { - 'cl': /^[ \t]*:[ \t]/gm - } - }, - 'term': /.+/g - } - } - if (options.fences) { - grammar.deflist.inside['deflist-desc'].inside['pre gfm'] = { - pattern: /^((?: {4}|\t)+)(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1\2\s*$/gm, - inside: insideFences - } - } - } - grammar.hr = { - pattern: /^ {0,3}([*\-_] *){3,}$/gm - } - if (options.footnotes) { - grammar.fndef = { - pattern: /^ {0,3}\[\^.*?\]:.*$/gm, - inside: { - 'ref-id': { - pattern: /^ {0,3}\[\^.*?\]/, - inside: { - cl: /(\[\^|\])/ - } - } - } - } - } - if (options.abbrs) { - grammar.abbrdef = { - pattern: /^ {0,3}\*\[.*?\]:.*$/gm, - inside: { - 'abbr-id': { - pattern: /^ {0,3}\*\[.*?\]/, - inside: { - cl: /(\*\[|\])/ - } - } - } - } - } - grammar.linkdef = { - pattern: /^ {0,3}\[.*?\]:.*$/gm, - inside: { - 'link-id': { - pattern: /^ {0,3}\[.*?\]/, - inside: { - cl: /[\[\]]/ - } - }, - url: urlPattern - } - } - grammar.p = { - pattern: /^ {0,3}\S.*$(\n.*\S.*)*/gm, - inside: {} - } - if (options.tocs) { - grammar.p.inside['cl cl-toc'] = /^[ \t]*\[toc\]$/mi - } - grammar.pre = { - pattern: /(?: {4}|\t).*\S.*\n((?: {4}|\t).*\n)*/g - } - - var rest = {} - if (options.maths) { - rest['math block'] = { - pattern: /\\\\\[[\s\S]*?\\\\\]/g, - inside: { - 'cl cl-bracket-start': /^\\\\\[/, - 'cl cl-bracket-end': /\\\\\]$/, - rest: latex - } - } - rest['math inline'] = { - pattern: /\\\\\([\s\S]*?\\\\\)/g, - inside: { - 'cl cl-bracket-start': /^\\\\\(/, - 'cl cl-bracket-end': /\\\\\)$/, - rest: latex - } - } - rest['math expr block'] = { - pattern: /(\$\$)[\s\S]*?\1/g, - inside: { - 'cl cl-bracket-start': /^\$\$/, - 'cl cl-bracket-end': /\$\$$/, - rest: latex - } - } - rest['math expr inline'] = { - pattern: /\$(?!\s)[\s\S]*?\S\$(?!\d)/g, - inside: { - 'cl cl-bracket-start': /^\$/, - 'cl cl-bracket-end': /\$$/, - rest: latex - } - } - rest['latex block'] = { - pattern: /\\begin\{([a-z]*\*?)\}[\s\S]*?\\?\\end\{\1\}/g, - inside: { - 'keyword': /\\(begin|end)/, - rest: latex - } - } - } - rest.code = { - pattern: /(`+)[\s\S]*?\1/g, - inside: { - 'cl cl-code': /`/ - } - } - if (options.footnotes) { - rest.inlinefn = { - pattern: /\^\[.+?\]/g, - inside: { - 'cl': /(\^\[|\])/ - } - } - rest.fn = { - pattern: /\[\^.+?\]/g, - inside: { - 'cl': /(\[\^|\])/ - } - } - } - rest.img = { - pattern: /!\[.*?\]\(.+?\)/g, - inside: { - 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/, - 'cl cl-src': { - pattern: /(\]\()[^\('" \t]+(?=[\)'" \t])/, - lookbehind: true - } - } - } - rest.link = { - pattern: /\[.*?\]\(.+?\)/gm, - inside: { - 'cl cl-underlined-text': { - pattern: /(\[)[^\]]*/, - lookbehind: true - }, - 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/ - } - } - rest.imgref = { - pattern: /!\[.*?\][ \t]*\[.*?\]/g - } - rest.linkref = { - pattern: /\[.*?\][ \t]*\[.*?\]/g, - inside: { - 'cl cl-underlined-text': { - pattern: /^(\[)[^\]]*(?=\][ \t]*\[)/, - lookbehind: true - } - } - } - rest.comment = markup.comment - rest.tag = markup.tag - rest.url = urlPattern - rest.email = emailPattern - rest.strong = { - pattern: /(^|[^\w*])([_\*])\2(?![_\*])[\s\S]*?\2{2}(?=([^\w*]|$))/gm, - lookbehind: true, - inside: { - 'cl cl-strong cl-start': /^([_\*])\1/, - 'cl cl-strong cl-close': /([_\*])\1$/ - } - } - rest.em = { - pattern: /(^|[^\w*])([_\*])(?![_\*])[\s\S]*?\2(?=([^\w*]|$))/gm, - lookbehind: true, - inside: { - 'cl cl-em cl-start': /^[_\*]/, - 'cl cl-em cl-close': /[_\*]$/ - } - } - if (options.dels) { - rest.del = { - pattern: /(^|[^\w*])(~~)[\s\S]*?\2(?=([^\w*]|$))/gm, - lookbehind: true, - inside: { - 'cl': /~~/, - 'cl-del-text': /[^~]+/ - } - } - } - if (options.subs) { - rest.sub = { - pattern: /(~)(?=\S)(.*?\S)\1/gm, - inside: { - 'cl': /~/ - } - } - } - if (options.sups) { - rest.sup = { - pattern: /(\^)(?=\S)(.*?\S)\1/gm, - inside: { - 'cl': /\^/ - } - } - } - rest.entity = markup.entity - - for (var c = 6; c >= 1; c--) { - grammar['h' + c].inside.rest = rest - } - grammar['h1 alt'].inside.rest = rest - grammar['h2 alt'].inside.rest = rest - if (options.tables) { - grammar.table.inside.rest = rest - grammar['table alt'].inside.rest = rest - } - grammar.p.inside.rest = rest - grammar.blockquote.inside.rest = rest - grammar.li.inside.rest = rest - if (options.footnotes) { - grammar.fndef.inside.rest = rest - } - if (options.deflists) { - grammar.deflist.inside['deflist-desc'].inside.rest = rest - } - - var restLight = { - code: rest.code, - inlinefn: rest.inlinefn, - fn: rest.fn, - link: rest.link, - linkref: rest.linkref - } - rest.strong.inside.rest = restLight - rest.em.inside.rest = restLight - if (options.dels) { - rest.del.inside.rest = restLight - } - - var inside = { - code: rest.code, - comment: rest.comment, - tag: rest.tag, - strong: rest.strong, - em: rest.em, - del: rest.del, - sub: rest.sub, - sup: rest.sup, - entity: markup.entity - } - rest.link.inside['cl cl-underlined-text'].inside = inside - rest.linkref.inside['cl cl-underlined-text'].inside = inside - - return grammar -} diff --git a/src/services/markdownGrammarSvc.js b/src/services/markdownGrammarSvc.js index 6eca26db..8a4ea443 100644 --- a/src/services/markdownGrammarSvc.js +++ b/src/services/markdownGrammarSvc.js @@ -150,6 +150,16 @@ export default { pattern: /^ {0,3}([*\-_] *){3,}$/gm, }; + if (options.tasklist) { + grammars.list.task = { + pattern: /^\[[ xX]\] /, + inside: { + cl: /[[\]]/, + strong: /[xX]/, + }, + }; + } + const defs = {}; if (options.footnote) { defs.fndef = { @@ -335,6 +345,16 @@ export default { }, }; } + if (options.mark) { + rest.mark = { + pattern: /(^|[^\w*])(==)[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + cl: /==/, + 'cl-mark-text': /[^=]+/, + }, + }; + } if (options.sub) { rest.sub = { pattern: /(~)(?=\S)(.*?\S)\1/gm, @@ -379,6 +399,9 @@ export default { if (options.del) { rest.del.inside.rest = restLight; } + if (options.mark) { + rest.mark.inside.rest = restLight; + } const inside = { code: rest.code,