User:Majr/Prism.js

/** * 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'); _.highlightElements(elements, async === true, callback); },	highlightElements: function( elements, async, callback ) { 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, '&amp;').replace(//g, '&gt;').replace(/\u00a0/g, ' '); //console.time(code.slice(0,50)); 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)); env.element.innerHTML = env.highlightedCode; callback && callback.call(env.element); //console.timeEnd(code.slice(0,50)); _.hooks.run('after-highlight', env); };			worker.postMessage(JSON.stringify({ language: env.language, code: env.code }));		}		else { env.highlightedCode = _.highlight(env.code, env.grammar) env.element.innerHTML = env.highlightedCode; callback && callback.call(element); _.hooks.run('after-highlight', env); //console.timeEnd(code.slice(0,50)); }	},	highlight: function (text, grammar) { return Token.stringify(_.tokenize(text, grammar)); },	tokenize: function(text, grammar) { 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 || 0; pattern = pattern.pattern || pattern; for (var i=0; i 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) { lookbehind = match[1].length; }

var from = match.index - 1 + lookbehind, match = match[0].slice(lookbehind), 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) { if (typeof o == 'string') { return o;	} if (Object.prototype.toString.call(o) == '[object Array]') { return o.map(Token.stringify).join(''); }	var env = { type: o.type, content: Token.stringify(o.content), tag: 'span', classes: ['token', o.type], attributes: {} };	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.css = { 'comment': /\/\*[\w\W]*?\*\//g, 'atrule': /@[\w-]+?(\s+[^;{]+)?(?=\s*{|\s*;)/gi, 'url': /url\((["']?).*?\1\)/gi,	'selector': /[^\{\}\s][^\{\}]*(?=\s*\{)/g,	'property': /(\b|\B)[a-z-]+(?=\s*:)/ig,	'string': /("|')(\\?.)*?\1/g, 'important': /\B!important\b/gi, 'ignore': /&(lt|gt|amp);/gi, 'punctuation': /[\{\};:]/g };

Prism.languages.clike = { 'comment': { pattern: /(^| |\t|\n|[^\\](?=\/\/ ))(\/\*[\w\W]*?\*\/|\/\/.*)/g, lookbehind: true },	'string': /("|')(\\?.)*?\1/g,	'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,	'boolean': /\b(true|false)\b/g,	'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,	'operator': /[-+]{1,2}|!|=?&lt;|=?&gt;|={1,2}|(&amp;){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|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 } });

Prism.languages.lua = Prism.languages.extend('clike', {	'keyword': /\b(break|do|else|elseif|end|for|function|goto|if|in|local|nil|repeat|return|then|until|while|\.\.\.)\b/g,	'number': /\b(-?0x\d*[\da-f]+|nan|-?inf)\b/g,	'comment': /\-\-(\[\.*)/g,	'string': /(?:("|')(\\?.)*?\1)|(?:\[\[([^\*)\]\])/g,	'operator': /[-+]|~=|=?&lt;|=?&gt;|={1,2}|\b(and|or|not)\b|\b#|\.\.|%|\^|\*|\//g, });

/* MediaWiki compatibility */ mw.hook( 'wikipage.content' ).add( function( $content ) {	// Kill geshi	var $GESHI = $content.find( '.mw-highlight' );	if ( $GESHI.length ) {		var lang = {			Scribunto: 'lua',			javascript: 'js',			css: 'css',		}[mw.config.get( 'wgPageContentModel' )];		if ( lang ) {			var $pre = $GESHI.find( '> pre' );			$pre.addClass( 'mw-' + lang );			$pre.text( $pre.text );		}	}	$content.find( 'pre.mw-js' ).addClass( 'mw-code' ).wrapInner( '' );	$content.find( 'pre.mw-css' ).addClass( 'mw-code' ).wrapInner( '' );	$content.find( 'pre.mw-lua, pre.mw-script' ).addClass( 'mw-code' ).wrapInner( '' );	$content.find( 'code.mw-js' ).addClass( 'mw-code language-javascript' );	$content.find( 'code.mw-css' ).addClass( 'mw-code language-css' );	$content.find( 'code.mw-lua, code.mw-script' ).addClass( 'mw-code language-lua' ); var $elements = $content.find( 'code[class*="language-"], [class*="language-"] code' ); if ( $elements.length ) { Prism.highlightElements( $elements.get ); } } );