(function (Prism) { // We don't allow for pipes inside parentheses // to not break table pattern |(. foo |). bar | var modifierRegex = /\([^|()\n]+\)|\[[^\]\n]+\]|\{[^}\n]+\}/.source; // Opening and closing parentheses which are not a modifier // This pattern is necessary to prevent exponential backtracking var parenthesesRegex = /\)|\((?![^|()\n]+\))/.source; /** * @param {string} source * @param {string} [flags] */ function withModifier(source, flags) { return RegExp( source .replace(//g, function () { return '(?:' + modifierRegex + ')'; }) .replace(//g, function () { return '(?:' + parenthesesRegex + ')'; }), flags || '' ); } var modifierTokens = { css: { pattern: /\{[^{}]+\}/, inside: { rest: Prism.languages.css, }, }, 'class-id': { pattern: /(\()[^()]+(?=\))/, lookbehind: true, alias: 'attr-value', }, lang: { pattern: /(\[)[^\[\]]+(?=\])/, lookbehind: true, alias: 'attr-value', }, // Anything else is punctuation (the first pattern is for row/col spans inside tables) punctuation: /[\\\/]\d+|\S/, }; var textile = (Prism.languages.textile = Prism.languages.extend('markup', { phrase: { pattern: /(^|\r|\n)\S[\s\S]*?(?=$|\r?\n\r?\n|\r\r)/, lookbehind: true, inside: { // h1. Header 1 'block-tag': { pattern: withModifier(/^[a-z]\w*(?:||[<>=])*\./.source), inside: { modifier: { pattern: withModifier( /(^[a-z]\w*)(?:||[<>=])+(?=\.)/.source ), lookbehind: true, inside: modifierTokens, }, tag: /^[a-z]\w*/, punctuation: /\.$/, }, }, // # List item // * List item list: { pattern: withModifier(/^[*#]+*\s+\S.*/.source, 'm'), inside: { modifier: { pattern: withModifier(/(^[*#]+)+/.source), lookbehind: true, inside: modifierTokens, }, punctuation: /^[*#]+/, }, }, // | cell | cell | cell | table: { // Modifiers can be applied to the row: {color:red}.|1|2|3| // or the cell: |{color:red}.1|2|3| pattern: withModifier( /^(?:(?:||[<>=^~])+\.\s*)?(?:\|(?:(?:||[<>=^~_]|[\\/]\d+)+\.|(?!(?:||[<>=^~_]|[\\/]\d+)+\.))[^|]*)+\|/ .source, 'm' ), inside: { modifier: { // Modifiers for rows after the first one are // preceded by a pipe and a line feed pattern: withModifier( /(^|\|(?:\r?\n|\r)?)(?:||[<>=^~_]|[\\/]\d+)+(?=\.)/ .source ), lookbehind: true, inside: modifierTokens, }, punctuation: /\||^\./, }, }, inline: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier( /(^|[^a-zA-Z\d])(\*\*|__|\?\?|[*_%@+\-^~])*.+?\2(?![a-zA-Z\d])/ .source ), lookbehind: true, inside: { // Note: superscripts and subscripts are not handled specifically // *bold*, **bold** bold: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^(\*\*?)*).+?(?=\2)/.source), lookbehind: true, }, // _italic_, __italic__ italic: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^(__?)*).+?(?=\2)/.source), lookbehind: true, }, // ??cite?? cite: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^\?\?*).+?(?=\?\?)/.source), lookbehind: true, alias: 'string', }, // @code@ code: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^@*).+?(?=@)/.source), lookbehind: true, alias: 'keyword', }, // +inserted+ inserted: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^\+*).+?(?=\+)/.source), lookbehind: true, }, // -deleted- deleted: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^-*).+?(?=-)/.source), lookbehind: true, }, // %span% span: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^%*).+?(?=%)/.source), lookbehind: true, }, modifier: { pattern: withModifier(/(^\*\*|__|\?\?|[*_%@+\-^~])+/.source), lookbehind: true, inside: modifierTokens, }, punctuation: /[*_%?@+\-^~]+/, }, }, // [alias]http://example.com 'link-ref': { pattern: /^\[[^\]]+\]\S+$/m, inside: { string: { pattern: /(^\[)[^\]]+(?=\])/, lookbehind: true, }, url: { pattern: /(^\])\S+$/, lookbehind: true, }, punctuation: /[\[\]]/, }, }, // "text":http://example.com // "text":link-ref link: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/"*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source), inside: { text: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^"*)[^"]+(?=")/.source), lookbehind: true, }, modifier: { pattern: withModifier(/(^")+/.source), lookbehind: true, inside: modifierTokens, }, url: { pattern: /(:).+/, lookbehind: true, }, punctuation: /[":]/, }, }, // !image.jpg! // !image.jpg(Title)!:http://example.com image: { pattern: withModifier( /!(?:||[<>=])*(?![<>=])[^!\s()]+(?:\([^)]+\))?!(?::.+?(?=[^\w/]?(?:\s|$)))?/ .source ), inside: { source: { pattern: withModifier( /(^!(?:||[<>=])*)(?![<>=])[^!\s()]+(?:\([^)]+\))?(?=!)/ .source ), lookbehind: true, alias: 'url', }, modifier: { pattern: withModifier(/(^!)(?:||[<>=])+/.source), lookbehind: true, inside: modifierTokens, }, url: { pattern: /(:).+/, lookbehind: true, }, punctuation: /[!:]/, }, }, // Footnote[1] footnote: { pattern: /\b\[\d+\]/, alias: 'comment', inside: { punctuation: /\[|\]/, }, }, // CSS(Cascading Style Sheet) acronym: { pattern: /\b[A-Z\d]+\([^)]+\)/, inside: { comment: { pattern: /(\()[^()]+(?=\))/, lookbehind: true, }, punctuation: /[()]/, }, }, // Prism(C) mark: { pattern: /\b\((?:C|R|TM)\)/, alias: 'comment', inside: { punctuation: /[()]/, }, }, }, }, })); var phraseInside = textile['phrase'].inside; var nestedPatterns = { inline: phraseInside['inline'], link: phraseInside['link'], image: phraseInside['image'], footnote: phraseInside['footnote'], acronym: phraseInside['acronym'], mark: phraseInside['mark'], }; // Only allow alpha-numeric HTML tags, not XML tags textile.tag.pattern = /<\/?(?!\d)[a-z0-9]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i; // Allow some nesting var phraseInlineInside = phraseInside['inline'].inside; phraseInlineInside['bold'].inside = nestedPatterns; phraseInlineInside['italic'].inside = nestedPatterns; phraseInlineInside['inserted'].inside = nestedPatterns; phraseInlineInside['deleted'].inside = nestedPatterns; phraseInlineInside['span'].inside = nestedPatterns; // Allow some styles inside table cells var phraseTableInside = phraseInside['table'].inside; phraseTableInside['inline'] = nestedPatterns['inline']; phraseTableInside['link'] = nestedPatterns['link']; phraseTableInside['image'] = nestedPatterns['image']; phraseTableInside['footnote'] = nestedPatterns['footnote']; phraseTableInside['acronym'] = nestedPatterns['acronym']; phraseTableInside['mark'] = nestedPatterns['mark']; })(Prism);