(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+.+/.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+)+\.)?[^|]*)+\|/.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': { 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': { pattern: withModifier(/(^(\*\*?)*).+?(?=\2)/.source), lookbehind: true }, // _italic_, __italic__ 'italic': { pattern: withModifier(/(^(__?)*).+?(?=\2)/.source), lookbehind: true }, // ??cite?? 'cite': { pattern: withModifier(/(^\?\?*).+?(?=\?\?)/.source), lookbehind: true, alias: 'string' }, // @code@ 'code': { pattern: withModifier(/(^@*).+?(?=@)/.source), lookbehind: true, alias: 'keyword' }, // +inserted+ 'inserted': { pattern: withModifier(/(^\+*).+?(?=\+)/.source), lookbehind: true }, // -deleted- 'deleted': { pattern: withModifier(/(^-*).+?(?=-)/.source), lookbehind: true }, // %span% 'span': { 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': { pattern: withModifier(/"*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source), inside: { 'text': { 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\((?:TM|R|C)\)/, 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));