286 lines
7.9 KiB
JavaScript
286 lines
7.9 KiB
JavaScript
(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(/<MOD>/g, function () { return '(?:' + modifierRegex + ')'; })
|
|
.replace(/<PAR>/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*(?:<MOD>|<PAR>|[<>=])*\./.source),
|
|
inside: {
|
|
'modifier': {
|
|
pattern: withModifier(/(^[a-z]\w*)(?:<MOD>|<PAR>|[<>=])+(?=\.)/.source),
|
|
lookbehind: true,
|
|
inside: modifierTokens
|
|
},
|
|
'tag': /^[a-z]\w*/,
|
|
'punctuation': /\.$/
|
|
}
|
|
},
|
|
|
|
// # List item
|
|
// * List item
|
|
'list': {
|
|
pattern: withModifier(/^[*#]+<MOD>*\s+\S.*/.source, 'm'),
|
|
inside: {
|
|
'modifier': {
|
|
pattern: withModifier(/(^[*#]+)<MOD>+/.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(/^(?:(?:<MOD>|<PAR>|[<>=^~])+\.\s*)?(?:\|(?:(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\d+)+\.|(?!(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\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)?)(?:<MOD>|<PAR>|[<>=^~_]|[\\/]\d+)+(?=\.)/.source),
|
|
lookbehind: true,
|
|
inside: modifierTokens
|
|
},
|
|
'punctuation': /\||^\./
|
|
}
|
|
},
|
|
|
|
'inline': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^|[^a-zA-Z\d])(\*\*|__|\?\?|[*_%@+\-^~])<MOD>*.+?\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(/(^(\*\*?)<MOD>*).+?(?=\2)/.source),
|
|
lookbehind: true
|
|
},
|
|
|
|
// _italic_, __italic__
|
|
'italic': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^(__?)<MOD>*).+?(?=\2)/.source),
|
|
lookbehind: true
|
|
},
|
|
|
|
// ??cite??
|
|
'cite': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^\?\?<MOD>*).+?(?=\?\?)/.source),
|
|
lookbehind: true,
|
|
alias: 'string'
|
|
},
|
|
|
|
// @code@
|
|
'code': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^@<MOD>*).+?(?=@)/.source),
|
|
lookbehind: true,
|
|
alias: 'keyword'
|
|
},
|
|
|
|
// +inserted+
|
|
'inserted': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^\+<MOD>*).+?(?=\+)/.source),
|
|
lookbehind: true
|
|
},
|
|
|
|
// -deleted-
|
|
'deleted': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^-<MOD>*).+?(?=-)/.source),
|
|
lookbehind: true
|
|
},
|
|
|
|
// %span%
|
|
'span': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^%<MOD>*).+?(?=%)/.source),
|
|
lookbehind: true
|
|
},
|
|
|
|
'modifier': {
|
|
pattern: withModifier(/(^\*\*|__|\?\?|[*_%@+\-^~])<MOD>+/.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(/"<MOD>*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source),
|
|
inside: {
|
|
'text': {
|
|
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
|
pattern: withModifier(/(^"<MOD>*)[^"]+(?=")/.source),
|
|
lookbehind: true
|
|
},
|
|
'modifier': {
|
|
pattern: withModifier(/(^")<MOD>+/.source),
|
|
lookbehind: true,
|
|
inside: modifierTokens
|
|
},
|
|
'url': {
|
|
pattern: /(:).+/,
|
|
lookbehind: true
|
|
},
|
|
'punctuation': /[":]/
|
|
}
|
|
},
|
|
|
|
// !image.jpg!
|
|
// !image.jpg(Title)!:http://example.com
|
|
'image': {
|
|
pattern: withModifier(/!(?:<MOD>|<PAR>|[<>=])*(?![<>=])[^!\s()]+(?:\([^)]+\))?!(?::.+?(?=[^\w/]?(?:\s|$)))?/.source),
|
|
inside: {
|
|
'source': {
|
|
pattern: withModifier(/(^!(?:<MOD>|<PAR>|[<>=])*)(?![<>=])[^!\s()]+(?:\([^)]+\))?(?=!)/.source),
|
|
lookbehind: true,
|
|
alias: 'url'
|
|
},
|
|
'modifier': {
|
|
pattern: withModifier(/(^!)(?:<MOD>|<PAR>|[<>=])+/.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));
|