/**
* Prism: Lightweight, robust, elegant syntax highlighting * MIT license http://www.opensource.org/licenses/mit-license.php/ * @author Lea Verou http://lea.verou.me */
(function(){
// Private helper vars var lang = /blang(?:uage)?-(?!*)(w+)b/i;
var _ = self.Prism = {
util: { type: function (o) { return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1]; }, // Deep clone a language definition (e.g. to extend it) clone: function (o) { var type = _.util.type(o); switch (type) { case 'Object': var clone = {}; for (var key in o) { if (o.hasOwnProperty(key)) { clone[key] = _.util.clone(o[key]); } } return clone; case 'Array': return o.slice(); } return o; } }, languages: { extend: function (id, redef) { var lang = _.util.clone(_.languages[id]); for (var key in redef) { lang[key] = redef[key]; } return lang; }, // Insert a token before another token in a language literal insertBefore: function (inside, before, insert, root) { root = root || _.languages; var grammar = root[inside]; var ret = {}; for (var token in grammar) { if (grammar.hasOwnProperty(token)) { if (token == before) { for (var newToken in insert) { if (insert.hasOwnProperty(newToken)) { ret[newToken] = insert[newToken]; } } } ret[token] = grammar[token]; } } return root[inside] = ret; }, // Traverse a language definition with Depth First Search DFS: function(o, callback) { for (var i in o) { callback.call(o, i, o[i]); if (_.util.type(o) === 'Object') { _.languages.DFS(o[i], callback); } } } }, highlightAll: function(async, callback) { var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'); for (var i=0, element; element = elements[i++];) { _.highlightElement(element, async === true, callback); } }, highlightElement: function(element, async, callback) { // Find language var language, grammar, parent = element; while (parent && !lang.test(parent.className)) { parent = parent.parentNode; } if (parent) { language = (parent.className.match(lang) || [,''])[1]; grammar = _.languages[language]; } if (!grammar) { return; } // Set language on the element, if not present element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; // Set language on the parent, for styling parent = element.parentNode; if (/pre/i.test(parent.nodeName)) { parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; } var code = element.textContent; if(!code) { return; } code = code.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); var env = { element: element, language: language, grammar: grammar, code: code }; _.hooks.run('before-highlight', env); if (async && self.Worker) { var worker = new Worker(_.filename); worker.onmessage = function(evt) { env.highlightedCode = Token.stringify(JSON.parse(evt.data), language); _.hooks.run('before-insert', env); env.element.innerHTML = env.highlightedCode; callback && callback.call(env.element); _.hooks.run('after-highlight', env); }; worker.postMessage(JSON.stringify({ language: env.language, code: env.code })); } else { env.highlightedCode = _.highlight(env.code, env.grammar, env.language) _.hooks.run('before-insert', env); env.element.innerHTML = env.highlightedCode; callback && callback.call(element); _.hooks.run('after-highlight', env); } }, highlight: function (text, grammar, language) { return Token.stringify(_.tokenize(text, grammar), language); }, tokenize: function(text, grammar, language) { var Token = _.Token; var strarr = [text]; var rest = grammar.rest; if (rest) { for (var token in rest) { grammar[token] = rest[token]; } delete grammar.rest; } tokenloop: for (var token in grammar) { if(!grammar.hasOwnProperty(token) || !grammar[token]) { continue; } var pattern = grammar[token], inside = pattern.inside, lookbehind = !!pattern.lookbehind, lookbehindLength = 0; pattern = pattern.pattern || pattern; for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop var str = strarr[i]; if (strarr.length > text.length) { // Something went terribly wrong, ABORT, ABORT! break tokenloop; } if (str instanceof Token) { continue; } pattern.lastIndex = 0; var match = pattern.exec(str); if (match) { if(lookbehind) { lookbehindLength = match[1].length; } var from = match.index - 1 + lookbehindLength, match = match[0].slice(lookbehindLength), len = match.length, to = from + len, before = str.slice(0, from + 1), after = str.slice(to + 1); var args = [i, 1]; if (before) { args.push(before); } var wrapped = new Token(token, inside? _.tokenize(match, inside) : match); args.push(wrapped); if (after) { args.push(after); } Array.prototype.splice.apply(strarr, args); } } } return strarr; }, hooks: { all: {}, add: function (name, callback) { var hooks = _.hooks.all; hooks[name] = hooks[name] || []; hooks[name].push(callback); }, run: function (name, env) { var callbacks = _.hooks.all[name]; if (!callbacks || !callbacks.length) { return; } for (var i=0, callback; callback = callbacks[i++];) { callback(env); } } }
};
var Token = _.Token = function(type, content) {
this.type = type; this.content = content;
};
Token.stringify = function(o, language, parent) {
if (typeof o == 'string') { return o; } if (Object.prototype.toString.call(o) == '[object Array]') { return o.map(function(element) { return Token.stringify(element, language, o); }).join(''); } var env = { type: o.type, content: Token.stringify(o.content, language, parent), tag: 'span', classes: ['token', o.type], attributes: {}, language: language, parent: parent }; if (env.type == 'comment') { env.attributes['spellcheck'] = 'true'; } _.hooks.run('wrap', env); var attributes = ''; for (var name in env.attributes) { attributes += name + '="' + (env.attributes[name] || '') + '"'; } return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>';
};
if (!self.document) {
// In worker self.addEventListener('message', function(evt) { var message = JSON.parse(evt.data), lang = message.language, code = message.code; self.postMessage(JSON.stringify(_.tokenize(code, _.languages[lang]))); self.close(); }, false); return;
}
})();; Prism.languages.markup = {
'comment': /<!--[\w\W]*?-->/g, 'prolog': /<\?.+?\?>/, 'doctype': /<!DOCTYPE.+?>/, 'cdata': /<!\[CDATA\[[\w\W]*?]]>/i, 'tag': { pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\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
};
// Plugin to make entity title show the real entity, idea by Roman Komarov Prism.hooks.add('wrap', function(env) {
if (env.type === 'entity') { env.attributes['title'] = env.content.replace(/&/, '&'); }
});; Prism.languages.css = {
'comment': /\/\*[\w\W]*?\*\//g, 'atrule': { pattern: /@[\w-]+?.*?(;|(?=\s*{))/gi, inside: { 'punctuation': /[;:]/g } }, 'url': /url\((["']?).*?\1\)/gi, 'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g, 'property': /(\b|\B)[\w-]+(?=\s*:)/ig, 'string': /("|')(\\?.)*?\1/g, 'important': /\B!important\b/gi, 'ignore': /&(lt|gt|amp);/gi, 'punctuation': /[\{\};:]/g
};
if (Prism.languages.markup) {
Prism.languages.insertBefore('markup', 'tag', { 'style': { pattern: /(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig, inside: { 'tag': { pattern: /(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig, inside: Prism.languages.markup.tag.inside }, rest: Prism.languages.css } } });
}; Prism.languages.clike = {
'comment': { pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g, lookbehind: true }, 'string': /("|')(\\?.)*?\1/g, 'class-name': { pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig, lookbehind: true, inside: { punctuation: /(\.|\\)/ } }, 'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g, 'boolean': /\b(true|false)\b/g, 'function': { pattern: /[a-z0-9_]+\(/ig, inside: { punctuation: /\(/ } }, 'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g, 'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g, 'ignore': /&(lt|gt|amp);/gi, 'punctuation': /[{}[\];(),.:]/g
}; ; Prism.languages.javascript = Prism.languages.extend('clike', {
'keyword': /\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|throw|catch|finally|null|break|continue)\b/g, 'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g
});
Prism.languages.insertBefore('javascript', 'keyword', {
'regex': { pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g, lookbehind: true }
});
if (Prism.languages.markup) {
Prism.languages.insertBefore('markup', 'tag', { 'script': { pattern: /(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig, inside: { 'tag': { pattern: /(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig, inside: Prism.languages.markup.tag.inside }, rest: Prism.languages.javascript } } });
} ; Prism.languages.coffeescript = Prism.languages.extend('javascript', {
'block-comment': /([#]{3}\s*\r?\n(.*\s*\r*\n*)\s*?\r?\n[#]{3})/g, 'comment': /(\s|^)([#]{1}[^#^\r^\n]{2,}?(\r?\n|$))/g, 'keyword': /\b(this|window|delete|class|extends|namespace|extend|ar|let|if|else|while|do|for|each|of|return|in|instanceof|new|with|typeof|try|catch|finally|null|undefined|break|continue)\b/g
});
Prism.languages.insertBefore('coffeescript', 'keyword', {
'function': { pattern: /[a-z|A-z]+\s*[:|=]\s*(\([.|a-z\s|,|:|{|}|\"|\'|=]*\))?\s*->/gi, inside: { 'function-name': /[_?a-z-|A-Z-]+(\s*[:|=])| @[_?$?a-z-|A-Z-]+(\s*)| /g, 'operator': /[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\//g } }, 'attr-name': /[_?a-z-|A-Z-]+(\s*:)| @[_?$?a-z-|A-Z-]+(\s*)| /g
}); ; Prism.languages.scss = Prism.languages.extend('css', {
'comment': { pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g, lookbehind: true }, // aturle is just the @***, not the entire rule (to highlight var & stuffs) // + add ability to highlight number & unit for media queries 'atrule': /@[\w-]+(?=\s+(\(|\{|;))/gi, // url, compassified 'url': /([-a-z]+-)*url(?=\()/gi, // CSS selector regex is not appropriate for Sass // since there can be lot more things (var, @ directive, nesting..) // a selector must start at the end of a property or after a brace (end of other rules or nesting) // it can contain some caracters that aren't used for defining rules or end of selector, & (parent selector), or interpolated variable // the end of a selector is found when there is no rules in it ( {} or {\s}) or if there is a property (because an interpolated var // can "pass" as a selector- e.g: proper#{$erty}) // this one was ard to do, so please be careful if you edit this one :) 'selector': /([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|\#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm
});
Prism.languages.insertBefore('scss', 'atrule', {
'keyword': /@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return)|(?=@for\s+\$[-_\w]+\s)+from/i
});
Prism.languages.insertBefore('scss', 'property', {
// var and interpolated vars 'variable': /((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i
});
Prism.languages.insertBefore('scss', 'ignore', {
'placeholder': /%[-_\w]+/i, 'statement': /\B!(default|optional)\b/gi, 'boolean': /\b(true|false)\b/g, 'null': /\b(null)\b/g, 'operator': /\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|\%)\s+/g
}); ; Prism.languages.bash = Prism.languages.extend('clike', {
'comment': { pattern: /(^|[^"{\\])(#.*?(\r?\n|$))/g, lookbehind: true }, 'string': { //allow multiline string pattern: /("|')(\\?[\s\S])*?\1/g, inside: { //'property' class reused for bash variables 'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g } }, 'keyword': /\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g
});
Prism.languages.insertBefore('bash', 'keyword', {
//'property' class reused for bash variables 'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g
}); Prism.languages.insertBefore('bash', 'comment', {
//shebang must be before comment, 'important' class from css reused 'important': /(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g
}); ; Prism.languages.c = Prism.languages.extend('clike', {
'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g, 'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|(&){1,2}|\|?\||\?|\*|\//g
});
Prism.languages.insertBefore('c', 'keyword', {
//property class reused for macro statements 'property': /#\s*[a-zA-Z]+/g
}); ; Prism.hooks.add('after-highlight', function (env) {
// works only for <code> wrapped inside <pre data-line-numbers> (not inline) var pre = env.element.parentNode; if (!pre || !/pre/i.test(pre.nodeName) || pre.className.indexOf('line-numbers') === -1) { return; } var linesNum = (1 + env.code.split('\n').length); var lineNumbersWrapper; lines = new Array(linesNum); lines = lines.join('<span></span>'); lineNumbersWrapper = document.createElement('span'); lineNumbersWrapper.className = 'line-numbers-rows'; lineNumbersWrapper.innerHTML = lines; if (pre.hasAttribute('data-start')) { pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1); } env.element.appendChild(lineNumbersWrapper);
});;