[epiphany] Distribute an unpacked highlight.js version
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] Distribute an unpacked highlight.js version
- Date: Fri, 1 May 2020 16:54:23 +0000 (UTC)
commit d9b959ae543fec83673fcf7a3701cb4052313b4f
Author: Jan-Michael Brummer <jan brummer tabos org>
Date: Fri May 1 18:41:34 2020 +0200
Distribute an unpacked highlight.js version
Fixes: https://gitlab.gnome.org/GNOME/epiphany/-/issues/1173
embed/ephy-view-source-handler.c | 2 +-
third-party/highlightjs/README.epiphany | 12 +-
third-party/highlightjs/highlight.js | 2141 +++++++++++++++++++++
third-party/highlightjs/highlight.pack.js | 6 -
third-party/highlightjs/highlightjs.gresource.xml | 2 +-
5 files changed, 2153 insertions(+), 10 deletions(-)
---
diff --git a/embed/ephy-view-source-handler.c b/embed/ephy-view-source-handler.c
index 2164cebd3..d39a3553a 100644
--- a/embed/ephy-view-source-handler.c
+++ b/embed/ephy-view-source-handler.c
@@ -128,7 +128,7 @@ web_resource_data_cb (WebKitWebResource *resource,
" <title>%s</title>"
"</head>"
"<body class='hljs'>"
- " <script
src='ephy-resource:///org/gnome/epiphany/highlightjs/highlight.pack.js'></script>"
+ " <script
src='ephy-resource:///org/gnome/epiphany/highlightjs/highlight.js'></script>"
" <script>hljs.initHighlightingOnLoad();</script>"
" <pre><code class='html'>%s</code></pre>"
"</body>",
diff --git a/third-party/highlightjs/README.epiphany b/third-party/highlightjs/README.epiphany
index dc98cffe3..3a751f4cb 100644
--- a/third-party/highlightjs/README.epiphany
+++ b/third-party/highlightjs/README.epiphany
@@ -1,8 +1,16 @@
# Embedded source code highlighter based on hightlight.js
-This directory contains an official highlight.js release version, distributed at:
https://highlightjs.org/download/
+This directory contains an official highlight.js release version, distributed at:
https://github.com/highlightjs/highlight.js
## Update process
-Download a new official release (select HTML,XML / CSS / JavaScript) and move highlight.pack.js and
styles/default.css into this directory.
+
+git clone https://github.com/highlightjs/highlight.js.git
+cd highlight.js
+git checkout <version number>
+npm install
+node tools/build.js -n css javascript xml
+
+Copy build/highlight.js to <epiphany-source>/third-party/highlightjs/
+Copy src/styles/default.css to <epiphany-source>third-party/highlightjs/
# Documentation created by Jan-Michael Brummer <jan brummer tabos org>
diff --git a/third-party/highlightjs/highlight.js b/third-party/highlightjs/highlight.js
new file mode 100644
index 000000000..13bb1e9e8
--- /dev/null
+++ b/third-party/highlightjs/highlight.js
@@ -0,0 +1,2141 @@
+/*
+ Highlight.js 10.0.1 (33af2ea5)
+ License: BSD-3-Clause
+ Copyright (c) 2006-2020, Ivan Sagalaev
+*/
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global = global || self, global.hljs = factory());
+}(this, (function () { 'use strict';
+
+ // 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;
+ }
+
+ function escapeHTML(value) {
+ return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
+ }
+
+
+
+ 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 tag(node) {
+ return node.nodeName.toLowerCase();
+ }
+
+
+ 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 + '="' + escapeHTML(a.value).replace(/"/g, '"') + '"';
+ }
+ result += '<' + tag(node) + [].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 += escapeHTML(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 + escapeHTML(value.substr(processed));
+ }
+
+ var utils = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ escapeHTML: escapeHTML,
+ inherit: inherit,
+ nodeStream: nodeStream,
+ mergeStreams: mergeStreams
+ });
+
+ const SPAN_CLOSE = '</span>';
+
+ const emitsWrappingTags = (node) => {
+ return !!node.kind;
+ };
+
+ class HTMLRenderer {
+ constructor(tree, options) {
+ this.buffer = "";
+ this.classPrefix = options.classPrefix;
+ tree.walk(this);
+ }
+
+ // renderer API
+
+ addText(text) {
+ this.buffer += escapeHTML(text);
+ }
+
+ openNode(node) {
+ if (!emitsWrappingTags(node)) return;
+
+ let className = node.kind;
+ if (!node.sublanguage)
+ className = `${this.classPrefix}${className}`;
+ this.span(className);
+ }
+
+ closeNode(node) {
+ if (!emitsWrappingTags(node)) return;
+
+ this.buffer += SPAN_CLOSE;
+ }
+
+ // helpers
+
+ span(className) {
+ this.buffer += `<span class="${className}">`;
+ }
+
+ value() {
+ return this.buffer;
+ }
+ }
+
+ class TokenTree {
+ constructor() {
+ this.rootNode = { children: [] };
+ this.stack = [ this.rootNode ];
+ }
+
+ get top() {
+ return this.stack[this.stack.length - 1];
+ }
+
+ get root() { return this.rootNode };
+
+ add(node) {
+ this.top.children.push(node);
+ }
+
+ openNode(kind) {
+ let node = { kind, children: [] };
+ this.add(node);
+ this.stack.push(node);
+ }
+
+ closeNode() {
+ if (this.stack.length > 1)
+ return this.stack.pop();
+ }
+
+ closeAllNodes() {
+ while (this.closeNode());
+ }
+
+ toJSON() {
+ return JSON.stringify(this.rootNode, null, 4);
+ }
+
+ walk(builder) {
+ return this.constructor._walk(builder, this.rootNode);
+ }
+
+ static _walk(builder, node) {
+ if (typeof node === "string") {
+ builder.addText(node);
+ } else if (node.children) {
+ builder.openNode(node);
+ node.children.forEach((child) => this._walk(builder, child));
+ builder.closeNode(node);
+ }
+ return builder;
+ }
+
+ static _collapse(node) {
+ if (!node.children) {
+ return;
+ }
+ if (node.children.every(el => typeof el === "string")) {
+ node.text = node.children.join("");
+ delete node["children"];
+ } else {
+ node.children.forEach((child) => {
+ if (typeof child === "string") return;
+ TokenTree._collapse(child);
+ });
+ }
+ }
+ }
+
+ /**
+ Currently this is all private API, but this is the minimal API necessary
+ that an Emitter must implement to fully support the parser.
+
+ Minimal interface:
+
+ - addKeyword(text, kind)
+ - addText(text)
+ - addSublanguage(emitter, subLangaugeName)
+ - finalize()
+ - openNode(kind)
+ - closeNode()
+ - closeAllNodes()
+ - toHTML()
+
+ */
+ class TokenTreeEmitter extends TokenTree {
+ constructor(options) {
+ super();
+ this.options = options;
+ }
+
+ addKeyword(text, kind) {
+ if (text === "") { return; }
+
+ this.openNode(kind);
+ this.addText(text);
+ this.closeNode();
+ }
+
+ addText(text) {
+ if (text === "") { return; }
+
+ this.add(text);
+ }
+
+ addSublanguage(emitter, name) {
+ let node = emitter.root;
+ node.kind = name;
+ node.sublanguage = true;
+ this.add(node);
+ }
+
+ toHTML() {
+ let renderer = new HTMLRenderer(this, this.options);
+ return renderer.value();
+ }
+
+ finalize() {
+ return;
+ }
+
+ }
+
+ function escape(value) {
+ return new RegExp(value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
+ }
+
+ function source(re) {
+ // if it's a regex get it's source,
+ // otherwise it's a string already so just return it
+ return (re && re.source) || re;
+ }
+
+ function countMatchGroups(re) {
+ return (new RegExp(re.toString() + '|')).exec('').length - 1;
+ }
+
+ function startsWith(re, lexeme) {
+ var match = re && re.exec(lexeme);
+ return match && match.index === 0;
+ }
+
+ // join 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 join(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 = source(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;
+ }
+
+ // Common regexps
+ const IDENT_RE = '[a-zA-Z]\\w*';
+ const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
+ const NUMBER_RE = '\\b\\d+(\\.\\d+)?';
+ const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x...,
0..., decimal, float
+ const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
+ const RE_STARTERS_RE =
'!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
+
+ // Common modes
+ const BACKSLASH_ESCAPE = {
+ begin: '\\\\[\\s\\S]', relevance: 0
+ };
+ const APOS_STRING_MODE = {
+ className: 'string',
+ begin: '\'', end: '\'',
+ illegal: '\\n',
+ contains: [BACKSLASH_ESCAPE]
+ };
+ const QUOTE_STRING_MODE = {
+ className: 'string',
+ begin: '"', end: '"',
+ illegal: '\\n',
+ contains: [BACKSLASH_ESCAPE]
+ };
+ const 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/
+ };
+ const COMMENT = function (begin, end, inherits) {
+ var mode = inherit(
+ {
+ className: 'comment',
+ begin: begin, end: end,
+ contains: []
+ },
+ inherits || {}
+ );
+ mode.contains.push(PHRASAL_WORDS_MODE);
+ mode.contains.push({
+ className: 'doctag',
+ begin: '(?:TODO|FIXME|NOTE|BUG|XXX):',
+ relevance: 0
+ });
+ return mode;
+ };
+ const C_LINE_COMMENT_MODE = COMMENT('//', '$');
+ const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');
+ const HASH_COMMENT_MODE = COMMENT('#', '$');
+ const NUMBER_MODE = {
+ className: 'number',
+ begin: NUMBER_RE,
+ relevance: 0
+ };
+ const C_NUMBER_MODE = {
+ className: 'number',
+ begin: C_NUMBER_RE,
+ relevance: 0
+ };
+ const BINARY_NUMBER_MODE = {
+ className: 'number',
+ begin: BINARY_NUMBER_RE,
+ relevance: 0
+ };
+ const CSS_NUMBER_MODE = {
+ className: 'number',
+ begin: 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
+ };
+ const REGEXP_MODE = {
+ // this outer rule makes sure we actually have a WHOLE regex and not simply
+ // an expression such as:
+ //
+ // 3 / something
+ //
+ // (which will then blow up when regex's `illegal` sees the newline)
+ begin: /(?=\/[^\/\n]*\/)/,
+ contains: [{
+ className: 'regexp',
+ begin: /\//, end: /\/[gimuy]*/,
+ illegal: /\n/,
+ contains: [
+ BACKSLASH_ESCAPE,
+ {
+ begin: /\[/, end: /\]/,
+ relevance: 0,
+ contains: [BACKSLASH_ESCAPE]
+ }
+ ]
+ }]
+ };
+ const TITLE_MODE = {
+ className: 'title',
+ begin: IDENT_RE,
+ relevance: 0
+ };
+ const UNDERSCORE_TITLE_MODE = {
+ className: 'title',
+ begin: UNDERSCORE_IDENT_RE,
+ relevance: 0
+ };
+ const METHOD_GUARD = {
+ // excludes method names from keyword processing
+ begin: '\\.\\s*' + UNDERSCORE_IDENT_RE,
+ relevance: 0
+ };
+
+ var MODES = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ IDENT_RE: IDENT_RE,
+ UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,
+ NUMBER_RE: NUMBER_RE,
+ C_NUMBER_RE: C_NUMBER_RE,
+ BINARY_NUMBER_RE: BINARY_NUMBER_RE,
+ RE_STARTERS_RE: RE_STARTERS_RE,
+ BACKSLASH_ESCAPE: BACKSLASH_ESCAPE,
+ APOS_STRING_MODE: APOS_STRING_MODE,
+ QUOTE_STRING_MODE: QUOTE_STRING_MODE,
+ PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE,
+ COMMENT: COMMENT,
+ C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE,
+ C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE,
+ HASH_COMMENT_MODE: HASH_COMMENT_MODE,
+ NUMBER_MODE: NUMBER_MODE,
+ C_NUMBER_MODE: C_NUMBER_MODE,
+ BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,
+ CSS_NUMBER_MODE: CSS_NUMBER_MODE,
+ REGEXP_MODE: REGEXP_MODE,
+ TITLE_MODE: TITLE_MODE,
+ UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,
+ METHOD_GUARD: METHOD_GUARD
+ });
+
+ // keywords that should have no default relevance value
+ var COMMON_KEYWORDS = 'of and for in not or if then'.split(' ');
+
+ // compilation
+
+ function compileLanguage(language) {
+
+ function langRe(value, global) {
+ return new RegExp(
+ source(value),
+ 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
+ );
+ }
+
+ /**
+ Stores multiple regular expressions and allows you to quickly search for
+ them all in a string simultaneously - returning the first match. It does
+ this by creating a huge (a|b|c) regex - each individual item wrapped with ()
+ and joined by `|` - using match groups to track position. When a match is
+ found checking which position in the array has content allows us to figure
+ out which of the original regexes / match groups triggered the match.
+
+ The match object itself (the result of `Regex.exec`) is returned but also
+ enhanced by merging in any meta-data that was registered with the regex.
+ This is how we keep track of which mode matched, and what type of rule
+ (`illegal`, `begin`, end, etc).
+ */
+ class MultiRegex {
+ constructor() {
+ this.matchIndexes = {};
+ this.regexes = [];
+ this.matchAt = 1;
+ this.position = 0;
+ }
+
+ addRule(re, opts) {
+ opts.position = this.position++;
+ this.matchIndexes[this.matchAt] = opts;
+ this.regexes.push([opts, re]);
+ this.matchAt += countMatchGroups(re) + 1;
+ }
+
+ compile() {
+ if (this.regexes.length === 0) {
+ // avoids the need to check length every time exec is called
+ this.exec = () => null;
+ }
+ let terminators = this.regexes.map(el => el[1]);
+ this.matcherRe = langRe(join(terminators, '|'), true);
+ this.lastIndex = 0;
+ }
+
+ exec(s) {
+ this.matcherRe.lastIndex = this.lastIndex;
+ let match = this.matcherRe.exec(s);
+ if (!match) { return null; }
+
+ let i = match.findIndex((el, i) => i>0 && el!=undefined);
+ let matchData = this.matchIndexes[i];
+
+ return Object.assign(match, matchData);
+ }
+ }
+
+ /*
+ Created to solve the key deficiently with MultiRegex - there is no way to
+ test for multiple matches at a single location. Why would we need to do
+ that? In the future a more dynamic engine will allow certain matches to be
+ ignored. An example: if we matched say the 3rd regex in a large group but
+ decided to ignore it - we'd need to started testing again at the 4th
+ regex... but MultiRegex itself gives us no real way to do that.
+
+ So what this class creates MultiRegexs on the fly for whatever search
+ position they are needed.
+
+ NOTE: These additional MultiRegex objects are created dynamically. For most
+ grammars most of the time we will never actually need anything more than the
+ first MultiRegex - so this shouldn't have too much overhead.
+
+ Say this is our search group, and we match regex3, but wish to ignore it.
+
+ regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0
+
+ What we need is a new MultiRegex that only includes the remaining
+ possibilities:
+
+ regex4 | regex5 ' ie, startAt = 3
+
+ This class wraps all that complexity up in a simple API... `startAt` decides
+ where in the array of expressions to start doing the matching. It
+ auto-increments, so if a match is found at position 2, then startAt will be
+ set to 3. If the end is reached startAt will return to 0.
+
+ MOST of the time the parser will be setting startAt manually to 0.
+ */
+ class ResumableMultiRegex {
+ constructor() {
+ this.rules = [];
+ this.multiRegexes = [];
+ this.count = 0;
+
+ this.lastIndex = 0;
+ this.regexIndex = 0;
+ }
+
+ getMatcher(index) {
+ if (this.multiRegexes[index]) return this.multiRegexes[index];
+
+ let matcher = new MultiRegex();
+ this.rules.slice(index).forEach(([re, opts])=> matcher.addRule(re,opts));
+ matcher.compile();
+ this.multiRegexes[index] = matcher;
+ return matcher;
+ }
+
+ considerAll() {
+ this.regexIndex = 0;
+ }
+
+ addRule(re, opts) {
+ this.rules.push([re, opts]);
+ if (opts.type==="begin") this.count++;
+ }
+
+ exec(s) {
+ let m = this.getMatcher(this.regexIndex);
+ m.lastIndex = this.lastIndex;
+ let result = m.exec(s);
+ if (result) {
+ this.regexIndex += result.position + 1;
+ if (this.regexIndex === this.count) // wrap-around
+ this.regexIndex = 0;
+ }
+
+ // this.regexIndex = 0;
+ return result;
+ }
+ }
+
+ function buildModeRegex(mode) {
+
+ let mm = new ResumableMultiRegex();
+
+ mode.contains.forEach(term => mm.addRule(term.begin, {rule: term, type: "begin" }));
+
+ if (mode.terminator_end)
+ mm.addRule(mode.terminator_end, {type: "end"} );
+ if (mode.illegal)
+ mm.addRule(mode.illegal, {type: "illegal"} );
+
+ return mm;
+ }
+
+ // TODO: We need negative look-behind support to do this properly
+ function skipIfhasPrecedingOrTrailingDot(match) {
+ let before = match.input[match.index-1];
+ let after = match.input[match.index + match[0].length];
+ if (before === "." || after === ".") {
+ return {ignoreMatch: true };
+ }
+ }
+
+ /** skip vs abort vs ignore
+ *
+ * @skip - The mode is still entered and exited normally (and contains rules apply),
+ * but all content is held and added to the parent buffer rather than being
+ * output when the mode ends. Mostly used with `sublanguage` to build up
+ * a single large buffer than can be parsed by sublanguage.
+ *
+ * - The mode begin ands ends normally.
+ * - Content matched is added to the parent mode buffer.
+ * - The parser cursor is moved forward normally.
+ *
+ * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it
+ * never matched) but DOES NOT continue to match subsequent `contains`
+ * modes. Abort is bad/suboptimal because it can result in modes
+ * farther down not getting applied because an earlier rule eats the
+ * content but then aborts.
+ *
+ * - The mode does not begin.
+ * - Content matched by `begin` is added to the mode buffer.
+ * - The parser cursor is moved forward accordingly.
+ *
+ * @ignore - Ignores the mode (as if it never matched) and continues to match any
+ * subsequent `contains` modes. Ignore isn't technically possible with
+ * the current parser implementation.
+ *
+ * - The mode does not begin.
+ * - Content matched by `begin` is ignored.
+ * - The parser cursor is not moved forward.
+ */
+
+ function compileMode(mode, parent) {
+ if (mode.compiled)
+ return;
+ mode.compiled = true;
+
+ // __onBegin is considered private API, internal use only
+ mode.__onBegin = null;
+
+ 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) {
+ // for languages with keywords that include non-word characters checking for
+ // a word boundary is not sufficient, so instead we check for a word boundary
+ // or whitespace - this does no harm in any case since our keyword engine
+ // doesn't allow spaces in keywords anyways and we still check for the boundary
+ // first
+ mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?=\\b|\\s)';
+ mode.__onBegin = skipIfhasPrecedingOrTrailingDot;
+ }
+ 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 = source(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 = [].concat(...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.matcher = buildModeRegex(mode);
+ }
+
+ // self is not valid at the top-level
+ if (language.contains && language.contains.includes('self')) {
+ throw new Error("ERR: contains `self` is not supported at the top-level of a language. See
documentation.")
+ }
+ compileMode(language);
+ }
+
+ 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;
+ }
+
+
+ // keywords
+
+ function compileKeywords(rawKeywords, case_insensitive) {
+ var compiled_keywords = {};
+
+ if (typeof rawKeywords === 'string') { // string
+ splitAndCompile('keyword', rawKeywords);
+ } else {
+ Object.keys(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.includes(word.toLowerCase());
+ }
+
+ var version = "10.0.1";
+
+ /*
+ Syntax highlighting with language autodetection.
+ https://highlightjs.org/
+ */
+
+ const escape$1 = escapeHTML;
+ const inherit$1 = inherit;
+
+ const { nodeStream: nodeStream$1, mergeStreams: mergeStreams$1 } = utils;
+
+
+ const HLJS = function(hljs) {
+
+ // Convenience variables for build-in objects
+ var ArrayProto = [];
+
+ // Global internal variables used within the highlight.js library.
+ var languages = {},
+ aliases = {},
+ plugins = [];
+
+ // 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 fixMarkupRe = /((^(<[^>]+>|\t|)+|(?:\n)))/gm;
+
+ 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 = {
+ noHighlightRe: /^(no-?highlight)$/i,
+ languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,
+ classPrefix: 'hljs-',
+ tabReplace: null,
+ useBR: false,
+ languages: undefined,
+ // beta configuration options, subject to change, welcome to discuss
+ // https://github.com/highlightjs/highlight.js/issues/1086
+ __emitter: TokenTreeEmitter
+ };
+
+ /* Utility functions */
+
+ function shouldNotHighlight(language) {
+ return options.noHighlightRe.test(language);
+ }
+
+ function blockLanguage(block) {
+ var match;
+ var classes = block.className + ' ';
+
+ classes += block.parentNode ? block.parentNode.className : '';
+
+ // language-* takes precedence over non-prefixed class names.
+ match = options.languageDetectRe.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';
+ }
+
+ return classes
+ .split(/\s+/)
+ .find((_class) => shouldNotHighlight(_class) || getLanguage(_class));
+ }
+
+ /**
+ * 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 {string} code - the original raw 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) {
+ var context = {
+ code,
+ language: languageName
+ };
+ // the plugin can change the desired language or the code to be highlighted
+ // just be changing the object it was passed
+ fire("before:highlight", context);
+
+ // a before plugin can usurp the result completely by providing it's own
+ // in which case we don't even need to call highlight
+ var result = context.result ?
+ context.result :
+ _highlight(context.language, context.code, ignore_illegals, continuation);
+
+ result.code = context.code;
+ // the plugin can change anything in result to suite it
+ fire("after:highlight", result);
+
+ return result;
+ }
+
+ // private highlight that's used internally and does not fire callbacks
+ function _highlight(languageName, code, ignore_illegals, continuation) {
+ var codeToHighlight = code;
+
+ function endOfMode(mode, lexeme) {
+ if (startsWith(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 processKeywords() {
+ var keyword_match, last_index, match, buf;
+
+ if (!top.keywords) {
+ emitter.addText(mode_buffer);
+ return;
+ }
+
+ last_index = 0;
+ top.lexemesRe.lastIndex = 0;
+ match = top.lexemesRe.exec(mode_buffer);
+ buf = "";
+
+ while (match) {
+ buf += mode_buffer.substring(last_index, match.index);
+ keyword_match = keywordMatch(top, match);
+ var kind = null;
+ if (keyword_match) {
+ emitter.addText(buf);
+ buf = "";
+
+ relevance += keyword_match[1];
+ kind = keyword_match[0];
+ emitter.addKeyword(match[0], kind);
+ } else {
+ buf += match[0];
+ }
+ last_index = top.lexemesRe.lastIndex;
+ match = top.lexemesRe.exec(mode_buffer);
+ }
+ buf += mode_buffer.substr(last_index);
+ emitter.addText(buf);
+ }
+
+ function processSubLanguage() {
+ if (mode_buffer === "") return;
+
+ var explicit = typeof top.subLanguage === 'string';
+
+ if (explicit && !languages[top.subLanguage]) {
+ emitter.addText(mode_buffer);
+ return;
+ }
+
+ 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;
+ }
+ emitter.addSublanguage(result.emitter, result.language);
+ }
+
+ function processBuffer() {
+ if (top.subLanguage != null)
+ processSubLanguage();
+ else
+ processKeywords();
+ mode_buffer = '';
+ }
+
+ function startNewMode(mode) {
+ if (mode.className) {
+ emitter.openNode(mode.className);
+ }
+ top = Object.create(mode, {parent: {value: top}});
+ }
+
+ function doIgnore(lexeme) {
+ if (top.matcher.regexIndex === 0) {
+ // no more regexs to potentially match here, so we move the cursor forward one
+ // space
+ mode_buffer += lexeme[0];
+ return 1;
+ } else {
+ // no need to move the cursor, we still have additional regexes to try and
+ // match at this very spot
+ continueScanAtSamePosition = true;
+ return 0;
+ }
+ }
+
+ function doBeginMatch(match) {
+ var lexeme = match[0];
+ var new_mode = match.rule;
+
+ if (new_mode.__onBegin) {
+ let res = new_mode.__onBegin(match) || {};
+ if (res.ignoreMatch)
+ return doIgnore(lexeme);
+ }
+
+ if (new_mode && new_mode.endSameAsBegin) {
+ new_mode.endRe = escape( 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) {
+ emitter.closeNode();
+ }
+ 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;
+ }
+
+ function processContinuations() {
+ var list = [];
+ for(var current = top; current !== language; current = current.parent) {
+ if (current.className) {
+ list.unshift(current.className);
+ }
+ }
+ list.forEach(item => emitter.openNode(item));
+ }
+
+ var lastMatch = {};
+ function processLexeme(text_before_match, match) {
+
+ var err;
+ 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);
+ if (!SAFE_MODE) {
+ err = new Error('0 width match regex');
+ err.languageName = languageName;
+ err.badRule = lastMatch.rule;
+ throw(err);
+ }
+ 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
+ err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '<unnamed>') +
'"');
+ err.mode = top;
+ throw err;
+ } 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;
+ var emitter = new options.__emitter(options);
+ processContinuations();
+ var mode_buffer = '';
+ var relevance = 0;
+ var match, processedCount, index = 0;
+
+ try {
+ var continueScanAtSamePosition = false;
+ top.matcher.considerAll();
+
+ while (true) {
+ if (continueScanAtSamePosition) {
+ continueScanAtSamePosition = false;
+ // only regexes not matched previously will now be
+ // considered for a potential match
+ } else {
+ top.matcher.lastIndex = index;
+ top.matcher.considerAll();
+ }
+ match = top.matcher.exec(codeToHighlight);
+ // console.log("match", match[0], match.rule && match.rule.begin)
+ if (!match)
+ break;
+ let beforeMatch = codeToHighlight.substring(index, match.index);
+ processedCount = processLexeme(beforeMatch, match);
+ index = match.index + processedCount;
+ }
+ processLexeme(codeToHighlight.substr(index));
+ emitter.closeAllNodes();
+ emitter.finalize();
+ result = emitter.toHTML();
+
+ return {
+ relevance: relevance,
+ value: result,
+ language: languageName,
+ illegal: false,
+ emitter: emitter,
+ top: top
+ };
+ } catch (err) {
+ if (err.message && err.message.includes('Illegal')) {
+ return {
+ illegal: true,
+ illegalBy: {
+ msg: err.message,
+ context: codeToHighlight.slice(index-100,index+100),
+ mode: err.mode
+ },
+ sofar: result,
+ relevance: 0,
+ value: escape$1(codeToHighlight),
+ emitter: emitter,
+ };
+ } else if (SAFE_MODE) {
+ return {
+ relevance: 0,
+ value: escape$1(codeToHighlight),
+ emitter: emitter,
+ language: languageName,
+ top: top,
+ errorRaised: err
+ };
+ } else {
+ throw err;
+ }
+ }
+ }
+
+ // returns a valid highlight result, without actually
+ // doing any actual work, auto highlight starts with
+ // this and it's possible for small snippets that
+ // auto-detection may not find a better match
+ function justTextHighlightResult(code) {
+ const result = {
+ relevance: 0,
+ emitter: new options.__emitter(options),
+ value: escape$1(code),
+ illegal: false,
+ top: PLAINTEXT_LANGUAGE
+ };
+ result.emitter.addText(code);
+ return result;
+ }
+
+ /*
+ 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 || Object.keys(languages);
+ var result = justTextHighlightResult(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.includes(language)) {
+ 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 (shouldNotHighlight(language))
+ return;
+
+ fire("before:highlightBlock",
+ { block: block, language: language});
+
+ 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$1(node);
+ if (originalStream.length) {
+ resultNode = document.createElement('div');
+ resultNode.innerHTML = result.value;
+ result.value = mergeStreams$1(originalStream, nodeStream$1(resultNode), text);
+ }
+ result.value = fixMarkup(result.value);
+
+ fire("after:highlightBlock", { block: block, result: result});
+
+ 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$1(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);
+ }
+
+ const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text' };
+
+ 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;
+ }
+ // give it a temporary name if it doesn't have one in the meta-data
+ if (!lang.name)
+ lang.name = name;
+ languages[name] = lang;
+ lang.rawDefinition = language.bind(null,hljs);
+
+ if (lang.aliases) {
+ lang.aliases.forEach(function(alias) {aliases[alias] = name;});
+ }
+ }
+
+ function listLanguages() {
+ return Object.keys(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;
+ }
+
+ function addPlugin(plugin, options) {
+ plugins.push(plugin);
+ }
+
+ function fire(event, args) {
+ var cb = event;
+ plugins.forEach(function (plugin) {
+ if (plugin[cb]) {
+ plugin[cb](args);
+ }
+ });
+ }
+
+ /* Interface definition */
+
+ Object.assign(hljs,{
+ highlight,
+ highlightAuto,
+ fixMarkup,
+ highlightBlock,
+ configure,
+ initHighlighting,
+ initHighlightingOnLoad,
+ registerLanguage,
+ listLanguages,
+ getLanguage,
+ requireLanguage,
+ autoDetection,
+ inherit: inherit$1,
+ addPlugin
+ });
+
+ hljs.debugMode = function() { SAFE_MODE = false; };
+ hljs.safeMode = function() { SAFE_MODE = true; };
+ hljs.versionString = version;
+
+ for (const key in MODES) {
+ if (typeof MODES[key] === "object")
+ deepFreeze(MODES[key]);
+ }
+
+ // merge all the modes/regexs into our main object
+ Object.assign(hljs, MODES);
+
+ return hljs;
+ };
+
+ // export an "instance" of the highlighter
+ var highlight = HLJS({});
+
+ return highlight;
+
+})));
+
+hljs.registerLanguage('css', function () {
+ 'use strict';
+
+ /*
+ Language: CSS
+ Category: common, css
+ Website: https://developer.mozilla.org/en-US/docs/Web/CSS
+ */
+
+ function css(hljs) {
+ var FUNCTION_LIKE = {
+ begin: /[\w-]+\(/, returnBegin: true,
+ contains: [
+ {
+ className: 'built_in',
+ begin: /[\w-]+/
+ },
+ {
+ begin: /\(/, end: /\)/,
+ contains: [
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.CSS_NUMBER_MODE,
+ ]
+ }
+ ]
+ };
+ var ATTRIBUTE = {
+ className: 'attribute',
+ begin: /\S/, end: ':', excludeEnd: true,
+ starts: {
+ endsWithParent: true, excludeEnd: true,
+ contains: [
+ FUNCTION_LIKE,
+ hljs.CSS_NUMBER_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'number', begin: '#[0-9A-Fa-f]+'
+ },
+ {
+ className: 'meta', begin: '!important'
+ }
+ ]
+ }
+ };
+ var AT_IDENTIFIER = '@[a-z-]+'; // @font-face
+ var AT_MODIFIERS = "and or not only";
+ var AT_PROPERTY_RE = /@\-?\w[\w]*(\-\w+)*/; // @-webkit-keyframes
+ var IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*';
+ var RULE = {
+ begin: /(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/, returnBegin: true, end: ';', endsWithParent: true,
+ contains: [
+ ATTRIBUTE
+ ]
+ };
+
+ return {
+ name: 'CSS',
+ case_insensitive: true,
+ illegal: /[=\/|'\$]/,
+ contains: [
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'selector-id', begin: /#[A-Za-z0-9_-]+/
+ },
+ {
+ className: 'selector-class', begin: /\.[A-Za-z0-9_-]+/
+ },
+ {
+ className: 'selector-attr',
+ begin: /\[/, end: /\]/,
+ illegal: '$',
+ contains: [
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ ]
+ },
+ {
+ className: 'selector-pseudo',
+ begin: /:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/
+ },
+ // matching these here allows us to treat them more like regular CSS
+ // rules so everything between the {} gets regular rule highlighting,
+ // which is what we want for page and font-face
+ {
+ begin: '@(page|font-face)',
+ lexemes: AT_IDENTIFIER,
+ keywords: '@page @font-face'
+ },
+ {
+ begin: '@', end: '[{;]', // at_rule eating first "{" is a good thing
+ // because it doesn’t let it to be parsed as
+ // a rule set but instead drops parser into
+ // the default mode which is how it should be.
+ illegal: /:/, // break on Less variables @var: ...
+ returnBegin: true,
+ contains: [
+ {
+ className: 'keyword',
+ begin: AT_PROPERTY_RE
+ },
+ {
+ begin: /\s/, endsWithParent: true, excludeEnd: true,
+ relevance: 0,
+ keywords: AT_MODIFIERS,
+ contains: [
+ {
+ begin: /[a-z-]+:/,
+ className:"attribute"
+ },
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.CSS_NUMBER_MODE
+ ]
+ }
+ ]
+ },
+ {
+ className: 'selector-tag', begin: IDENT_RE,
+ relevance: 0
+ },
+ {
+ begin: '{', end: '}',
+ illegal: /\S/,
+ contains: [
+ hljs.C_BLOCK_COMMENT_MODE,
+ RULE,
+ ]
+ }
+ ]
+ };
+ }
+
+ return css;
+
+ return module.exports.definer || module.exports;
+
+}());
+
+hljs.registerLanguage('javascript', function () {
+ 'use strict';
+
+ /*
+ Language: JavaScript
+ Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language
with first-class functions.
+ Category: common, scripting
+ Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
+ */
+
+ function javascript(hljs) {
+ var FRAGMENT = {
+ begin: '<>',
+ end: '</>'
+ };
+ var XML_TAG = {
+ begin: /<[A-Za-z0-9\\._:-]+/,
+ end: /\/[A-Za-z0-9\\._:-]+>|\/>/
+ };
+ var IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
+ var KEYWORDS = {
+ keyword:
+ 'in of if for while finally var new function do return void else break catch ' +
+ 'instanceof with throw case default try this switch continue typeof delete ' +
+ 'let yield const export super debugger as async await static ' +
+ // ECMAScript 6 modules import
+ 'import from as'
+ ,
+ literal:
+ 'true false null undefined NaN Infinity',
+ built_in:
+ 'eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent ' +
+ 'encodeURI encodeURIComponent escape unescape Object Function Boolean Error ' +
+ 'EvalError InternalError RangeError ReferenceError StopIteration SyntaxError ' +
+ 'TypeError URIError Number Math Date String RegExp Array Float32Array ' +
+ 'Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array ' +
+ 'Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require ' +
+ 'module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect ' +
+ 'Promise'
+ };
+ var NUMBER = {
+ className: 'number',
+ variants: [
+ { begin: '\\b(0[bB][01]+)n?' },
+ { begin: '\\b(0[oO][0-7]+)n?' },
+ { begin: hljs.C_NUMBER_RE + 'n?' }
+ ],
+ relevance: 0
+ };
+ var SUBST = {
+ className: 'subst',
+ begin: '\\$\\{', end: '\\}',
+ keywords: KEYWORDS,
+ contains: [] // defined later
+ };
+ var HTML_TEMPLATE = {
+ begin: 'html`', end: '',
+ starts: {
+ end: '`', returnEnd: false,
+ contains: [
+ hljs.BACKSLASH_ESCAPE,
+ SUBST
+ ],
+ subLanguage: 'xml',
+ }
+ };
+ var CSS_TEMPLATE = {
+ begin: 'css`', end: '',
+ starts: {
+ end: '`', returnEnd: false,
+ contains: [
+ hljs.BACKSLASH_ESCAPE,
+ SUBST
+ ],
+ subLanguage: 'css',
+ }
+ };
+ var TEMPLATE_STRING = {
+ className: 'string',
+ begin: '`', end: '`',
+ contains: [
+ hljs.BACKSLASH_ESCAPE,
+ SUBST
+ ]
+ };
+ SUBST.contains = [
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ HTML_TEMPLATE,
+ CSS_TEMPLATE,
+ TEMPLATE_STRING,
+ NUMBER,
+ hljs.REGEXP_MODE
+ ];
+ var PARAMS_CONTAINS = SUBST.contains.concat([
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.C_LINE_COMMENT_MODE
+ ]);
+ var PARAMS = {
+ className: 'params',
+ begin: /\(/, end: /\)/,
+ excludeBegin: true,
+ excludeEnd: true,
+ contains: PARAMS_CONTAINS
+ };
+
+ return {
+ name: 'JavaScript',
+ aliases: ['js', 'jsx', 'mjs', 'cjs'],
+ keywords: KEYWORDS,
+ contains: [
+ {
+ className: 'meta',
+ relevance: 10,
+ begin: /^\s*['"]use (strict|asm)['"]/
+ },
+ {
+ className: 'meta',
+ begin: /^#!/, end: /$/
+ },
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ HTML_TEMPLATE,
+ CSS_TEMPLATE,
+ TEMPLATE_STRING,
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.COMMENT(
+ '/\\*\\*',
+ '\\*/',
+ {
+ relevance : 0,
+ contains : [
+ {
+ className : 'doctag',
+ begin : '@[A-Za-z]+',
+ contains : [
+ {
+ className: 'type',
+ begin: '\\{',
+ end: '\\}',
+ relevance: 0
+ },
+ {
+ className: 'variable',
+ begin: IDENT_RE + '(?=\\s*(-)|$)',
+ endsParent: true,
+ relevance: 0
+ },
+ // eat spaces (not newlines) so we can find
+ // types or variables
+ {
+ begin: /(?=[^\n])\s/,
+ relevance: 0
+ },
+ ]
+ }
+ ]
+ }
+ ),
+ hljs.C_BLOCK_COMMENT_MODE,
+ NUMBER,
+ { // object attr container
+ begin: /[{,\n]\s*/, relevance: 0,
+ contains: [
+ {
+ begin: IDENT_RE + '\\s*:', returnBegin: true,
+ relevance: 0,
+ contains: [{className: 'attr', begin: IDENT_RE, relevance: 0}]
+ }
+ ]
+ },
+ { // "value" container
+ begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
+ keywords: 'return throw case',
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.REGEXP_MODE,
+ {
+ className: 'function',
+ begin: '(\\(.*?\\)|' + IDENT_RE + ')\\s*=>', returnBegin: true,
+ end: '\\s*=>',
+ contains: [
+ {
+ className: 'params',
+ variants: [
+ {
+ begin: IDENT_RE
+ },
+ {
+ begin: /\(\s*\)/,
+ },
+ {
+ begin: /\(/, end: /\)/,
+ excludeBegin: true, excludeEnd: true,
+ keywords: KEYWORDS,
+ contains: PARAMS_CONTAINS
+ }
+ ]
+ }
+ ]
+ },
+ { // could be a comma delimited list of params to a function call
+ begin: /,/, relevance: 0,
+ },
+ {
+ className: '',
+ begin: /\s/,
+ end: /\s*/,
+ skip: true,
+ },
+ { // JSX
+ variants: [
+ { begin: FRAGMENT.begin, end: FRAGMENT.end },
+ { begin: XML_TAG.begin, end: XML_TAG.end }
+ ],
+ subLanguage: 'xml',
+ contains: [
+ {
+ begin: XML_TAG.begin, end: XML_TAG.end, skip: true,
+ contains: ['self']
+ }
+ ]
+ },
+ ],
+ relevance: 0
+ },
+ {
+ className: 'function',
+ beginKeywords: 'function', end: /\{/, excludeEnd: true,
+ contains: [
+ hljs.inherit(hljs.TITLE_MODE, {begin: IDENT_RE}),
+ PARAMS
+ ],
+ illegal: /\[|%/
+ },
+ {
+ begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and
`$.something`
+ },
+
+ hljs.METHOD_GUARD,
+ { // ES6 class
+ className: 'class',
+ beginKeywords: 'class', end: /[{;=]/, excludeEnd: true,
+ illegal: /[:"\[\]]/,
+ contains: [
+ {beginKeywords: 'extends'},
+ hljs.UNDERSCORE_TITLE_MODE
+ ]
+ },
+ {
+ beginKeywords: 'constructor', end: /\{/, excludeEnd: true
+ },
+ {
+ begin:'(get|set)\\s*(?=' + IDENT_RE+ '\\()',
+ end: /{/,
+ keywords: "get set",
+ contains: [
+ hljs.inherit(hljs.TITLE_MODE, {begin: IDENT_RE}),
+ { begin: /\(\)/ }, // eat to avoid empty params
+ PARAMS
+ ]
+
+ }
+ ],
+ illegal: /#(?!!)/
+ };
+ }
+
+ return javascript;
+
+ return module.exports.definer || module.exports;
+
+}());
+
+hljs.registerLanguage('xml', function () {
+ 'use strict';
+
+ /*
+ Language: HTML, XML
+ Website: https://www.w3.org/XML/
+ Category: common
+ */
+
+ function xml(hljs) {
+ var XML_IDENT_RE = '[A-Za-z0-9\\._:-]+';
+ var XML_ENTITIES = {
+ className: 'symbol',
+ begin: '&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;'
+ };
+ var XML_META_KEYWORDS = {
+ begin: '\\s',
+ contains:[
+ {
+ className: 'meta-keyword',
+ begin: '#?[a-z_][a-z1-9_-]+',
+ illegal: '\\n',
+ }
+ ]
+ };
+ var XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, {begin: '\\(', end: '\\)'});
+ var APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, {className: 'meta-string'});
+ var QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, {className: 'meta-string'});
+ var TAG_INTERNALS = {
+ endsWithParent: true,
+ illegal: /</,
+ relevance: 0,
+ contains: [
+ {
+ className: 'attr',
+ begin: XML_IDENT_RE,
+ relevance: 0
+ },
+ {
+ begin: /=\s*/,
+ relevance: 0,
+ contains: [
+ {
+ className: 'string',
+ endsParent: true,
+ variants: [
+ {begin: /"/, end: /"/, contains: [XML_ENTITIES]},
+ {begin: /'/, end: /'/, contains: [XML_ENTITIES]},
+ {begin: /[^\s"'=<>`]+/}
+ ]
+ }
+ ]
+ }
+ ]
+ };
+ return {
+ name: 'HTML, XML',
+ aliases: ['html', 'xhtml', 'rss', 'atom', 'xjb', 'xsd', 'xsl', 'plist', 'wsf', 'svg'],
+ case_insensitive: true,
+ contains: [
+ {
+ className: 'meta',
+ begin: '<![a-z]', end: '>',
+ relevance: 10,
+ contains: [
+ XML_META_KEYWORDS,
+ QUOTE_META_STRING_MODE,
+ APOS_META_STRING_MODE,
+ XML_META_PAR_KEYWORDS,
+ {
+ begin: '\\[', end: '\\]',
+ contains:[
+ {
+ className: 'meta',
+ begin: '<![a-z]', end: '>',
+ contains: [
+ XML_META_KEYWORDS,
+ XML_META_PAR_KEYWORDS,
+ QUOTE_META_STRING_MODE,
+ APOS_META_STRING_MODE
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ hljs.COMMENT(
+ '<!--',
+ '-->',
+ {
+ relevance: 10
+ }
+ ),
+ {
+ begin: '<\\!\\[CDATA\\[', end: '\\]\\]>',
+ relevance: 10
+ },
+ XML_ENTITIES,
+ {
+ className: 'meta',
+ begin: /<\?xml/, end: /\?>/, relevance: 10
+ },
+ {
+ className: 'tag',
+ /*
+ The lookahead pattern (?=...) ensures that 'begin' only matches
+ '<style' as a single word, followed by a whitespace or an
+ ending braket. The '$' is needed for the lexeme to be recognized
+ by hljs.subMode() that tests lexemes outside the stream.
+ */
+ begin: '<style(?=\\s|>)', end: '>',
+ keywords: {name: 'style'},
+ contains: [TAG_INTERNALS],
+ starts: {
+ end: '</style>', returnEnd: true,
+ subLanguage: ['css', 'xml']
+ }
+ },
+ {
+ className: 'tag',
+ // See the comment in the <style tag about the lookahead pattern
+ begin: '<script(?=\\s|>)', end: '>',
+ keywords: {name: 'script'},
+ contains: [TAG_INTERNALS],
+ starts: {
+ end: '\<\/script\>', returnEnd: true,
+ subLanguage: ['javascript', 'handlebars', 'xml']
+ }
+ },
+ {
+ className: 'tag',
+ begin: '</?', end: '/?>',
+ contains: [
+ {
+ className: 'name', begin: /[^\/><\s]+/, relevance: 0
+ },
+ TAG_INTERNALS
+ ]
+ }
+ ]
+ };
+ }
+
+ return xml;
+
+ return module.exports.definer || module.exports;
+
+}());
diff --git a/third-party/highlightjs/highlightjs.gresource.xml
b/third-party/highlightjs/highlightjs.gresource.xml
index 458aa6604..44db95f55 100644
--- a/third-party/highlightjs/highlightjs.gresource.xml
+++ b/third-party/highlightjs/highlightjs.gresource.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/epiphany/highlightjs">
- <file compressed="true">highlight.pack.js</file>
+ <file compressed="true">highlight.js</file>
<file compressed="true">default.css</file>
</gresource>
</gresources>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]