/** * 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(/ 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 + ''; }; 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 wrapped inside
 (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('');

	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);

});;