123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188 |
- /*
- Syntax highlighting with language autodetection.
- https://highlightjs.org/
- */
- (function(factory) {
- // Find the global object for export to both the browser and web workers.
- var globalObject = typeof window === 'object' && window ||
- typeof self === 'object' && self;
- // Setup highlight.js for different environments. First is Node.js or
- // CommonJS.
- // `nodeType` is checked to ensure that `exports` is not a HTML element.
- if(typeof exports !== 'undefined' && !exports.nodeType) {
- factory(exports);
- } else if(globalObject) {
- // Export hljs globally even when using AMD for cases when this script
- // is loaded with others that may still expect a global hljs.
- globalObject.hljs = factory({});
- // Finally register the global hljs with AMD.
- if(typeof define === 'function' && define.amd) {
- define([], function() {
- return globalObject.hljs;
- });
- }
- }
- }(function(hljs) {
- var showedUpgradeWarning = false;
- // Convenience variables for build-in objects
- var ArrayProto = [],
- objectKeys = Object.keys;
- // Global internal variables used within the highlight.js library.
- var languages = Object.create(null),
- aliases = Object.create(null);
- // safe/production mode - swallows more errors, tries to keep running
- // even if a single syntax or parse hits a fatal error
- var SAFE_MODE = true;
- // Regular expressions used throughout the highlight.js library.
- var noHighlightRe = /^(no-?highlight|plain|text)$/i,
- languagePrefixRe = /\blang(?:uage)?-([\w-]+)\b/i,
- fixMarkupRe = /((^(<[^>]+>|\t|)+|(?:\n)))/gm;
- // The object will be assigned by the build tool. It used to synchronize API
- // of external language files with minified version of the highlight.js library.
- var API_REPLACES;
- var spanEndTag = '</span>';
- var LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?";
- // Global options used when within external APIs. This is modified when
- // calling the `hljs.configure` function.
- var options = {
- hideUpgradeWarningAcceptNoSupportOrSecurityUpdates: false,
- classPrefix: 'hljs-',
- tabReplace: null,
- useBR: false,
- languages: undefined
- };
- // keywords that should have no default relevance value
- var COMMON_KEYWORDS = 'of and for in not or if then'.split(' ');
- /* Utility functions */
- function escape(value) {
- return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
- }
- function tag(node) {
- return node.nodeName.toLowerCase();
- }
- function testRe(re, lexeme) {
- var match = re && re.exec(lexeme);
- return match && match.index === 0;
- }
- function isNotHighlighted(language) {
- return noHighlightRe.test(language);
- }
- function blockLanguage(block) {
- var i, match, length, _class;
- var classes = block.className + ' ';
- classes += block.parentNode ? block.parentNode.className : '';
- // language-* takes precedence over non-prefixed class names.
- match = languagePrefixRe.exec(classes);
- if (match) {
- var language = getLanguage(match[1]);
- if (!language) {
- console.warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));
- console.warn("Falling back to no-highlight mode for this block.", block);
- }
- return language ? match[1] : 'no-highlight';
- }
- classes = classes.split(/\s+/);
- for (i = 0, length = classes.length; i < length; i++) {
- _class = classes[i];
- if (isNotHighlighted(_class) || getLanguage(_class)) {
- return _class;
- }
- }
- }
- /**
- * performs a shallow merge of multiple objects into one
- *
- * @arguments list of objects with properties to merge
- * @returns a single new object
- */
- function inherit(parent) { // inherit(parent, override_obj, override_obj, ...)
- var key;
- var result = {};
- var objects = Array.prototype.slice.call(arguments, 1);
- for (key in parent)
- result[key] = parent[key];
- objects.forEach(function(obj) {
- for (key in obj)
- result[key] = obj[key];
- });
- return result;
- }
- /* 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.nodeType === 1) {
- result.push({
- event: 'start',
- offset: offset,
- node: child
- });
- offset = _nodeStream(child, offset);
- // Prevent void elements from having an end tag that would actually
- // double them in the output. There are more void elements in HTML
- // but we list only those realistically expected in code display.
- if (!tag(child).match(/br|hr|img|input/)) {
- result.push({
- event: 'stop',
- offset: offset,
- node: child
- });
- }
- }
- }
- return offset;
- })(node, 0);
- return result;
- }
- function mergeStreams(original, highlighted, value) {
- var processed = 0;
- var result = '';
- var nodeStack = [];
- function selectStream() {
- if (!original.length || !highlighted.length) {
- return original.length ? original : highlighted;
- }
- if (original[0].offset !== highlighted[0].offset) {
- return (original[0].offset < highlighted[0].offset) ? original : highlighted;
- }
- /*
- To avoid starting the stream just before it should stop the order is
- ensured that original always starts first and closes last:
- if (event1 == 'start' && event2 == 'start')
- return original;
- if (event1 == 'start' && event2 == 'stop')
- return highlighted;
- if (event1 == 'stop' && event2 == 'start')
- return original;
- if (event1 == 'stop' && event2 == 'stop')
- return highlighted;
- ... which is collapsed to:
- */
- return highlighted[0].event === 'start' ? original : highlighted;
- }
- function open(node) {
- function attr_str(a) {
- return ' ' + a.nodeName + '="' + escape(a.value).replace(/"/g, '"') + '"';
- }
- result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>';
- }
- function close(node) {
- result += '</' + tag(node) + '>';
- }
- function render(event) {
- (event.event === 'start' ? open : close)(event.node);
- }
- while (original.length || highlighted.length) {
- var stream = selectStream();
- result += escape(value.substring(processed, stream[0].offset));
- processed = stream[0].offset;
- if (stream === original) {
- /*
- On any opening or closing tag of the original markup we first close
- the entire highlighted node stack, then render the original tag along
- with all the following original tags at the same offset and then
- reopen all the tags on the highlighted stack.
- */
- nodeStack.reverse().forEach(close);
- do {
- render(stream.splice(0, 1)[0]);
- stream = selectStream();
- } while (stream === original && stream.length && stream[0].offset === processed);
- nodeStack.reverse().forEach(open);
- } else {
- if (stream[0].event === 'start') {
- nodeStack.push(stream[0].node);
- } else {
- nodeStack.pop();
- }
- render(stream.splice(0, 1)[0]);
- }
- }
- return result + escape(value.substr(processed));
- }
- /* Initialization */
- function dependencyOnParent(mode) {
- if (!mode) return false;
- return mode.endsWithParent || dependencyOnParent(mode.starts);
- }
- function expand_or_clone_mode(mode) {
- if (mode.variants && !mode.cached_variants) {
- mode.cached_variants = mode.variants.map(function(variant) {
- return inherit(mode, {variants: null}, variant);
- });
- }
- // EXPAND
- // if we have variants then essentially "replace" the mode with the variants
- // this happens in compileMode, where this function is called from
- if (mode.cached_variants)
- return mode.cached_variants;
- // CLONE
- // if we have dependencies on parents then we need a unique
- // instance of ourselves, so we can be reused with many
- // different parents without issue
- if (dependencyOnParent(mode))
- return [inherit(mode, { starts: mode.starts ? inherit(mode.starts) : null })];
- if (Object.isFrozen(mode))
- return [inherit(mode)];
- // no special dependency issues, just return ourselves
- return [mode];
- }
- function restoreLanguageApi(obj) {
- if(API_REPLACES && !obj.langApiRestored) {
- obj.langApiRestored = true;
- for(var key in API_REPLACES) {
- if (obj[key]) {
- obj[API_REPLACES[key]] = obj[key];
- }
- }
- (obj.contains || []).concat(obj.variants || []).forEach(restoreLanguageApi);
- }
- }
- function compileKeywords(rawKeywords, case_insensitive) {
- var compiled_keywords = {};
- if (typeof rawKeywords === 'string') { // string
- splitAndCompile('keyword', rawKeywords);
- } else {
- objectKeys(rawKeywords).forEach(function (className) {
- splitAndCompile(className, rawKeywords[className]);
- });
- }
- return compiled_keywords;
- // ---
- function splitAndCompile(className, str) {
- if (case_insensitive) {
- str = str.toLowerCase();
- }
- str.split(' ').forEach(function(keyword) {
- var pair = keyword.split('|');
- compiled_keywords[pair[0]] = [className, scoreForKeyword(pair[0], pair[1])];
- });
- }
- }
- function scoreForKeyword(keyword, providedScore) {
- // manual scores always win over common keywords
- // so you can force a score of 1 if you really insist
- if (providedScore)
- return Number(providedScore);
- return commonKeyword(keyword) ? 0 : 1;
- }
- function commonKeyword(word) {
- return COMMON_KEYWORDS.indexOf(word.toLowerCase()) != -1;
- }
- function compileLanguage(language) {
- function reStr(re) {
- return (re && re.source) || re;
- }
- function langRe(value, global) {
- return new RegExp(
- reStr(value),
- 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
- );
- }
- function reCountMatchGroups(re) {
- return (new RegExp(re.toString() + '|')).exec('').length - 1;
- }
- // joinRe logically computes regexps.join(separator), but fixes the
- // backreferences so they continue to match.
- // it also places each individual regular expression into it's own
- // match group, keeping track of the sequencing of those match groups
- // is currently an exercise for the caller. :-)
- function joinRe(regexps, separator) {
- // backreferenceRe matches an open parenthesis or backreference. To avoid
- // an incorrect parse, it additionally matches the following:
- // - [...] elements, where the meaning of parentheses and escapes change
- // - other escape sequences, so we do not misparse escape sequences as
- // interesting elements
- // - non-matching or lookahead parentheses, which do not capture. These
- // follow the '(' with a '?'.
- var backreferenceRe = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
- var numCaptures = 0;
- var ret = '';
- for (var i = 0; i < regexps.length; i++) {
- numCaptures += 1;
- var offset = numCaptures;
- var re = reStr(regexps[i]);
- if (i > 0) {
- ret += separator;
- }
- ret += "(";
- while (re.length > 0) {
- var match = backreferenceRe.exec(re);
- if (match == null) {
- ret += re;
- break;
- }
- ret += re.substring(0, match.index);
- re = re.substring(match.index + match[0].length);
- if (match[0][0] == '\\' && match[1]) {
- // Adjust the backreference.
- ret += '\\' + String(Number(match[1]) + offset);
- } else {
- ret += match[0];
- if (match[0] == '(') {
- numCaptures++;
- }
- }
- }
- ret += ")";
- }
- return ret;
- }
- function buildModeRegex(mode) {
- var matchIndexes = {};
- var matcherRe;
- var regexes = [];
- var matcher = {};
- var matchAt = 1;
- function addRule(rule, regex) {
- matchIndexes[matchAt] = rule;
- regexes.push([rule, regex]);
- matchAt += reCountMatchGroups(regex) + 1;
- }
- var term;
- for (var i=0; i < mode.contains.length; i++) {
- var re;
- term = mode.contains[i];
- if (term.beginKeywords) {
- re = '\\.?(?:' + term.begin + ')\\.?';
- } else {
- re = term.begin;
- }
- addRule(term, re);
- }
- if (mode.terminator_end)
- addRule("end", mode.terminator_end);
- if (mode.illegal)
- addRule("illegal", mode.illegal);
- var terminators = regexes.map(function(el) { return el[1]; });
- matcherRe = langRe(joinRe(terminators, '|'), true);
- matcher.lastIndex = 0;
- matcher.exec = function(s) {
- var rule;
- if( regexes.length === 0) return null;
- matcherRe.lastIndex = matcher.lastIndex;
- var match = matcherRe.exec(s);
- if (!match) { return null; }
- for(var i = 0; i<match.length; i++) {
- if (match[i] != undefined && matchIndexes["" +i] != undefined ) {
- rule = matchIndexes[""+i];
- break;
- }
- }
- // illegal or end match
- if (typeof rule === "string") {
- match.type = rule;
- match.extra = [mode.illegal, mode.terminator_end];
- } else {
- match.type = "begin";
- match.rule = rule;
- }
- return match;
- };
- return matcher;
- }
- function compileMode(mode, parent) {
- if (mode.compiled)
- return;
- mode.compiled = true;
- mode.keywords = mode.keywords || mode.beginKeywords;
- if (mode.keywords)
- mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);
- mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);
- if (parent) {
- if (mode.beginKeywords) {
- mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b';
- }
- if (!mode.begin)
- mode.begin = /\B|\b/;
- mode.beginRe = langRe(mode.begin);
- if (mode.endSameAsBegin)
- mode.end = mode.begin;
- 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 == null)
- mode.relevance = 1;
- if (!mode.contains) {
- mode.contains = [];
- }
- mode.contains = Array.prototype.concat.apply([], mode.contains.map(function(c) {
- return expand_or_clone_mode(c === 'self' ? mode : c);
- }));
- mode.contains.forEach(function(c) {compileMode(c, mode);});
- if (mode.starts) {
- compileMode(mode.starts, parent);
- }
- mode.terminators = buildModeRegex(mode);
- }
- // self is not valid at the top-level
- if (language.contains && language.contains.indexOf('self') != -1) {
- if (!SAFE_MODE) {
- throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
- } else {
- // silently remove the broken rule (effectively ignoring it), this has historically
- // been the behavior in the past, so this removal preserves compatibility with broken
- // grammars when running in Safe Mode
- language.contains = language.contains.filter(function(mode) { return mode != 'self'; });
- }
- }
- compileMode(language);
- }
- function hideUpgradeWarning() {
- if (options.hideUpgradeWarningAcceptNoSupportOrSecurityUpdates)
- return true;
- if (typeof process === "object" && typeof process.env === "object" && process.env["HLJS_HIDE_UPGRADE_WARNING"])
- return true;
- }
- /**
- * Core highlighting function.
- *
- * @param {string} languageName - the language to use for highlighting
- * @param {string} code - the code to highlight
- * @param {boolean} ignore_illegals - whether to ignore illegal matches, default is to bail
- * @param {array<mode>} continuation - array of continuation modes
- *
- * @returns an object that represents the result
- * @property {string} language - the language name
- * @property {number} relevance - the relevance score
- * @property {string} value - the highlighted HTML code
- * @property {mode} top - top of the current mode stack
- * @property {boolean} illegal - indicates whether any illegal matches were found
- */
- function highlight(languageName, code, ignore_illegals, continuation) {
- if (!hideUpgradeWarning()) {
- if (!showedUpgradeWarning) {
- showedUpgradeWarning = true;
- console.log(
- "Version 9 of Highlight.js has reached EOL and is no longer supported.\n" +
- "Please upgrade or ask whatever dependency you are using to upgrade.\n" +
- "https://github.com/highlightjs/highlight.js/issues/2877"
- );
- }
- }
- var codeToHighlight = code;
- function escapeRe(value) {
- return new RegExp(value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
- }
- function endOfMode(mode, lexeme) {
- if (testRe(mode.endRe, lexeme)) {
- while (mode.endsParent && mode.parent) {
- mode = mode.parent;
- }
- return mode;
- }
- if (mode.endsWithParent) {
- return endOfMode(mode.parent, lexeme);
- }
- }
- function keywordMatch(mode, match) {
- var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0];
- return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str];
- }
- function buildSpan(className, insideSpan, leaveOpen, noPrefix) {
- if (!leaveOpen && insideSpan === '') return '';
- if (!className) return insideSpan;
- var classPrefix = noPrefix ? '' : options.classPrefix,
- openSpan = '<span class="' + classPrefix,
- closeSpan = leaveOpen ? '' : spanEndTag;
- openSpan += className + '">';
- return openSpan + insideSpan + closeSpan;
- }
- function processKeywords() {
- var keyword_match, last_index, match, result;
- if (!top.keywords)
- return escape(mode_buffer);
- result = '';
- last_index = 0;
- top.lexemesRe.lastIndex = 0;
- match = top.lexemesRe.exec(mode_buffer);
- while (match) {
- result += escape(mode_buffer.substring(last_index, match.index));
- keyword_match = keywordMatch(top, match);
- if (keyword_match) {
- relevance += keyword_match[1];
- result += buildSpan(keyword_match[0], escape(match[0]));
- } else {
- result += escape(match[0]);
- }
- last_index = top.lexemesRe.lastIndex;
- match = top.lexemesRe.exec(mode_buffer);
- }
- return result + escape(mode_buffer.substr(last_index));
- }
- function processSubLanguage() {
- var explicit = typeof top.subLanguage === 'string';
- if (explicit && !languages[top.subLanguage]) {
- return escape(mode_buffer);
- }
- var result = explicit ?
- highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) :
- highlightAuto(mode_buffer, top.subLanguage.length ? top.subLanguage : undefined);
- // Counting embedded language score towards the host language may be disabled
- // with zeroing the containing mode relevance. Use case in point is Markdown that
- // allows XML everywhere and makes every XML snippet to have a much larger Markdown
- // score.
- if (top.relevance > 0) {
- relevance += result.relevance;
- }
- if (explicit) {
- continuations[top.subLanguage] = result.top;
- }
- return buildSpan(result.language, result.value, false, true);
- }
- function processBuffer() {
- result += (top.subLanguage != null ? processSubLanguage() : processKeywords());
- mode_buffer = '';
- }
- function startNewMode(mode) {
- result += mode.className? buildSpan(mode.className, '', true): '';
- top = Object.create(mode, {parent: {value: top}});
- }
- function doBeginMatch(match) {
- var lexeme = match[0];
- var new_mode = match.rule;
- if (new_mode && new_mode.endSameAsBegin) {
- new_mode.endRe = escapeRe( lexeme );
- }
- if (new_mode.skip) {
- mode_buffer += lexeme;
- } else {
- if (new_mode.excludeBegin) {
- mode_buffer += lexeme;
- }
- processBuffer();
- if (!new_mode.returnBegin && !new_mode.excludeBegin) {
- mode_buffer = lexeme;
- }
- }
- startNewMode(new_mode);
- return new_mode.returnBegin ? 0 : lexeme.length;
- }
- function doEndMatch(match) {
- var lexeme = match[0];
- var matchPlusRemainder = codeToHighlight.substr(match.index);
- var end_mode = endOfMode(top, matchPlusRemainder);
- if (!end_mode) { return; }
- var origin = top;
- if (origin.skip) {
- mode_buffer += lexeme;
- } else {
- if (!(origin.returnEnd || origin.excludeEnd)) {
- mode_buffer += lexeme;
- }
- processBuffer();
- if (origin.excludeEnd) {
- mode_buffer = lexeme;
- }
- }
- do {
- if (top.className) {
- result += spanEndTag;
- }
- if (!top.skip && !top.subLanguage) {
- relevance += top.relevance;
- }
- top = top.parent;
- } while (top !== end_mode.parent);
- if (end_mode.starts) {
- if (end_mode.endSameAsBegin) {
- end_mode.starts.endRe = end_mode.endRe;
- }
- startNewMode(end_mode.starts);
- }
- return origin.returnEnd ? 0 : lexeme.length;
- }
- var lastMatch = {};
- function processLexeme(text_before_match, match) {
- var lexeme = match && match[0];
- // add non-matched text to the current mode buffer
- mode_buffer += text_before_match;
- if (lexeme == null) {
- processBuffer();
- return 0;
- }
- // we've found a 0 width match and we're stuck, so we need to advance
- // this happens when we have badly behaved rules that have optional matchers to the degree that
- // sometimes they can end up matching nothing at all
- // Ref: https://github.com/highlightjs/highlight.js/issues/2140
- if (lastMatch.type=="begin" && match.type=="end" && lastMatch.index == match.index && lexeme === "") {
- // spit the "skipped" character that our regex choked on back into the output sequence
- mode_buffer += codeToHighlight.slice(match.index, match.index + 1);
- return 1;
- }
- // edge case for when illegal matches $ (end of line) which is technically
- // a 0 width match but not a begin/end match so it's not caught by the
- // first handler (when ignoreIllegals is true)
- // https://github.com/highlightjs/highlight.js/issues/2522
- if (lastMatch.type==="illegal" && lexeme === "") {
- mode_buffer += codeToHighlight.slice(match.index, match.index + 1);
- return 1;
- }
- lastMatch = match;
- if (match.type==="begin") {
- return doBeginMatch(match);
- } else if (match.type==="illegal" && !ignore_illegals) {
- // illegal match, we do not continue processing
- throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '<unnamed>') + '"');
- } else if (match.type==="end") {
- var processed = doEndMatch(match);
- if (processed != undefined)
- return processed;
- }
- /*
- Why might be find ourselves here? Only one occasion now. An end match that was
- triggered but could not be completed. When might this happen? When an `endSameasBegin`
- rule sets the end rule to a specific match. Since the overall mode termination rule that's
- being used to scan the text isn't recompiled that means that any match that LOOKS like
- the end (but is not, because it is not an exact match to the beginning) will
- end up here. A definite end match, but when `doEndMatch` tries to "reapply"
- the end rule and fails to match, we wind up here, and just silently ignore the end.
- This causes no real harm other than stopping a few times too many.
- */
- mode_buffer += lexeme;
- return lexeme.length;
- }
- var language = getLanguage(languageName);
- if (!language) {
- console.error(LANGUAGE_NOT_FOUND.replace("{}", languageName));
- throw new Error('Unknown language: "' + languageName + '"');
- }
- compileLanguage(language);
- var top = continuation || language;
- var continuations = {}; // keep continuations for sub-languages
- var result = '', current;
- for(current = top; current !== language; current = current.parent) {
- if (current.className) {
- result = buildSpan(current.className, '', true) + result;
- }
- }
- var mode_buffer = '';
- var relevance = 0;
- try {
- var match, count, index = 0;
- while (true) {
- top.terminators.lastIndex = index;
- match = top.terminators.exec(codeToHighlight);
- if (!match)
- break;
- count = processLexeme(codeToHighlight.substring(index, match.index), match);
- index = match.index + count;
- }
- processLexeme(codeToHighlight.substr(index));
- for(current = top; current.parent; current = current.parent) { // close dangling modes
- if (current.className) {
- result += spanEndTag;
- }
- }
- return {
- relevance: relevance,
- value: result,
- illegal:false,
- language: languageName,
- top: top
- };
- } catch (err) {
- if (err.message && err.message.indexOf('Illegal') !== -1) {
- return {
- illegal: true,
- relevance: 0,
- value: escape(codeToHighlight)
- };
- } else if (SAFE_MODE) {
- return {
- relevance: 0,
- value: escape(codeToHighlight),
- language: languageName,
- top: top,
- errorRaised: err
- };
- } else {
- throw err;
- }
- }
- }
- /*
- Highlighting with language detection. Accepts a string with the code to
- highlight. Returns an object with the following properties:
- - language (detected language)
- - relevance (int)
- - value (an HTML string with highlighting markup)
- - second_best (object with the same structure for second-best heuristically
- detected language, may be absent)
- */
- function highlightAuto(code, languageSubset) {
- languageSubset = languageSubset || options.languages || objectKeys(languages);
- var result = {
- relevance: 0,
- value: escape(code)
- };
- var second_best = result;
- languageSubset.filter(getLanguage).filter(autoDetection).forEach(function(name) {
- var current = highlight(name, code, false);
- current.language = name;
- if (current.relevance > second_best.relevance) {
- second_best = current;
- }
- if (current.relevance > result.relevance) {
- second_best = result;
- result = current;
- }
- });
- if (second_best.language) {
- result.second_best = second_best;
- }
- return result;
- }
- /*
- Post-processing of the highlighted markup:
- - replace TABs with something more useful
- - replace real line-breaks with '<br>' for non-pre containers
- */
- function fixMarkup(value) {
- if (!(options.tabReplace || options.useBR)) {
- return value;
- }
- return value.replace(fixMarkupRe, function(match, p1) {
- if (options.useBR && match === '\n') {
- return '<br>';
- } else if (options.tabReplace) {
- return p1.replace(/\t/g, options.tabReplace);
- }
- return '';
- });
- }
- function buildClassName(prevClassName, currentLang, resultLang) {
- var language = currentLang ? aliases[currentLang] : resultLang,
- result = [prevClassName.trim()];
- if (!prevClassName.match(/\bhljs\b/)) {
- result.push('hljs');
- }
- if (prevClassName.indexOf(language) === -1) {
- result.push(language);
- }
- return result.join(' ').trim();
- }
- /*
- Applies highlighting to a DOM node containing code. Accepts a DOM node and
- two optional parameters for fixMarkup.
- */
- function highlightBlock(block) {
- var node, originalStream, result, resultNode, text;
- var language = blockLanguage(block);
- if (isNotHighlighted(language))
- return;
- if (options.useBR) {
- node = document.createElement('div');
- node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(/<br[ \/]*>/g, '\n');
- } else {
- node = block;
- }
- text = node.textContent;
- result = language ? highlight(language, text, true) : highlightAuto(text);
- originalStream = nodeStream(node);
- if (originalStream.length) {
- resultNode = document.createElement('div');
- resultNode.innerHTML = result.value;
- result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
- }
- result.value = fixMarkup(result.value);
- block.innerHTML = result.value;
- block.className = buildClassName(block.className, language, result.language);
- block.result = {
- language: result.language,
- re: result.relevance
- };
- if (result.second_best) {
- block.second_best = {
- language: result.second_best.language,
- re: result.second_best.relevance
- };
- }
- }
- /*
- Updates highlight.js global options with values passed in the form of an object.
- */
- function configure(user_options) {
- options = inherit(options, user_options);
- }
- /*
- Applies highlighting to all <pre><code>..</code></pre> blocks on a page.
- */
- function initHighlighting() {
- if (initHighlighting.called)
- return;
- initHighlighting.called = true;
- var blocks = document.querySelectorAll('pre code');
- ArrayProto.forEach.call(blocks, highlightBlock);
- }
- /*
- Attaches highlighting to the page load event.
- */
- function initHighlightingOnLoad() {
- window.addEventListener('DOMContentLoaded', initHighlighting, false);
- window.addEventListener('load', initHighlighting, false);
- }
- var PLAINTEXT_LANGUAGE = { disableAutodetect: true };
- function registerLanguage(name, language) {
- var lang;
- try { lang = language(hljs); }
- catch (error) {
- console.error("Language definition for '{}' could not be registered.".replace("{}", name));
- // hard or soft error
- if (!SAFE_MODE) { throw error; } else { console.error(error); }
- // languages that have serious errors are replaced with essentially a
- // "plaintext" stand-in so that the code blocks will still get normal
- // css classes applied to them - and one bad language won't break the
- // entire highlighter
- lang = PLAINTEXT_LANGUAGE;
- }
- languages[name] = lang;
- restoreLanguageApi(lang);
- lang.rawDefinition = language.bind(null,hljs);
- if (lang.aliases) {
- lang.aliases.forEach(function(alias) {aliases[alias] = name;});
- }
- }
- function listLanguages() {
- return objectKeys(languages);
- }
- /*
- intended usage: When one language truly requires another
- Unlike `getLanguage`, this will throw when the requested language
- is not available.
- */
- function requireLanguage(name) {
- var lang = getLanguage(name);
- if (lang) { return lang; }
- var err = new Error('The \'{}\' language is required, but not loaded.'.replace('{}',name));
- throw err;
- }
- function getLanguage(name) {
- name = (name || '').toLowerCase();
- return languages[name] || languages[aliases[name]];
- }
- function autoDetection(name) {
- var lang = getLanguage(name);
- return lang && !lang.disableAutodetect;
- }
- /* Interface definition */
- hljs.highlight = highlight;
- hljs.highlightAuto = highlightAuto;
- hljs.fixMarkup = fixMarkup;
- hljs.highlightBlock = highlightBlock;
- hljs.configure = configure;
- hljs.initHighlighting = initHighlighting;
- hljs.initHighlightingOnLoad = initHighlightingOnLoad;
- hljs.registerLanguage = registerLanguage;
- hljs.listLanguages = listLanguages;
- hljs.getLanguage = getLanguage;
- hljs.requireLanguage = requireLanguage;
- hljs.autoDetection = autoDetection;
- hljs.inherit = inherit;
- hljs.debugMode = function() { SAFE_MODE = false; }
- // Common regexps
- hljs.IDENT_RE = '[a-zA-Z]\\w*';
- hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
- hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
- hljs.C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float
- hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
- hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
- // Common modes
- hljs.BACKSLASH_ESCAPE = {
- begin: '\\\\[\\s\\S]', relevance: 0
- };
- hljs.APOS_STRING_MODE = {
- className: 'string',
- begin: '\'', end: '\'',
- illegal: '\\n',
- contains: [hljs.BACKSLASH_ESCAPE]
- };
- hljs.QUOTE_STRING_MODE = {
- className: 'string',
- begin: '"', end: '"',
- illegal: '\\n',
- contains: [hljs.BACKSLASH_ESCAPE]
- };
- hljs.PHRASAL_WORDS_MODE = {
- begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
- };
- hljs.COMMENT = function (begin, end, inherits) {
- var mode = hljs.inherit(
- {
- className: 'comment',
- begin: begin, end: end,
- contains: []
- },
- inherits || {}
- );
- mode.contains.push(hljs.PHRASAL_WORDS_MODE);
- mode.contains.push({
- className: 'doctag',
- begin: '(?:TODO|FIXME|NOTE|BUG|XXX):',
- relevance: 0
- });
- return mode;
- };
- hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$');
- hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/');
- hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$');
- hljs.NUMBER_MODE = {
- className: 'number',
- begin: hljs.NUMBER_RE,
- relevance: 0
- };
- hljs.C_NUMBER_MODE = {
- className: 'number',
- begin: hljs.C_NUMBER_RE,
- relevance: 0
- };
- hljs.BINARY_NUMBER_MODE = {
- className: 'number',
- begin: hljs.BINARY_NUMBER_RE,
- relevance: 0
- };
- hljs.CSS_NUMBER_MODE = {
- className: 'number',
- begin: hljs.NUMBER_RE + '(' +
- '%|em|ex|ch|rem' +
- '|vw|vh|vmin|vmax' +
- '|cm|mm|in|pt|pc|px' +
- '|deg|grad|rad|turn' +
- '|s|ms' +
- '|Hz|kHz' +
- '|dpi|dpcm|dppx' +
- ')?',
- relevance: 0
- };
- hljs.REGEXP_MODE = {
- className: 'regexp',
- begin: /\//, end: /\/[gimuy]*/,
- illegal: /\n/,
- contains: [
- hljs.BACKSLASH_ESCAPE,
- {
- begin: /\[/, end: /\]/,
- relevance: 0,
- contains: [hljs.BACKSLASH_ESCAPE]
- }
- ]
- };
- hljs.TITLE_MODE = {
- className: 'title',
- begin: hljs.IDENT_RE,
- relevance: 0
- };
- hljs.UNDERSCORE_TITLE_MODE = {
- className: 'title',
- begin: hljs.UNDERSCORE_IDENT_RE,
- relevance: 0
- };
- hljs.METHOD_GUARD = {
- // excludes method names from keyword processing
- begin: '\\.\\s*' + hljs.UNDERSCORE_IDENT_RE,
- relevance: 0
- };
- var constants = [
- hljs.BACKSLASH_ESCAPE,
- hljs.APOS_STRING_MODE,
- hljs.QUOTE_STRING_MODE,
- hljs.PHRASAL_WORDS_MODE,
- hljs.COMMENT,
- hljs.C_LINE_COMMENT_MODE,
- hljs.C_BLOCK_COMMENT_MODE,
- hljs.HASH_COMMENT_MODE,
- hljs.NUMBER_MODE,
- hljs.C_NUMBER_MODE,
- hljs.BINARY_NUMBER_MODE,
- hljs.CSS_NUMBER_MODE,
- hljs.REGEXP_MODE,
- hljs.TITLE_MODE,
- hljs.UNDERSCORE_TITLE_MODE,
- hljs.METHOD_GUARD
- ]
- constants.forEach(function(obj) { deepFreeze(obj); });
- // https://github.com/substack/deep-freeze/blob/master/index.js
- function deepFreeze (o) {
- Object.freeze(o);
- var objIsFunction = typeof o === 'function';
- Object.getOwnPropertyNames(o).forEach(function (prop) {
- if (o.hasOwnProperty(prop)
- && o[prop] !== null
- && (typeof o[prop] === "object" || typeof o[prop] === "function")
- // IE11 fix: https://github.com/highlightjs/highlight.js/issues/2318
- // TODO: remove in the future
- && (objIsFunction ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments' : true)
- && !Object.isFrozen(o[prop])) {
- deepFreeze(o[prop]);
- }
- });
- return o;
- };
- return hljs;
- }));
|