/*
Syntax highlighting with language autodetection.
http://softwaremaniacs.org/soft/highlight/
*/
function() {
/* Utility functions */
function escape(value) {
return value.replace(/&/gm, '&').replace(//gm, '>');
}
function findCode(pre) {
for (var node = pre.firstChild; node; node = node.nextSibling) {
if (node.nodeName == 'CODE')
return node;
if (!(node.nodeType == 3 && node.nodeValue.match(/\s+/)))
break;
}
}
function blockText(block, ignoreNewLines) {
return Array.prototype.map.call(block.childNodes, function(node) {
if (node.nodeType == 3) {
return ignoreNewLines ? node.nodeValue.replace(/\n/g, '') : node.nodeValue;
}
if (node.nodeName == 'BR') {
return '\n';
}
return blockText(node, ignoreNewLines);
}).join('');
}
function blockLanguage(block) {
var classes = (block.className + ' ' + (block.parentNode ? block.parentNode.className : '')).split(/\s+/);
classes = classes.map(function(c) {return c.replace(/^language-/, '')});
for (var i = 0; i < classes.length; i++) {
if (languages[classes[i]] || classes[i] == 'no-highlight') {
return classes[i];
}
}
}
/* Stream merging */
function nodeStream(node) {
var result = [];
(function _nodeStream(node, offset) {
for (var child = node.firstChild; child; child = child.nextSibling) {
if (child.nodeType == 3)
offset += child.nodeValue.length;
else if (child.nodeName == 'BR')
offset += 1;
else if (child.nodeType == 1) {
result.push({
event: 'start',
offset: offset,
node: child
});
offset = _nodeStream(child, offset);
result.push({
event: 'stop',
offset: offset,
node: child
});
}
}
return offset;
})(node, 0);
return result;
}
function mergeStreams(stream1, stream2, value) {
var processed = 0;
var result = '';
var nodeStack = [];
function selectStream() {
if (stream1.length && stream2.length) {
if (stream1[0].offset != stream2[0].offset)
return (stream1[0].offset < stream2[0].offset) ? stream1 : stream2;
else {
/*
To avoid starting the stream just before it should stop the order is
ensured that stream1 always starts first and closes last:
if (event1 == 'start' && event2 == 'start')
return stream1;
if (event1 == 'start' && event2 == 'stop')
return stream2;
if (event1 == 'stop' && event2 == 'start')
return stream1;
if (event1 == 'stop' && event2 == 'stop')
return stream2;
... which is collapsed to:
*/
return stream2[0].event == 'start' ? stream1 : stream2;
}
} else {
return stream1.length ? stream1 : stream2;
}
}
function open(node) {
function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"'};
return '<' + node.nodeName + Array.prototype.map.call(node.attributes, attr_str).join('') + '>';
}
while (stream1.length || stream2.length) {
var current = selectStream().splice(0, 1)[0];
result += escape(value.substr(processed, current.offset - processed));
processed = current.offset;
if ( current.event == 'start') {
result += open(current.node);
nodeStack.push(current.node);
} else if (current.event == 'stop') {
var node, i = nodeStack.length;
do {
i--;
node = nodeStack[i];
result += ('' + node.nodeName.toLowerCase() + '>');
} while (node != current.node);
nodeStack.splice(i, 1);
while (i < nodeStack.length) {
result += open(nodeStack[i]);
i++;
}
}
}
return result + escape(value.substr(processed));
}
/* Initialization */
function compileLanguage(language) {
function reStr(re) {
return (re && re.source) || re;
}
function langRe(value, global) {
return RegExp(
reStr(value),
'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
);
}
function compileMode(mode, parent) {
if (mode.compiled)
return;
mode.compiled = true;
var keywords = []; // used later with beginWithKeyword but filled as a side-effect of keywords compilation
if (mode.keywords) {
var compiled_keywords = {};
function flatten(className, str) {
str.split(' ').forEach(function(kw) {
var pair = kw.split('|');
compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1];
keywords.push(pair[0]);
});
}
mode.lexemsRe = langRe(mode.lexems || hljs.IDENT_RE + '(?!\\.)', true);
if (typeof mode.keywords == 'string') { // string
flatten('keyword', mode.keywords)
} else {
for (var className in mode.keywords) {
if (!mode.keywords.hasOwnProperty(className))
continue;
flatten(className, mode.keywords[className]);
}
}
mode.keywords = compiled_keywords;
}
if (parent) {
if (mode.beginWithKeyword) {
mode.begin = '\\b(' + keywords.join('|') + ')\\b(?!\\.)\\s*';
}
mode.beginRe = langRe(mode.begin ? mode.begin : '\\B|\\b');
if (!mode.end && !mode.endsWithParent)
mode.end = '\\B|\\b';
if (mode.end)
mode.endRe = langRe(mode.end);
mode.terminator_end = reStr(mode.end) || '';
if (mode.endsWithParent && parent.terminator_end)
mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end;
}
if (mode.illegal)
mode.illegalRe = langRe(mode.illegal);
if (mode.relevance === undefined)
mode.relevance = 1;
if (!mode.contains) {
mode.contains = [];
}
for (var i = 0; i < mode.contains.length; i++) {
if (mode.contains[i] == 'self') {
mode.contains[i] = mode;
}
compileMode(mode.contains[i], mode);
}
if (mode.starts) {
compileMode(mode.starts, parent);
}
var terminators = [];
for (var i = 0; i < mode.contains.length; i++) {
terminators.push(reStr(mode.contains[i].begin));
}
if (mode.terminator_end) {
terminators.push(reStr(mode.terminator_end));
}
if (mode.illegal) {
terminators.push(reStr(mode.illegal));
}
mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(s) {return null;}};
}
compileMode(language);
}