[devdocsgjs/main: 1671/1867] LaTeX: syntax highlighting
- From: Andy Holmes <andyholmes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [devdocsgjs/main: 1671/1867] LaTeX: syntax highlighting
- Date: Fri, 19 Nov 2021 23:48:14 +0000 (UTC)
commit f139802767b0eee88deb309241e985e524c77e95
Author: Simon Legner <Simon Legner gmail com>
Date: Wed May 26 21:13:38 2021 +0200
LaTeX: syntax highlighting
assets/javascripts/vendor/prism.js | 2941 +++++++++++++++++++---------------
lib/docs/filters/latex/clean_html.rb | 5 +
2 files changed, 1647 insertions(+), 1299 deletions(-)
---
diff --git a/assets/javascripts/vendor/prism.js b/assets/javascripts/vendor/prism.js
index 2f830fe4..8fc99771 100644
--- a/assets/javascripts/vendor/prism.js
+++ b/assets/javascripts/vendor/prism.js
@@ -1,13 +1,13 @@
/* PrismJS 1.23.0
-https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+lua+markup-templating+matlab+nginx+nim+ocaml+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml
*/
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+latex+lua+markup-templating+matlab+nginx+nim+ocaml+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml
*/
/// <reference lib="WebWorker"/>
var _self = (typeof window !== 'undefined')
? window // if in browser
: (
(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
- ? self // if in worker
- : {} // if in node js
+ ? self // if in worker
+ : {} // if in node js
);
/**
@@ -18,1133 +18,1151 @@ var _self = (typeof window !== 'undefined')
* @namespace
* @public
*/
-var Prism = (function (_self){
+var Prism = (function (_self) {
-// Private helper vars
-var lang = /\blang(?:uage)?-([\w-]+)\b/i;
-var uniqueId = 0;
+ // Private helper vars
+ var lang = /\blang(?:uage)?-([\w-]+)\b/i;
+ var uniqueId = 0;
+ // The grammar object for plaintext
+ var plainTextGrammar = {};
-var _ = {
- /**
- * By default, Prism will attempt to highlight all code elements (by calling {@link
Prism.highlightAll}) on the
- * current page after the page finished loading. This might be a problem if e.g. you wanted to
asynchronously load
- * additional languages or plugins yourself.
- *
- * By setting this value to `true`, Prism will not automatically highlight all code elements on the
page.
- *
- * You obviously have to change this value before the automatic highlighting started. To do this, you
can add an
- * empty Prism object into the global scope before loading the Prism script like this:
- *
- * ```js
- * window.Prism = window.Prism || {};
- * Prism.manual = true;
- * // add a new <script> to load Prism's script
- * ```
- *
- * @default false
- * @type {boolean}
- * @memberof Prism
- * @public
- */
- manual: _self.Prism && _self.Prism.manual,
- disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
-
- /**
- * A namespace for utility methods.
- *
- * All function in this namespace that are not explicitly marked as _public_ are for __internal use
only__ and may
- * change or disappear at any time.
- *
- * @namespace
- * @memberof Prism
- */
- util: {
- encode: function encode(tokens) {
- if (tokens instanceof Token) {
- return new Token(tokens.type, encode(tokens.content), tokens.alias);
- } else if (Array.isArray(tokens)) {
- return tokens.map(encode);
- } else {
- return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g,
' ');
- }
- },
+ var _ = {
/**
- * Returns the name of the type of the given value.
+ * By default, Prism will attempt to highlight all code elements (by calling {@link
Prism.highlightAll}) on the
+ * current page after the page finished loading. This might be a problem if e.g. you wanted
to asynchronously load
+ * additional languages or plugins yourself.
*
- * @param {any} o
- * @returns {string}
- * @example
- * type(null) === 'Null'
- * type(undefined) === 'Undefined'
- * type(123) === 'Number'
- * type('foo') === 'String'
- * type(true) === 'Boolean'
- * type([1, 2]) === 'Array'
- * type({}) === 'Object'
- * type(String) === 'Function'
- * type(/abc+/) === 'RegExp'
- */
- type: function (o) {
- return Object.prototype.toString.call(o).slice(8, -1);
- },
-
- /**
- * Returns a unique number for the given object. Later calls will still return the same
number.
+ * By setting this value to `true`, Prism will not automatically highlight all code elements
on the page.
+ *
+ * You obviously have to change this value before the automatic highlighting started. To do
this, you can add an
+ * empty Prism object into the global scope before loading the Prism script like this:
*
- * @param {Object} obj
- * @returns {number}
+ * ```js
+ * window.Prism = window.Prism || {};
+ * Prism.manual = true;
+ * // add a new <script> to load Prism's script
+ * ```
+ *
+ * @default false
+ * @type {boolean}
+ * @memberof Prism
+ * @public
*/
- objId: function (obj) {
- if (!obj['__id']) {
- Object.defineProperty(obj, '__id', { value: ++uniqueId });
- }
- return obj['__id'];
- },
+ manual: _self.Prism && _self.Prism.manual,
+ disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
/**
- * Creates a deep clone of the given object.
+ * A namespace for utility methods.
*
- * The main intended use of this function is to clone language definitions.
+ * All function in this namespace that are not explicitly marked as _public_ are for
__internal use only__ and may
+ * change or disappear at any time.
*
- * @param {T} o
- * @param {Record<number, any>} [visited]
- * @returns {T}
- * @template T
+ * @namespace
+ * @memberof Prism
*/
- clone: function deepClone(o, visited) {
- visited = visited || {};
-
- var clone, id;
- switch (_.util.type(o)) {
- case 'Object':
- id = _.util.objId(o);
- if (visited[id]) {
- return visited[id];
- }
- clone = /** @type {Record<string, any>} */ ({});
- visited[id] = clone;
+ util: {
+ encode: function encode(tokens) {
+ if (tokens instanceof Token) {
+ return new Token(tokens.type, encode(tokens.content), tokens.alias);
+ } else if (Array.isArray(tokens)) {
+ return tokens.map(encode);
+ } else {
+ return tokens.replace(/&/g, '&').replace(/</g,
'<').replace(/\u00a0/g, ' ');
+ }
+ },
+
+ /**
+ * Returns the name of the type of the given value.
+ *
+ * @param {any} o
+ * @returns {string}
+ * @example
+ * type(null) === 'Null'
+ * type(undefined) === 'Undefined'
+ * type(123) === 'Number'
+ * type('foo') === 'String'
+ * type(true) === 'Boolean'
+ * type([1, 2]) === 'Array'
+ * type({}) === 'Object'
+ * type(String) === 'Function'
+ * type(/abc+/) === 'RegExp'
+ */
+ type: function (o) {
+ return Object.prototype.toString.call(o).slice(8, -1);
+ },
+
+ /**
+ * Returns a unique number for the given object. Later calls will still return the
same number.
+ *
+ * @param {Object} obj
+ * @returns {number}
+ */
+ objId: function (obj) {
+ if (!obj['__id']) {
+ Object.defineProperty(obj, '__id', { value: ++uniqueId });
+ }
+ return obj['__id'];
+ },
- for (var key in o) {
- if (o.hasOwnProperty(key)) {
- clone[key] = deepClone(o[key], visited);
+ /**
+ * Creates a deep clone of the given object.
+ *
+ * The main intended use of this function is to clone language definitions.
+ *
+ * @param {T} o
+ * @param {Record<number, any>} [visited]
+ * @returns {T}
+ * @template T
+ */
+ clone: function deepClone(o, visited) {
+ visited = visited || {};
+
+ var clone; var id;
+ switch (_.util.type(o)) {
+ case 'Object':
+ id = _.util.objId(o);
+ if (visited[id]) {
+ return visited[id];
}
- }
+ clone = /** @type {Record<string, any>} */ ({});
+ visited[id] = clone;
- return /** @type {any} */ (clone);
+ for (var key in o) {
+ if (o.hasOwnProperty(key)) {
+ clone[key] = deepClone(o[key], visited);
+ }
+ }
- case 'Array':
- id = _.util.objId(o);
- if (visited[id]) {
- return visited[id];
- }
- clone = [];
- visited[id] = clone;
+ return /** @type {any} */ (clone);
- (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i)
{
- clone[i] = deepClone(v, visited);
- });
+ case 'Array':
+ id = _.util.objId(o);
+ if (visited[id]) {
+ return visited[id];
+ }
+ clone = [];
+ visited[id] = clone;
- return /** @type {any} */ (clone);
+ (/** @type {Array} */(/** @type {any}
*/(o))).forEach(function (v, i) {
+ clone[i] = deepClone(v, visited);
+ });
- default:
- return o;
- }
- },
+ return /** @type {any} */ (clone);
- /**
- * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx`
class.
- *
- * If no language is set for the element or the element is `null` or `undefined`, `none` will
be returned.
- *
- * @param {Element} element
- * @returns {string}
- */
- getLanguage: function (element) {
- while (element && !lang.test(element.className)) {
- element = element.parentElement;
- }
- if (element) {
- return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
- }
- return 'none';
- },
+ default:
+ return o;
+ }
+ },
- /**
- * Returns the script element that is currently executing.
- *
- * This does __not__ work for line script element.
- *
- * @returns {HTMLScriptElement | null}
- */
- currentScript: function () {
- if (typeof document === 'undefined') {
- return null;
- }
- if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
- return /** @type {any} */ (document.currentScript);
- }
+ /**
+ * Returns the Prism language of the given element set by a `language-xxxx` or
`lang-xxxx` class.
+ *
+ * If no language is set for the element or the element is `null` or `undefined`,
`none` will be returned.
+ *
+ * @param {Element} element
+ * @returns {string}
+ */
+ getLanguage: function (element) {
+ while (element && !lang.test(element.className)) {
+ element = element.parentElement;
+ }
+ if (element) {
+ return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
+ }
+ return 'none';
+ },
- // IE11 workaround
- // we'll get the src of the current script by parsing IE11's error stack trace
- // this will not work for inline scripts
+ /**
+ * Returns the script element that is currently executing.
+ *
+ * This does __not__ work for line script element.
+ *
+ * @returns {HTMLScriptElement | null}
+ */
+ currentScript: function () {
+ if (typeof document === 'undefined') {
+ return null;
+ }
+ if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis
*/) {
+ return /** @type {any} */ (document.currentScript);
+ }
- try {
- throw new Error();
- } catch (err) {
- // Get file src url from stack. Specifically works with the format of stack
traces in IE.
- // A stack will look like this:
- //
- // Error
- // at _.util.currentScript
(http://localhost/components/prism-core.js:119:5)
- // at Global code (http://localhost/components/prism-core.js:606:1)
-
- var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
- if (src) {
- var scripts = document.getElementsByTagName('script');
- for (var i in scripts) {
- if (scripts[i].src == src) {
- return scripts[i];
+ // IE11 workaround
+ // we'll get the src of the current script by parsing IE11's error stack trace
+ // this will not work for inline scripts
+
+ try {
+ throw new Error();
+ } catch (err) {
+ // Get file src url from stack. Specifically works with the format of
stack traces in IE.
+ // A stack will look like this:
+ //
+ // Error
+ // at _.util.currentScript
(http://localhost/components/prism-core.js:119:5)
+ // at Global code (http://localhost/components/prism-core.js:606:1)
+
+ var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
+ if (src) {
+ var scripts = document.getElementsByTagName('script');
+ for (var i in scripts) {
+ if (scripts[i].src == src) {
+ return scripts[i];
+ }
}
}
+ return null;
+ }
+ },
+
+ /**
+ * Returns whether a given class is active for `element`.
+ *
+ * The class can be activated if `element` or one of its ancestors has the given
class and it can be deactivated
+ * if `element` or one of its ancestors has the negated version of the given class.
The _negated version_ of the
+ * given class is just the given class with a `no-` prefix.
+ *
+ * Whether the class is active is determined by the closest ancestor of `element`
(where `element` itself is
+ * closest ancestor) that has the given class or the negated version of it. If
neither `element` nor any of its
+ * ancestors have the given class or the negated version of it, then the default
activation will be returned.
+ *
+ * In the paradoxical situation where the closest ancestor contains __both__ the
given class and the negated
+ * version of it, the class is considered active.
+ *
+ * @param {Element} element
+ * @param {string} className
+ * @param {boolean} [defaultActivation=false]
+ * @returns {boolean}
+ */
+ isActive: function (element, className, defaultActivation) {
+ var no = 'no-' + className;
+
+ while (element) {
+ var classList = element.classList;
+ if (classList.contains(className)) {
+ return true;
+ }
+ if (classList.contains(no)) {
+ return false;
+ }
+ element = element.parentElement;
}
- return null;
+ return !!defaultActivation;
}
},
/**
- * Returns whether a given class is active for `element`.
+ * This namespace contains all currently loaded languages and the some helper functions to
create and modify languages.
*
- * The class can be activated if `element` or one of its ancestors has the given class and it
can be deactivated
- * if `element` or one of its ancestors has the negated version of the given class. The
_negated version_ of the
- * given class is just the given class with a `no-` prefix.
- *
- * Whether the class is active is determined by the closest ancestor of `element` (where
`element` itself is
- * closest ancestor) that has the given class or the negated version of it. If neither
`element` nor any of its
- * ancestors have the given class or the negated version of it, then the default activation
will be returned.
- *
- * In the paradoxical situation where the closest ancestor contains __both__ the given class
and the negated
- * version of it, the class is considered active.
- *
- * @param {Element} element
- * @param {string} className
- * @param {boolean} [defaultActivation=false]
- * @returns {boolean}
+ * @namespace
+ * @memberof Prism
+ * @public
*/
- isActive: function (element, className, defaultActivation) {
- var no = 'no-' + className;
+ languages: {
+ /**
+ * The grammar for plain, unformatted text.
+ */
+ plain: plainTextGrammar,
+ plaintext: plainTextGrammar,
+ text: plainTextGrammar,
+ txt: plainTextGrammar,
- while (element) {
- var classList = element.classList;
- if (classList.contains(className)) {
- return true;
+ /**
+ * Creates a deep copy of the language with the given id and appends the given tokens.
+ *
+ * If a token in `redef` also appears in the copied language, then the existing token
in the copied language
+ * will be overwritten at its original position.
+ *
+ * ## Best practices
+ *
+ * Since the position of overwriting tokens (token in `redef` that overwrite tokens
in the copied language)
+ * doesn't matter, they can technically be in any order. However, this can be
confusing to others that trying to
+ * understand the language definition because, normally, the order of tokens matters
in Prism grammars.
+ *
+ * Therefore, it is encouraged to order overwriting tokens according to the positions
of the overwritten tokens.
+ * Furthermore, all non-overwriting tokens should be placed after the overwriting
ones.
+ *
+ * @param {string} id The id of the language to extend. This has to be a key in
`Prism.languages`.
+ * @param {Grammar} redef The new tokens to append.
+ * @returns {Grammar} The new language created.
+ * @public
+ * @example
+ * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
+ * // Prism.languages.css already has a 'comment' token, so this token will
overwrite CSS' 'comment' token
+ * // at its original position
+ * 'comment': { ... },
+ * // CSS doesn't have a 'color' token, so this token will be appended
+ * 'color': /\b(?:red|green|blue)\b/
+ * });
+ */
+ extend: function (id, redef) {
+ var lang = _.util.clone(_.languages[id]);
+
+ for (var key in redef) {
+ lang[key] = redef[key];
+ }
+
+ return lang;
+ },
+
+ /**
+ * Inserts tokens _before_ another token in a language definition or any other
grammar.
+ *
+ * ## Usage
+ *
+ * This helper method makes it easy to modify existing languages. For example, the
CSS language definition
+ * not only defines CSS highlighting for CSS documents, but also needs to define
highlighting for CSS embedded
+ * in HTML through `<style>` elements. To do this, it needs to modify
`Prism.languages.markup` and add the
+ * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript
object literal, so if you do
+ * this:
+ *
+ * ```js
+ * Prism.languages.markup.style = {
+ * // token
+ * };
+ * ```
+ *
+ * then the `style` token will be added (and processed) at the end. `insertBefore`
allows you to insert tokens
+ * before existing tokens. For the CSS example above, you would use it like this:
+ *
+ * ```js
+ * Prism.languages.insertBefore('markup', 'cdata', {
+ * 'style': {
+ * // token
+ * }
+ * });
+ * ```
+ *
+ * ## Special cases
+ *
+ * If the grammars of `inside` and `insert` have tokens with the same name, the
tokens in `inside`'s grammar
+ * will be ignored.
+ *
+ * This behavior can be used to insert tokens after `before`:
+ *
+ * ```js
+ * Prism.languages.insertBefore('markup', 'comment', {
+ * 'comment': Prism.languages.markup.comment,
+ * // tokens after 'comment'
+ * });
+ * ```
+ *
+ * ## Limitations
+ *
+ * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the
iteration order for object
+ * properties is guaranteed to be the insertion order (except for integer keys) but
some browsers behave
+ * differently when keys are deleted and re-inserted. So `insertBefore` can't be
implemented by temporarily
+ * deleting properties which is necessary to insert at arbitrary positions.
+ *
+ * To solve this problem, `insertBefore` doesn't actually insert the given tokens
into the target object.
+ * Instead, it will create a new object and replace all references to the target
object with the new one. This
+ * can be done without temporarily deleting properties, so the iteration order is
well-defined.
+ *
+ * However, only references that can be reached from `Prism.languages` or `insert`
will be replaced. I.e. if
+ * you hold the target object in a variable, then the value of the variable will not
change.
+ *
+ * ```js
+ * var oldMarkup = Prism.languages.markup;
+ * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
+ *
+ * assert(oldMarkup !== Prism.languages.markup);
+ * assert(newMarkup === Prism.languages.markup);
+ * ```
+ *
+ * @param {string} inside The property of `root` (e.g. a language id in
`Prism.languages`) that contains the
+ * object to be modified.
+ * @param {string} before The key to insert before.
+ * @param {Grammar} insert An object containing the key-value pairs to be inserted.
+ * @param {Object<string, any>} [root] The object containing `inside`, i.e. the
object that contains the
+ * object to be modified.
+ *
+ * Defaults to `Prism.languages`.
+ * @returns {Grammar} The new grammar object.
+ * @public
+ */
+ insertBefore: function (inside, before, insert, root) {
+ root = root || /** @type {any} */ (_.languages);
+ var grammar = root[inside];
+ /** @type {Grammar} */
+ var ret = {};
+
+ for (var token in grammar) {
+ if (grammar.hasOwnProperty(token)) {
+
+ if (token == before) {
+ for (var newToken in insert) {
+ if (insert.hasOwnProperty(newToken)) {
+ ret[newToken] = insert[newToken];
+ }
+ }
+ }
+
+ // Do not insert token which also occur in insert. See #1525
+ if (!insert.hasOwnProperty(token)) {
+ ret[token] = grammar[token];
+ }
+ }
}
- if (classList.contains(no)) {
- return false;
+
+ var old = root[inside];
+ root[inside] = ret;
+
+ // Update references in other language definitions
+ _.languages.DFS(_.languages, function (key, value) {
+ if (value === old && key != inside) {
+ this[key] = ret;
+ }
+ });
+
+ return ret;
+ },
+
+ // Traverse a language definition with Depth First Search
+ DFS: function DFS(o, callback, type, visited) {
+ visited = visited || {};
+
+ var objId = _.util.objId;
+
+ for (var i in o) {
+ if (o.hasOwnProperty(i)) {
+ callback.call(o, i, o[i], type || i);
+
+ var property = o[i];
+ var propertyType = _.util.type(property);
+
+ if (propertyType === 'Object' && !visited[objId(property)]) {
+ visited[objId(property)] = true;
+ DFS(property, callback, null, visited);
+ } else if (propertyType === 'Array' &&
!visited[objId(property)]) {
+ visited[objId(property)] = true;
+ DFS(property, callback, i, visited);
+ }
+ }
}
- element = element.parentElement;
}
- return !!defaultActivation;
- }
- },
+ },
+
+ plugins: {},
- /**
- * This namespace contains all currently loaded languages and the some helper functions to create and
modify languages.
- *
- * @namespace
- * @memberof Prism
- * @public
- */
- languages: {
/**
- * Creates a deep copy of the language with the given id and appends the given tokens.
+ * This is the most high-level function in Prism’s API.
+ * It fetches all the elements that have a `.language-xxxx` class and then calls {@link
Prism.highlightElement} on
+ * each one of them.
*
- * If a token in `redef` also appears in the copied language, then the existing token in the
copied language
- * will be overwritten at its original position.
+ * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
*
- * ## Best practices
- *
- * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the
copied language)
- * doesn't matter, they can technically be in any order. However, this can be confusing to
others that trying to
- * understand the language definition because, normally, the order of tokens matters in Prism
grammars.
+ * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
+ * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
+ * @memberof Prism
+ * @public
+ */
+ highlightAll: function (async, callback) {
+ _.highlightAllUnder(document, async, callback);
+ },
+
+ /**
+ * Fetches all the descendants of `container` that have a `.language-xxxx` class and then
calls
+ * {@link Prism.highlightElement} on each one of them.
*
- * Therefore, it is encouraged to order overwriting tokens according to the positions of the
overwritten tokens.
- * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
+ * The following hooks will be run:
+ * 1. `before-highlightall`
+ * 2. `before-all-elements-highlight`
+ * 3. All hooks of {@link Prism.highlightElement} for each element.
*
- * @param {string} id The id of the language to extend. This has to be a key in
`Prism.languages`.
- * @param {Grammar} redef The new tokens to append.
- * @returns {Grammar} The new language created.
+ * @param {ParentNode} container The root element, whose descendants that have a
`.language-xxxx` class will be highlighted.
+ * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously
using Web Workers.
+ * @param {HighlightCallback} [callback] An optional callback to be invoked on each element
after its highlighting is done.
+ * @memberof Prism
* @public
- * @example
- * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
- * // Prism.languages.css already has a 'comment' token, so this token will overwrite
CSS' 'comment' token
- * // at its original position
- * 'comment': { ... },
- * // CSS doesn't have a 'color' token, so this token will be appended
- * 'color': /\b(?:red|green|blue)\b/
- * });
*/
- extend: function (id, redef) {
- var lang = _.util.clone(_.languages[id]);
+ highlightAllUnder: function (container, async, callback) {
+ var env = {
+ callback: callback,
+ container: container,
+ selector: 'code[class*="language-"], [class*="language-"] code,
code[class*="lang-"], [class*="lang-"] code'
+ };
- for (var key in redef) {
- lang[key] = redef[key];
- }
+ _.hooks.run('before-highlightall', env);
- return lang;
+ env.elements =
Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
+
+ _.hooks.run('before-all-elements-highlight', env);
+
+ for (var i = 0, element; (element = env.elements[i++]);) {
+ _.highlightElement(element, async === true, env.callback);
+ }
},
/**
- * Inserts tokens _before_ another token in a language definition or any other grammar.
- *
- * ## Usage
- *
- * This helper method makes it easy to modify existing languages. For example, the CSS
language definition
- * not only defines CSS highlighting for CSS documents, but also needs to define highlighting
for CSS embedded
- * in HTML through `<style>` elements. To do this, it needs to modify
`Prism.languages.markup` and add the
- * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object
literal, so if you do
- * this:
- *
- * ```js
- * Prism.languages.markup.style = {
- * // token
- * };
- * ```
- *
- * then the `style` token will be added (and processed) at the end. `insertBefore` allows you
to insert tokens
- * before existing tokens. For the CSS example above, you would use it like this:
- *
- * ```js
- * Prism.languages.insertBefore('markup', 'cdata', {
- * 'style': {
- * // token
- * }
- * });
- * ```
- *
- * ## Special cases
- *
- * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in
`inside`'s grammar
- * will be ignored.
- *
- * This behavior can be used to insert tokens after `before`:
- *
- * ```js
- * Prism.languages.insertBefore('markup', 'comment', {
- * 'comment': Prism.languages.markup.comment,
- * // tokens after 'comment'
- * });
- * ```
- *
- * ## Limitations
- *
- * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the
iteration order for object
- * properties is guaranteed to be the insertion order (except for integer keys) but some
browsers behave
- * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented
by temporarily
- * deleting properties which is necessary to insert at arbitrary positions.
- *
- * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the
target object.
- * Instead, it will create a new object and replace all references to the target object with
the new one. This
- * can be done without temporarily deleting properties, so the iteration order is
well-defined.
+ * Highlights the code inside a single element.
*
- * However, only references that can be reached from `Prism.languages` or `insert` will be
replaced. I.e. if
- * you hold the target object in a variable, then the value of the variable will not change.
+ * The following hooks will be run:
+ * 1. `before-sanity-check`
+ * 2. `before-highlight`
+ * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker
if `async` is `true`.
+ * 4. `before-insert`
+ * 5. `after-highlight`
+ * 6. `complete`
*
- * ```js
- * var oldMarkup = Prism.languages.markup;
- * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
- *
- * assert(oldMarkup !== Prism.languages.markup);
- * assert(newMarkup === Prism.languages.markup);
- * ```
+ * Some the above hooks will be skipped if the element doesn't contain any text or there is
no grammar loaded for
+ * the element's language.
*
- * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`)
that contains the
- * object to be modified.
- * @param {string} before The key to insert before.
- * @param {Grammar} insert An object containing the key-value pairs to be inserted.
- * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that
contains the
- * object to be modified.
+ * @param {Element} element The element containing the code.
+ * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language
identifier.
+ * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously
using Web Workers
+ * to improve performance and avoid blocking the UI when highlighting very large chunks of
code. This option is
+ * [disabled by
default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
*
- * Defaults to `Prism.languages`.
- * @returns {Grammar} The new grammar object.
+ * Note: All language definitions required to highlight the code must be included in the main
`prism.js` file for
+ * asynchronous highlighting to work. You can build your own bundle on the
+ * [Download page](https://prismjs.com/download.html).
+ * @param {HighlightCallback} [callback] An optional callback to be invoked after the
highlighting is done.
+ * Mostly useful when `async` is `true`, since in that case, the highlighting is done
asynchronously.
+ * @memberof Prism
* @public
*/
- insertBefore: function (inside, before, insert, root) {
- root = root || /** @type {any} */ (_.languages);
- var grammar = root[inside];
- /** @type {Grammar} */
- var ret = {};
-
- for (var token in grammar) {
- if (grammar.hasOwnProperty(token)) {
-
- if (token == before) {
- for (var newToken in insert) {
- if (insert.hasOwnProperty(newToken)) {
- ret[newToken] = insert[newToken];
- }
- }
- }
-
- // Do not insert token which also occur in insert. See #1525
- if (!insert.hasOwnProperty(token)) {
- ret[token] = grammar[token];
- }
- }
+ highlightElement: function (element, async, callback) {
+ // Find language
+ var language = _.util.getLanguage(element);
+ var grammar = _.languages[language];
+
+ // Set language on the element, if not present
+ element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + '
language-' + language;
+
+ // Set language on the parent, for styling
+ var parent = element.parentElement;
+ if (parent && parent.nodeName.toLowerCase() === 'pre') {
+ parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') +
' language-' + language;
}
- var old = root[inside];
- root[inside] = ret;
+ var code = element.textContent;
- // Update references in other language definitions
- _.languages.DFS(_.languages, function(key, value) {
- if (value === old && key != inside) {
- this[key] = ret;
- }
- });
-
- return ret;
- },
-
- // Traverse a language definition with Depth First Search
- DFS: function DFS(o, callback, type, visited) {
- visited = visited || {};
+ var env = {
+ element: element,
+ language: language,
+ grammar: grammar,
+ code: code
+ };
- var objId = _.util.objId;
+ function insertHighlightedCode(highlightedCode) {
+ env.highlightedCode = highlightedCode;
- for (var i in o) {
- if (o.hasOwnProperty(i)) {
- callback.call(o, i, o[i], type || i);
+ _.hooks.run('before-insert', env);
- var property = o[i],
- propertyType = _.util.type(property);
+ env.element.innerHTML = env.highlightedCode;
- if (propertyType === 'Object' && !visited[objId(property)]) {
- visited[objId(property)] = true;
- DFS(property, callback, null, visited);
- }
- else if (propertyType === 'Array' && !visited[objId(property)]) {
- visited[objId(property)] = true;
- DFS(property, callback, i, visited);
- }
- }
+ _.hooks.run('after-highlight', env);
+ _.hooks.run('complete', env);
+ callback && callback.call(env.element);
}
- }
- },
- plugins: {},
+ _.hooks.run('before-sanity-check', env);
- /**
- * This is the most high-level function in Prism’s API.
- * It fetches all the elements that have a `.language-xxxx` class and then calls {@link
Prism.highlightElement} on
- * each one of them.
- *
- * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
- *
- * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
- * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
- * @memberof Prism
- * @public
- */
- highlightAll: function(async, callback) {
- _.highlightAllUnder(document, async, callback);
- },
-
- /**
- * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
- * {@link Prism.highlightElement} on each one of them.
- *
- * The following hooks will be run:
- * 1. `before-highlightall`
- * 2. `before-all-elements-highlight`
- * 3. All hooks of {@link Prism.highlightElement} for each element.
- *
- * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx`
class will be highlighted.
- * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web
Workers.
- * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its
highlighting is done.
- * @memberof Prism
- * @public
- */
- highlightAllUnder: function(container, async, callback) {
- var env = {
- callback: callback,
- container: container,
- selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"],
[class*="lang-"] code'
- };
-
- _.hooks.run('before-highlightall', env);
+ // plugins may change/add the parent/element
+ parent = env.element.parentElement;
+ if (parent && parent.nodeName.toLowerCase() === 'pre' &&
!parent.hasAttribute('tabindex')) {
+ parent.setAttribute('tabindex', '0');
+ }
- env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
+ if (!env.code) {
+ _.hooks.run('complete', env);
+ callback && callback.call(env.element);
+ return;
+ }
- _.hooks.run('before-all-elements-highlight', env);
+ _.hooks.run('before-highlight', env);
- for (var i = 0, element; element = env.elements[i++];) {
- _.highlightElement(element, async === true, env.callback);
- }
- },
+ if (!env.grammar) {
+ insertHighlightedCode(_.util.encode(env.code));
+ return;
+ }
- /**
- * Highlights the code inside a single element.
- *
- * The following hooks will be run:
- * 1. `before-sanity-check`
- * 2. `before-highlight`
- * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if
`async` is `true`.
- * 4. `before-insert`
- * 5. `after-highlight`
- * 6. `complete`
- *
- * Some the above hooks will be skipped if the element doesn't contain any text or there is no
grammar loaded for
- * the element's language.
- *
- * @param {Element} element The element containing the code.
- * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language
identifier.
- * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web
Workers
- * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This
option is
- * [disabled by
default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
- *
- * Note: All language definitions required to highlight the code must be included in the main
`prism.js` file for
- * asynchronous highlighting to work. You can build your own bundle on the
- * [Download page](https://prismjs.com/download.html).
- * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is
done.
- * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
- * @memberof Prism
- * @public
- */
- highlightElement: function(element, async, callback) {
- // Find language
- var language = _.util.getLanguage(element);
- var grammar = _.languages[language];
-
- // Set language on the element, if not present
- element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' +
language;
-
- // Set language on the parent, for styling
- var parent = element.parentElement;
- if (parent && parent.nodeName.toLowerCase() === 'pre') {
- parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + '
language-' + language;
- }
+ if (async && _self.Worker) {
+ var worker = new Worker(_.filename);
- var code = element.textContent;
+ worker.onmessage = function (evt) {
+ insertHighlightedCode(evt.data);
+ };
- var env = {
- element: element,
- language: language,
- grammar: grammar,
- code: code
- };
+ worker.postMessage(JSON.stringify({
+ language: env.language,
+ code: env.code,
+ immediateClose: true
+ }));
+ } else {
+ insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
+ }
+ },
- function insertHighlightedCode(highlightedCode) {
- env.highlightedCode = highlightedCode;
+ /**
+ * Low-level function, only use if you know what you’re doing. It accepts a string of text as
input
+ * and the language definitions to use, and returns a string with the HTML produced.
+ *
+ * The following hooks will be run:
+ * 1. `before-tokenize`
+ * 2. `after-tokenize`
+ * 3. `wrap`: On each {@link Token}.
+ *
+ * @param {string} text A string with the code to be highlighted.
+ * @param {Grammar} grammar An object containing the tokens to use.
+ *
+ * Usually a language definition like `Prism.languages.markup`.
+ * @param {string} language The name of the language definition passed to `grammar`.
+ * @returns {string} The highlighted HTML.
+ * @memberof Prism
+ * @public
+ * @example
+ * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
+ */
+ highlight: function (text, grammar, language) {
+ var env = {
+ code: text,
+ grammar: grammar,
+ language: language
+ };
+ _.hooks.run('before-tokenize', env);
+ env.tokens = _.tokenize(env.code, env.grammar);
+ _.hooks.run('after-tokenize', env);
+ return Token.stringify(_.util.encode(env.tokens), env.language);
+ },
- _.hooks.run('before-insert', env);
+ /**
+ * This is the heart of Prism, and the most low-level function you can use. It accepts a
string of text as input
+ * and the language definitions to use, and returns an array with the tokenized code.
+ *
+ * When the language definition includes nested tokens, the function is called recursively on
each of these tokens.
+ *
+ * This method could be useful in other contexts as well, as a very crude parser.
+ *
+ * @param {string} text A string with the code to be highlighted.
+ * @param {Grammar} grammar An object containing the tokens to use.
+ *
+ * Usually a language definition like `Prism.languages.markup`.
+ * @returns {TokenStream} An array of strings and tokens, a token stream.
+ * @memberof Prism
+ * @public
+ * @example
+ * let code = `var foo = 0;`;
+ * let tokens = Prism.tokenize(code, Prism.languages.javascript);
+ * tokens.forEach(token => {
+ * if (token instanceof Prism.Token && token.type === 'number') {
+ * console.log(`Found numeric literal: ${token.content}`);
+ * }
+ * });
+ */
+ tokenize: function (text, grammar) {
+ var rest = grammar.rest;
+ if (rest) {
+ for (var token in rest) {
+ grammar[token] = rest[token];
+ }
- env.element.innerHTML = env.highlightedCode;
+ delete grammar.rest;
+ }
- _.hooks.run('after-highlight', env);
- _.hooks.run('complete', env);
- callback && callback.call(env.element);
- }
+ var tokenList = new LinkedList();
+ addAfter(tokenList, tokenList.head, text);
- _.hooks.run('before-sanity-check', env);
+ matchGrammar(text, tokenList, grammar, tokenList.head, 0);
- if (!env.code) {
- _.hooks.run('complete', env);
- callback && callback.call(env.element);
- return;
- }
+ return toArray(tokenList);
+ },
- _.hooks.run('before-highlight', env);
+ /**
+ * @namespace
+ * @memberof Prism
+ * @public
+ */
+ hooks: {
+ all: {},
- if (!env.grammar) {
- insertHighlightedCode(_.util.encode(env.code));
- return;
- }
+ /**
+ * Adds the given callback to the list of callbacks for the given hook.
+ *
+ * The callback will be invoked when the hook it is registered for is run.
+ * Hooks are usually directly run by a highlight function but you can also run hooks
yourself.
+ *
+ * One callback function can be registered to multiple hooks and the same hook
multiple times.
+ *
+ * @param {string} name The name of the hook.
+ * @param {HookCallback} callback The callback function which is given environment
variables.
+ * @public
+ */
+ add: function (name, callback) {
+ var hooks = _.hooks.all;
- if (async && _self.Worker) {
- var worker = new Worker(_.filename);
+ hooks[name] = hooks[name] || [];
- worker.onmessage = function(evt) {
- insertHighlightedCode(evt.data);
- };
+ hooks[name].push(callback);
+ },
- worker.postMessage(JSON.stringify({
- language: env.language,
- code: env.code,
- immediateClose: true
- }));
- }
- else {
- insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
- }
- },
+ /**
+ * Runs a hook invoking all registered callbacks with the given environment variables.
+ *
+ * Callbacks will be invoked synchronously and in the order in which they were
registered.
+ *
+ * @param {string} name The name of the hook.
+ * @param {Object<string, any>} env The environment variables of the hook passed to
all callbacks registered.
+ * @public
+ */
+ run: function (name, env) {
+ var callbacks = _.hooks.all[name];
- /**
- * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
- * and the language definitions to use, and returns a string with the HTML produced.
- *
- * The following hooks will be run:
- * 1. `before-tokenize`
- * 2. `after-tokenize`
- * 3. `wrap`: On each {@link Token}.
- *
- * @param {string} text A string with the code to be highlighted.
- * @param {Grammar} grammar An object containing the tokens to use.
- *
- * Usually a language definition like `Prism.languages.markup`.
- * @param {string} language The name of the language definition passed to `grammar`.
- * @returns {string} The highlighted HTML.
- * @memberof Prism
- * @public
- * @example
- * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
- */
- highlight: function (text, grammar, language) {
- var env = {
- code: text,
- grammar: grammar,
- language: language
- };
- _.hooks.run('before-tokenize', env);
- env.tokens = _.tokenize(env.code, env.grammar);
- _.hooks.run('after-tokenize', env);
- return Token.stringify(_.util.encode(env.tokens), env.language);
- },
+ if (!callbacks || !callbacks.length) {
+ return;
+ }
- /**
- * This is the heart of Prism, and the most low-level function you can use. It accepts a string of
text as input
- * and the language definitions to use, and returns an array with the tokenized code.
- *
- * When the language definition includes nested tokens, the function is called recursively on each of
these tokens.
- *
- * This method could be useful in other contexts as well, as a very crude parser.
- *
- * @param {string} text A string with the code to be highlighted.
- * @param {Grammar} grammar An object containing the tokens to use.
- *
- * Usually a language definition like `Prism.languages.markup`.
- * @returns {TokenStream} An array of strings and tokens, a token stream.
- * @memberof Prism
- * @public
- * @example
- * let code = `var foo = 0;`;
- * let tokens = Prism.tokenize(code, Prism.languages.javascript);
- * tokens.forEach(token => {
- * if (token instanceof Prism.Token && token.type === 'number') {
- * console.log(`Found numeric literal: ${token.content}`);
- * }
- * });
- */
- tokenize: function(text, grammar) {
- var rest = grammar.rest;
- if (rest) {
- for (var token in rest) {
- grammar[token] = rest[token];
+ for (var i = 0, callback; (callback = callbacks[i++]);) {
+ callback(env);
+ }
}
+ },
- delete grammar.rest;
- }
-
- var tokenList = new LinkedList();
- addAfter(tokenList, tokenList.head, text);
+ Token: Token
+ };
+ _self.Prism = _;
- matchGrammar(text, tokenList, grammar, tokenList.head, 0);
- return toArray(tokenList);
- },
+ // Typescript note:
+ // The following can be used to import the Token type in JSDoc:
+ //
+ // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
/**
- * @namespace
- * @memberof Prism
+ * Creates a new token.
+ *
+ * @param {string} type See {@link Token#type type}
+ * @param {string | TokenStream} content See {@link Token#content content}
+ * @param {string|string[]} [alias] The alias(es) of the token.
+ * @param {string} [matchedStr=""] A copy of the full string this token was created from.
+ * @class
+ * @global
* @public
*/
- hooks: {
- all: {},
-
+ function Token(type, content, alias, matchedStr) {
/**
- * Adds the given callback to the list of callbacks for the given hook.
+ * The type of the token.
*
- * The callback will be invoked when the hook it is registered for is run.
- * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
+ * This is usually the key of a pattern in a {@link Grammar}.
*
- * One callback function can be registered to multiple hooks and the same hook multiple times.
- *
- * @param {string} name The name of the hook.
- * @param {HookCallback} callback The callback function which is given environment variables.
+ * @type {string}
+ * @see GrammarToken
* @public
*/
- add: function (name, callback) {
- var hooks = _.hooks.all;
-
- hooks[name] = hooks[name] || [];
-
- hooks[name].push(callback);
- },
-
+ this.type = type;
/**
- * Runs a hook invoking all registered callbacks with the given environment variables.
+ * The strings or tokens contained by this token.
*
- * Callbacks will be invoked synchronously and in the order in which they were registered.
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
*
- * @param {string} name The name of the hook.
- * @param {Object<string, any>} env The environment variables of the hook passed to all
callbacks registered.
+ * @type {string | TokenStream}
* @public
*/
- run: function (name, env) {
- var callbacks = _.hooks.all[name];
-
- if (!callbacks || !callbacks.length) {
- return;
- }
-
- for (var i=0, callback; callback = callbacks[i++];) {
- callback(env);
- }
- }
- },
-
- Token: Token
-};
-_self.Prism = _;
-
-
-// Typescript note:
-// The following can be used to import the Token type in JSDoc:
-//
-// @typedef {InstanceType<import("./prism-core")["Token"]>} Token
+ this.content = content;
+ /**
+ * The alias(es) of the token.
+ *
+ * @type {string|string[]}
+ * @see GrammarToken
+ * @public
+ */
+ this.alias = alias;
+ // Copy of the full string this token was created from
+ this.length = (matchedStr || '').length | 0;
+ }
-/**
- * Creates a new token.
- *
- * @param {string} type See {@link Token#type type}
- * @param {string | TokenStream} content See {@link Token#content content}
- * @param {string|string[]} [alias] The alias(es) of the token.
- * @param {string} [matchedStr=""] A copy of the full string this token was created from.
- * @class
- * @global
- * @public
- */
-function Token(type, content, alias, matchedStr) {
/**
- * The type of the token.
+ * A token stream is an array of strings and {@link Token Token} objects.
*
- * This is usually the key of a pattern in a {@link Grammar}.
+ * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal
ones) that process
+ * them.
*
- * @type {string}
- * @see GrammarToken
- * @public
- */
- this.type = type;
- /**
- * The strings or tokens contained by this token.
+ * 1. No adjacent strings.
+ * 2. No empty strings.
*
- * This will be a token stream if the pattern matched also defined an `inside` grammar.
+ * The only exception here is the token stream that only contains the empty string and nothing
else.
*
- * @type {string | TokenStream}
+ * @typedef {Array<string | Token>} TokenStream
+ * @global
* @public
*/
- this.content = content;
+
/**
- * The alias(es) of the token.
+ * Converts the given token or token stream to an HTML representation.
*
- * @type {string|string[]}
- * @see GrammarToken
- * @public
+ * The following hooks will be run:
+ * 1. `wrap`: On each {@link Token}.
+ *
+ * @param {string | Token | TokenStream} o The token or token stream to be converted.
+ * @param {string} language The name of current language.
+ * @returns {string} The HTML representation of the token or token stream.
+ * @memberof Token
+ * @static
*/
- this.alias = alias;
- // Copy of the full string this token was created from
- this.length = (matchedStr || '').length | 0;
-}
-
-/**
- * A token stream is an array of strings and {@link Token Token} objects.
- *
- * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones)
that process
- * them.
- *
- * 1. No adjacent strings.
- * 2. No empty strings.
- *
- * The only exception here is the token stream that only contains the empty string and nothing else.
- *
- * @typedef {Array<string | Token>} TokenStream
- * @global
- * @public
- */
-
-/**
- * Converts the given token or token stream to an HTML representation.
- *
- * The following hooks will be run:
- * 1. `wrap`: On each {@link Token}.
- *
- * @param {string | Token | TokenStream} o The token or token stream to be converted.
- * @param {string} language The name of current language.
- * @returns {string} The HTML representation of the token or token stream.
- * @memberof Token
- * @static
- */
-Token.stringify = function stringify(o, language) {
- if (typeof o == 'string') {
- return o;
- }
- if (Array.isArray(o)) {
- var s = '';
- o.forEach(function (e) {
- s += stringify(e, language);
- });
- return s;
- }
-
- var env = {
- type: o.type,
- content: stringify(o.content, language),
- tag: 'span',
- classes: ['token', o.type],
- attributes: {},
- language: language
- };
-
- var aliases = o.alias;
- if (aliases) {
- if (Array.isArray(aliases)) {
- Array.prototype.push.apply(env.classes, aliases);
- } else {
- env.classes.push(aliases);
+ Token.stringify = function stringify(o, language) {
+ if (typeof o == 'string') {
+ return o;
+ }
+ if (Array.isArray(o)) {
+ var s = '';
+ o.forEach(function (e) {
+ s += stringify(e, language);
+ });
+ return s;
}
- }
- _.hooks.run('wrap', env);
+ var env = {
+ type: o.type,
+ content: stringify(o.content, language),
+ tag: 'span',
+ classes: ['token', o.type],
+ attributes: {},
+ language: language
+ };
- var attributes = '';
- for (var name in env.attributes) {
- attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"';
- }
+ var aliases = o.alias;
+ if (aliases) {
+ if (Array.isArray(aliases)) {
+ Array.prototype.push.apply(env.classes, aliases);
+ } else {
+ env.classes.push(aliases);
+ }
+ }
- return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content +
'</' + env.tag + '>';
-};
+ _.hooks.run('wrap', env);
-/**
- * @param {RegExp} pattern
- * @param {number} pos
- * @param {string} text
- * @param {boolean} lookbehind
- * @returns {RegExpExecArray | null}
- */
-function matchPattern(pattern, pos, text, lookbehind) {
- pattern.lastIndex = pos;
- var match = pattern.exec(text);
- if (match && lookbehind && match[1]) {
- // change the match to remove the text matched by the Prism lookbehind group
- var lookbehindLength = match[1].length;
- match.index += lookbehindLength;
- match[0] = match[0].slice(lookbehindLength);
- }
- return match;
-}
-
-/**
- * @param {string} text
- * @param {LinkedList<string | Token>} tokenList
- * @param {any} grammar
- * @param {LinkedListNode<string | Token>} startNode
- * @param {number} startPos
- * @param {RematchOptions} [rematch]
- * @returns {void}
- * @private
- *
- * @typedef RematchOptions
- * @property {string} cause
- * @property {number} reach
- */
-function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
- for (var token in grammar) {
- if (!grammar.hasOwnProperty(token) || !grammar[token]) {
- continue;
+ var attributes = '';
+ for (var name in env.attributes) {
+ attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g,
'"') + '"';
}
- var patterns = grammar[token];
- patterns = Array.isArray(patterns) ? patterns : [patterns];
-
- for (var j = 0; j < patterns.length; ++j) {
- if (rematch && rematch.cause == token + ',' + j) {
- return;
- }
+ return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' +
env.content + '</' + env.tag + '>';
+ };
- var patternObj = patterns[j],
- inside = patternObj.inside,
- lookbehind = !!patternObj.lookbehind,
- greedy = !!patternObj.greedy,
- alias = patternObj.alias;
+ /**
+ * @param {RegExp} pattern
+ * @param {number} pos
+ * @param {string} text
+ * @param {boolean} lookbehind
+ * @returns {RegExpExecArray | null}
+ */
+ function matchPattern(pattern, pos, text, lookbehind) {
+ pattern.lastIndex = pos;
+ var match = pattern.exec(text);
+ if (match && lookbehind && match[1]) {
+ // change the match to remove the text matched by the Prism lookbehind group
+ var lookbehindLength = match[1].length;
+ match.index += lookbehindLength;
+ match[0] = match[0].slice(lookbehindLength);
+ }
+ return match;
+ }
- if (greedy && !patternObj.pattern.global) {
- // Without the global flag, lastIndex won't work
- var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
- patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
+ /**
+ * @param {string} text
+ * @param {LinkedList<string | Token>} tokenList
+ * @param {any} grammar
+ * @param {LinkedListNode<string | Token>} startNode
+ * @param {number} startPos
+ * @param {RematchOptions} [rematch]
+ * @returns {void}
+ * @private
+ *
+ * @typedef RematchOptions
+ * @property {string} cause
+ * @property {number} reach
+ */
+ function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
+ for (var token in grammar) {
+ if (!grammar.hasOwnProperty(token) || !grammar[token]) {
+ continue;
}
- /** @type {RegExp} */
- var pattern = patternObj.pattern || patternObj;
-
- for ( // iterate the token list and keep track of the current token/string position
- var currentNode = startNode.next, pos = startPos;
- currentNode !== tokenList.tail;
- pos += currentNode.value.length, currentNode = currentNode.next
- ) {
+ var patterns = grammar[token];
+ patterns = Array.isArray(patterns) ? patterns : [patterns];
- if (rematch && pos >= rematch.reach) {
- break;
+ for (var j = 0; j < patterns.length; ++j) {
+ if (rematch && rematch.cause == token + ',' + j) {
+ return;
}
- var str = currentNode.value;
+ var patternObj = patterns[j];
+ var inside = patternObj.inside;
+ var lookbehind = !!patternObj.lookbehind;
+ var greedy = !!patternObj.greedy;
+ var alias = patternObj.alias;
- if (tokenList.length > text.length) {
- // Something went terribly wrong, ABORT, ABORT!
- return;
+ if (greedy && !patternObj.pattern.global) {
+ // Without the global flag, lastIndex won't work
+ var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
+ patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
}
- if (str instanceof Token) {
- continue;
- }
+ /** @type {RegExp} */
+ var pattern = patternObj.pattern || patternObj;
- var removeCount = 1; // this is the to parameter of removeBetween
- var match;
+ for ( // iterate the token list and keep track of the current token/string
position
+ var currentNode = startNode.next, pos = startPos;
+ currentNode !== tokenList.tail;
+ pos += currentNode.value.length, currentNode = currentNode.next
+ ) {
- if (greedy) {
- match = matchPattern(pattern, pos, text, lookbehind);
- if (!match) {
+ if (rematch && pos >= rematch.reach) {
break;
}
- var from = match.index;
- var to = match.index + match[0].length;
- var p = pos;
+ var str = currentNode.value;
- // find the node that contains the match
- p += currentNode.value.length;
- while (from >= p) {
- currentNode = currentNode.next;
- p += currentNode.value.length;
+ if (tokenList.length > text.length) {
+ // Something went terribly wrong, ABORT, ABORT!
+ return;
}
- // adjust pos (and p)
- p -= currentNode.value.length;
- pos = p;
- // the current node is a Token, then the match starts inside another
Token, which is invalid
- if (currentNode.value instanceof Token) {
+ if (str instanceof Token) {
continue;
}
- // find the last node which is affected by this match
- for (
- var k = currentNode;
- k !== tokenList.tail && (p < to || typeof k.value ===
'string');
- k = k.next
- ) {
- removeCount++;
- p += k.value.length;
- }
- removeCount--;
+ var removeCount = 1; // this is the to parameter of removeBetween
+ var match;
- // replace with the new match
- str = text.slice(pos, p);
- match.index -= pos;
- } else {
- match = matchPattern(pattern, 0, str, lookbehind);
- if (!match) {
- continue;
+ if (greedy) {
+ match = matchPattern(pattern, pos, text, lookbehind);
+ if (!match) {
+ break;
+ }
+
+ var from = match.index;
+ var to = match.index + match[0].length;
+ var p = pos;
+
+ // find the node that contains the match
+ p += currentNode.value.length;
+ while (from >= p) {
+ currentNode = currentNode.next;
+ p += currentNode.value.length;
+ }
+ // adjust pos (and p)
+ p -= currentNode.value.length;
+ pos = p;
+
+ // the current node is a Token, then the match starts inside
another Token, which is invalid
+ if (currentNode.value instanceof Token) {
+ continue;
+ }
+
+ // find the last node which is affected by this match
+ for (
+ var k = currentNode;
+ k !== tokenList.tail && (p < to || typeof k.value ===
'string');
+ k = k.next
+ ) {
+ removeCount++;
+ p += k.value.length;
+ }
+ removeCount--;
+
+ // replace with the new match
+ str = text.slice(pos, p);
+ match.index -= pos;
+ } else {
+ match = matchPattern(pattern, 0, str, lookbehind);
+ if (!match) {
+ continue;
+ }
}
- }
- var from = match.index,
- matchStr = match[0],
- before = str.slice(0, from),
- after = str.slice(from + matchStr.length);
+ // eslint-disable-next-line no-redeclare
+ var from = match.index;
+ var matchStr = match[0];
+ var before = str.slice(0, from);
+ var after = str.slice(from + matchStr.length);
- var reach = pos + str.length;
- if (rematch && reach > rematch.reach) {
- rematch.reach = reach;
- }
+ var reach = pos + str.length;
+ if (rematch && reach > rematch.reach) {
+ rematch.reach = reach;
+ }
- var removeFrom = currentNode.prev;
+ var removeFrom = currentNode.prev;
- if (before) {
- removeFrom = addAfter(tokenList, removeFrom, before);
- pos += before.length;
- }
+ if (before) {
+ removeFrom = addAfter(tokenList, removeFrom, before);
+ pos += before.length;
+ }
- removeRange(tokenList, removeFrom, removeCount);
+ removeRange(tokenList, removeFrom, removeCount);
- var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) :
matchStr, alias, matchStr);
- currentNode = addAfter(tokenList, removeFrom, wrapped);
+ var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside)
: matchStr, alias, matchStr);
+ currentNode = addAfter(tokenList, removeFrom, wrapped);
- if (after) {
- addAfter(tokenList, currentNode, after);
- }
+ if (after) {
+ addAfter(tokenList, currentNode, after);
+ }
- if (removeCount > 1) {
- // at least one Token object was removed, so we have to do some
rematching
- // this can only happen if the current pattern is greedy
+ if (removeCount > 1) {
+ // at least one Token object was removed, so we have to do
some rematching
+ // this can only happen if the current pattern is greedy
- /** @type {RematchOptions} */
- var nestedRematch = {
- cause: token + ',' + j,
- reach: reach
- };
- matchGrammar(text, tokenList, grammar, currentNode.prev, pos,
nestedRematch);
+ /** @type {RematchOptions} */
+ var nestedRematch = {
+ cause: token + ',' + j,
+ reach: reach
+ };
+ matchGrammar(text, tokenList, grammar, currentNode.prev, pos,
nestedRematch);
- // the reach might have been extended because of the rematching
- if (rematch && nestedRematch.reach > rematch.reach) {
- rematch.reach = nestedRematch.reach;
+ // the reach might have been extended because of the
rematching
+ if (rematch && nestedRematch.reach > rematch.reach) {
+ rematch.reach = nestedRematch.reach;
+ }
}
}
}
}
}
-}
-/**
- * @typedef LinkedListNode
- * @property {T} value
- * @property {LinkedListNode<T> | null} prev The previous node.
- * @property {LinkedListNode<T> | null} next The next node.
- * @template T
- * @private
- */
+ /**
+ * @typedef LinkedListNode
+ * @property {T} value
+ * @property {LinkedListNode<T> | null} prev The previous node.
+ * @property {LinkedListNode<T> | null} next The next node.
+ * @template T
+ * @private
+ */
-/**
- * @template T
- * @private
- */
-function LinkedList() {
- /** @type {LinkedListNode<T>} */
- var head = { value: null, prev: null, next: null };
- /** @type {LinkedListNode<T>} */
- var tail = { value: null, prev: head, next: null };
- head.next = tail;
-
- /** @type {LinkedListNode<T>} */
- this.head = head;
- /** @type {LinkedListNode<T>} */
- this.tail = tail;
- this.length = 0;
-}
+ /**
+ * @template T
+ * @private
+ */
+ function LinkedList() {
+ /** @type {LinkedListNode<T>} */
+ var head = { value: null, prev: null, next: null };
+ /** @type {LinkedListNode<T>} */
+ var tail = { value: null, prev: head, next: null };
+ head.next = tail;
+
+ /** @type {LinkedListNode<T>} */
+ this.head = head;
+ /** @type {LinkedListNode<T>} */
+ this.tail = tail;
+ this.length = 0;
+ }
-/**
- * Adds a new node with the given value to the list.
- * @param {LinkedList<T>} list
- * @param {LinkedListNode<T>} node
- * @param {T} value
- * @returns {LinkedListNode<T>} The added node.
- * @template T
- */
-function addAfter(list, node, value) {
- // assumes that node != list.tail && values.length >= 0
- var next = node.next;
+ /**
+ * Adds a new node with the given value to the list.
+ *
+ * @param {LinkedList<T>} list
+ * @param {LinkedListNode<T>} node
+ * @param {T} value
+ * @returns {LinkedListNode<T>} The added node.
+ * @template T
+ */
+ function addAfter(list, node, value) {
+ // assumes that node != list.tail && values.length >= 0
+ var next = node.next;
- var newNode = { value: value, prev: node, next: next };
- node.next = newNode;
- next.prev = newNode;
- list.length++;
+ var newNode = { value: value, prev: node, next: next };
+ node.next = newNode;
+ next.prev = newNode;
+ list.length++;
- return newNode;
-}
-/**
- * Removes `count` nodes after the given node. The given node will not be removed.
- * @param {LinkedList<T>} list
- * @param {LinkedListNode<T>} node
- * @param {number} count
- * @template T
- */
-function removeRange(list, node, count) {
- var next = node.next;
- for (var i = 0; i < count && next !== list.tail; i++) {
- next = next.next;
+ return newNode;
}
- node.next = next;
- next.prev = node;
- list.length -= i;
-}
-/**
- * @param {LinkedList<T>} list
- * @returns {T[]}
- * @template T
- */
-function toArray(list) {
- var array = [];
- var node = list.head.next;
- while (node !== list.tail) {
- array.push(node.value);
- node = node.next;
+ /**
+ * Removes `count` nodes after the given node. The given node will not be removed.
+ *
+ * @param {LinkedList<T>} list
+ * @param {LinkedListNode<T>} node
+ * @param {number} count
+ * @template T
+ */
+ function removeRange(list, node, count) {
+ var next = node.next;
+ for (var i = 0; i < count && next !== list.tail; i++) {
+ next = next.next;
+ }
+ node.next = next;
+ next.prev = node;
+ list.length -= i;
+ }
+ /**
+ * @param {LinkedList<T>} list
+ * @returns {T[]}
+ * @template T
+ */
+ function toArray(list) {
+ var array = [];
+ var node = list.head.next;
+ while (node !== list.tail) {
+ array.push(node.value);
+ node = node.next;
+ }
+ return array;
}
- return array;
-}
-if (!_self.document) {
- if (!_self.addEventListener) {
- // in Node.js
- return _;
- }
+ if (!_self.document) {
+ if (!_self.addEventListener) {
+ // in Node.js
+ return _;
+ }
- if (!_.disableWorkerMessageHandler) {
- // In worker
- _self.addEventListener('message', function (evt) {
- var message = JSON.parse(evt.data),
- lang = message.language,
- code = message.code,
- immediateClose = message.immediateClose;
-
- _self.postMessage(_.highlight(code, _.languages[lang], lang));
- if (immediateClose) {
- _self.close();
- }
- }, false);
- }
+ if (!_.disableWorkerMessageHandler) {
+ // In worker
+ _self.addEventListener('message', function (evt) {
+ var message = JSON.parse(evt.data);
+ var lang = message.language;
+ var code = message.code;
+ var immediateClose = message.immediateClose;
+
+ _self.postMessage(_.highlight(code, _.languages[lang], lang));
+ if (immediateClose) {
+ _self.close();
+ }
+ }, false);
+ }
- return _;
-}
+ return _;
+ }
-// Get current script and highlight
-var script = _.util.currentScript();
+ // Get current script and highlight
+ var script = _.util.currentScript();
-if (script) {
- _.filename = script.src;
+ if (script) {
+ _.filename = script.src;
- if (script.hasAttribute('data-manual')) {
- _.manual = true;
+ if (script.hasAttribute('data-manual')) {
+ _.manual = true;
+ }
}
-}
-function highlightAutomaticallyCallback() {
- if (!_.manual) {
- _.highlightAll();
+ function highlightAutomaticallyCallback() {
+ if (!_.manual) {
+ _.highlightAll();
+ }
}
-}
-if (!_.manual) {
- // If the document state is "loading", then we'll use DOMContentLoaded.
- // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
- // DOMContentLoaded event because there might be some plugins or languages which have also been
deferred and they
- // might take longer one animation frame to execute which can create a race condition where only some
plugins have
- // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
- // See https://github.com/PrismJS/prism/issues/2102
- var readyState = document.readyState;
- if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
- document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
- } else {
- if (window.requestAnimationFrame) {
- window.requestAnimationFrame(highlightAutomaticallyCallback);
+ if (!_.manual) {
+ // If the document state is "loading", then we'll use DOMContentLoaded.
+ // If the document state is "interactive" and the prism.js script is deferred, then we'll
also use the
+ // DOMContentLoaded event because there might be some plugins or languages which have also
been deferred and they
+ // might take longer one animation frame to execute which can create a race condition where
only some plugins have
+ // been loaded when Prism.highlightAll() is executed, depending on how fast resources are
loaded.
+ // See https://github.com/PrismJS/prism/issues/2102
+ var readyState = document.readyState;
+ if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
+ document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
} else {
- window.setTimeout(highlightAutomaticallyCallback, 16);
+ if (window.requestAnimationFrame) {
+ window.requestAnimationFrame(highlightAutomaticallyCallback);
+ } else {
+ window.setTimeout(highlightAutomaticallyCallback, 16);
+ }
}
}
-}
-return _;
+ return _;
-})(_self);
+}(_self));
if (typeof module !== 'undefined' && module.exports) {
module.exports = Prism;
@@ -1176,7 +1194,7 @@ if (typeof global !== 'undefined') {
* each another.
* @global
* @public
-*/
+ */
/**
* @typedef Grammar
@@ -1194,7 +1212,7 @@ if (typeof global !== 'undefined') {
* @returns {void}
* @global
* @public
-*/
+ */
/**
* @callback HookCallback
@@ -1239,6 +1257,7 @@ Prism.languages.markup = {
'namespace': /^[^\s>\/:]+:/
}
},
+ 'special-attr': [],
'attr-value': {
pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
inside: {
@@ -1325,6 +1344,49 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
Prism.languages.insertBefore('markup', 'cdata', def);
}
});
+Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
+ /**
+ * Adds an pattern to highlight languages embedded in HTML attributes.
+ *
+ * An example of an inlined language is CSS with `style` attributes.
+ *
+ * @param {string} attrName The name of the tag that contains the inlined language. This name will be
treated as
+ * case insensitive.
+ * @param {string} lang The language key.
+ * @example
+ * addAttribute('style', 'css');
+ */
+ value: function (attrName, lang) {
+ Prism.languages.markup.tag.inside['special-attr'].push({
+ pattern: RegExp(
+ /(^|["'\s])/.source + '(?:' + attrName + ')' +
/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
+ 'i'
+ ),
+ lookbehind: true,
+ inside: {
+ 'attr-name': /^[^\s=]+/,
+ 'attr-value': {
+ pattern: /=[\s\S]+/,
+ inside: {
+ 'value': {
+ pattern: /(=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
+ lookbehind: true,
+ alias: [lang, 'language-' + lang],
+ inside: Prism.languages[lang]
+ },
+ 'punctuation': [
+ {
+ pattern: /^=/,
+ alias: 'attr-equals'
+ },
+ /"|'/
+ ]
+ }
+ }
+ }
+ });
+ }
+});
Prism.languages.html = Prism.languages.markup;
Prism.languages.mathml = Prism.languages.markup;
@@ -1386,34 +1448,7 @@ Prism.languages.rss = Prism.languages.xml;
var markup = Prism.languages.markup;
if (markup) {
markup.tag.addInlined('style', 'css');
-
- Prism.languages.insertBefore('inside', 'attr-value', {
- 'style-attr': {
- pattern: /(^|["'\s])style\s*=\s*(?:"[^"]*"|'[^']*')/i,
- lookbehind: true,
- inside: {
- 'attr-value': {
- pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
- inside: {
- 'style': {
- pattern: /(["'])[\s\S]+(?=["']$)/,
- lookbehind: true,
- alias: 'language-css',
- inside: Prism.languages.css
- },
- 'punctuation': [
- {
- pattern: /^=/,
- alias: 'attr-equals'
- },
- /"|'/
- ]
- }
- },
- 'attr-name': /^style/i
- }
- }
- }, markup.tag);
+ markup.tag.addAttribute('style', 'css');
}
}(Prism));
@@ -1464,7 +1499,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', {
lookbehind: true
},
{
- pattern:
/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
+ pattern:
/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
lookbehind: true
},
],
@@ -1478,7 +1513,7 @@ Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|ext
Prism.languages.insertBefore('javascript', 'keyword', {
'regex': {
- pattern:
/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
+ pattern:
/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
lookbehind: true,
greedy: true,
inside: {
@@ -1522,6 +1557,11 @@ Prism.languages.insertBefore('javascript', 'keyword', {
});
Prism.languages.insertBefore('javascript', 'string', {
+ 'hashbang': {
+ pattern: /^#!.*/,
+ greedy: true,
+ alias: 'comment'
+ },
'template-string': {
pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,
greedy: true,
@@ -1548,11 +1588,18 @@ Prism.languages.insertBefore('javascript', 'string', {
if (Prism.languages.markup) {
Prism.languages.markup.tag.addInlined('script', 'javascript');
+
+ // add attribute support for all DOM events.
+ // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
+ Prism.languages.markup.tag.addAttribute(
+
/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,
+ 'javascript'
+ );
}
Prism.languages.js = Prism.languages.javascript;
-(function(Prism) {
+(function (Prism) {
// $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
// + LC_ALL, RANDOM, REPLY, SECONDS.
// + make sure PS1..4 are here as they are not always set,
@@ -1569,7 +1616,7 @@ Prism.languages.js = Prism.languages.javascript;
var insideString = {
'bash': commandAfterHeredoc,
'environment': {
- pattern: RegExp("\\$" + envVars),
+ pattern: RegExp('\\$' + envVars),
alias: 'constant'
},
'variable': [
@@ -1609,7 +1656,7 @@ Prism.languages.js = Prism.languages.javascript;
'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
'punctuation': /[\[\]]/,
'environment': {
- pattern: RegExp("(\\{)" + envVars),
+ pattern: RegExp('(\\{)' + envVars),
lookbehind: true,
alias: 'constant'
}
@@ -1637,13 +1684,13 @@ Prism.languages.js = Prism.languages.javascript;
// but not “foo {”
{
// a) and c)
- pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,
+ pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
lookbehind: true,
alias: 'function'
},
{
// b)
- pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/,
+ pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
alias: 'function'
}
],
@@ -1659,7 +1706,7 @@ Prism.languages.js = Prism.languages.javascript;
pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,
inside: {
'environment': {
- pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars),
+ pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
lookbehind: true,
alias: 'constant'
}
@@ -1687,14 +1734,29 @@ Prism.languages.js = Prism.languages.javascript;
},
// “Normal” string
{
- pattern:
/(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\2)[^\\`$])*\2/,
+ // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
+ pattern:
/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
lookbehind: true,
greedy: true,
inside: insideString
+ },
+ {
+ // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
+ pattern: /(^|[^$\\])'[^']*'/,
+ lookbehind: true,
+ greedy: true
+ },
+ {
+ // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
+ pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
+ greedy: true,
+ inside: {
+ 'entity': insideString.entity
+ }
}
],
'environment': {
- pattern: RegExp("\\$?" + envVars),
+ pattern: RegExp('\\$?' + envVars),
alias: 'constant'
},
'variable': insideString.variable,
@@ -1758,12 +1820,12 @@ Prism.languages.js = Prism.languages.javascript;
'number'
];
var inside = insideString.variable[1].inside;
- for(var i = 0; i < toBeCopied.length; i++) {
+ for (var i = 0; i < toBeCopied.length; i++) {
inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
}
Prism.languages.shell = Prism.languages.bash;
-})(Prism);
+}(Prism));
Prism.languages.c = Prism.languages.extend('clike', {
'comment': {
@@ -1831,7 +1893,8 @@ delete Prism.languages.c['boolean'];
(function (Prism) {
- var keyword =
/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;
+ var keyword =
/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;
+ var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function () {
return keyword.source; });
Prism.languages.cpp = Prism.languages.extend('c', {
'class-name': [
@@ -1857,11 +1920,31 @@ delete Prism.languages.c['boolean'];
pattern:
/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,
greedy: true
},
- 'operator':
/>>=?|<<=?|->|([-+&|:])\1|[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
+ 'operator':
/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
'boolean': /\b(?:true|false)\b/
});
Prism.languages.insertBefore('cpp', 'string', {
+ 'module': {
+ // https://en.cppreference.com/w/cpp/language/modules
+ pattern: RegExp(
+ /(\b(?:module|import)\s+)/.source +
+ '(?:' +
+ // header-name
+ /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source +
+ '|' +
+ // module name or partition or both
+
/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function () { return modName;
}) +
+ ')'
+ ),
+ lookbehind: true,
+ greedy: true,
+ inside: {
+ 'string': /^[<"][\s\S]+/,
+ 'operator': /:/,
+ 'punctuation': /\./
+ }
+ },
'raw-string': {
pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
alias: 'string',
@@ -1869,6 +1952,27 @@ delete Prism.languages.c['boolean'];
}
});
+ Prism.languages.insertBefore('cpp', 'keyword', {
+ 'generic-function': {
+ pattern: /\b[a-z_]\w*\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\s*\()/i,
+ inside: {
+ 'function': /^\w+/,
+ 'generic': {
+ pattern: /<[\s\S]+/,
+ alias: 'class-name',
+ inside: Prism.languages.cpp
+ }
+ }
+ }
+ });
+
+ Prism.languages.insertBefore('cpp', 'operator', {
+ 'double-colon': {
+ pattern: /::/,
+ alias: 'punctuation'
+ }
+ });
+
Prism.languages.insertBefore('cpp', 'class-name', {
// the base clause is an optional list of parent classes
// https://en.cppreference.com/w/cpp/language/class
@@ -1879,108 +1983,109 @@ delete Prism.languages.c['boolean'];
inside: Prism.languages.extend('cpp', {})
}
});
- Prism.languages.insertBefore('inside', 'operator', {
+
+ Prism.languages.insertBefore('inside', 'double-colon', {
// All untokenized words that are not namespaces should be class names
'class-name': /\b[a-z_]\w*\b(?!\s*::)/i
}, Prism.languages.cpp['base-clause']);
}(Prism));
-(function(Prism) {
-
-// Ignore comments starting with { to privilege string interpolation highlighting
-var comment = /#(?!\{).+/,
- interpolation = {
- pattern: /#\{[^}]+\}/,
- alias: 'variable'
- };
+(function (Prism) {
-Prism.languages.coffeescript = Prism.languages.extend('javascript', {
- 'comment': comment,
- 'string': [
+ // Ignore comments starting with { to privilege string interpolation highlighting
+ var comment = /#(?!\{).+/;
+ var interpolation = {
+ pattern: /#\{[^}]+\}/,
+ alias: 'variable'
+ };
- // Strings are multiline
- {
- pattern: /'(?:\\[\s\S]|[^\\'])*'/,
- greedy: true
- },
+ Prism.languages.coffeescript = Prism.languages.extend('javascript', {
+ 'comment': comment,
+ 'string': [
- {
// Strings are multiline
- pattern: /"(?:\\[\s\S]|[^\\"])*"/,
- greedy: true,
- inside: {
- 'interpolation': interpolation
+ {
+ pattern: /'(?:\\[\s\S]|[^\\'])*'/,
+ greedy: true
+ },
+
+ {
+ // Strings are multiline
+ pattern: /"(?:\\[\s\S]|[^\\"])*"/,
+ greedy: true,
+ inside: {
+ 'interpolation': interpolation
+ }
}
+ ],
+ 'keyword':
/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,
+ 'class-member': {
+ pattern: /@(?!\d)\w+/,
+ alias: 'variable'
}
- ],
- 'keyword':
/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,
- 'class-member': {
- pattern: /@(?!\d)\w+/,
- alias: 'variable'
- }
-});
-
-Prism.languages.insertBefore('coffeescript', 'comment', {
- 'multiline-comment': {
- pattern: /###[\s\S]+?###/,
- alias: 'comment'
- },
+ });
- // Block regexp can contain comments and interpolation
- 'block-regex': {
- pattern: /\/{3}[\s\S]*?\/{3}/,
- alias: 'regex',
- inside: {
- 'comment': comment,
- 'interpolation': interpolation
- }
- }
-});
+ Prism.languages.insertBefore('coffeescript', 'comment', {
+ 'multiline-comment': {
+ pattern: /###[\s\S]+?###/,
+ alias: 'comment'
+ },
-Prism.languages.insertBefore('coffeescript', 'string', {
- 'inline-javascript': {
- pattern: /`(?:\\[\s\S]|[^\\`])*`/,
- inside: {
- 'delimiter': {
- pattern: /^`|`$/,
- alias: 'punctuation'
- },
- 'script': {
- pattern: /[\s\S]+/,
- alias: 'language-javascript',
- inside: Prism.languages.javascript
+ // Block regexp can contain comments and interpolation
+ 'block-regex': {
+ pattern: /\/{3}[\s\S]*?\/{3}/,
+ alias: 'regex',
+ inside: {
+ 'comment': comment,
+ 'interpolation': interpolation
}
}
- },
+ });
- // Block strings
- 'multiline-string': [
- {
- pattern: /'''[\s\S]*?'''/,
- greedy: true,
- alias: 'string'
- },
- {
- pattern: /"""[\s\S]*?"""/,
- greedy: true,
- alias: 'string',
+ Prism.languages.insertBefore('coffeescript', 'string', {
+ 'inline-javascript': {
+ pattern: /`(?:\\[\s\S]|[^\\`])*`/,
inside: {
- interpolation: interpolation
+ 'delimiter': {
+ pattern: /^`|`$/,
+ alias: 'punctuation'
+ },
+ 'script': {
+ pattern: /[\s\S]+/,
+ alias: 'language-javascript',
+ inside: Prism.languages.javascript
+ }
}
- }
- ]
+ },
-});
+ // Block strings
+ 'multiline-string': [
+ {
+ pattern: /'''[\s\S]*?'''/,
+ greedy: true,
+ alias: 'string'
+ },
+ {
+ pattern: /"""[\s\S]*?"""/,
+ greedy: true,
+ alias: 'string',
+ inside: {
+ interpolation: interpolation
+ }
+ }
+ ]
-Prism.languages.insertBefore('coffeescript', 'keyword', {
- // Object property
- 'property': /(?!\d)\w+(?=\s*:(?!:))/
-});
+ });
+
+ Prism.languages.insertBefore('coffeescript', 'keyword', {
+ // Object property
+ 'property': /(?!\d)\w+(?=\s*:(?!:))/
+ });
-delete Prism.languages.coffeescript['template-string'];
+ delete Prism.languages.coffeescript['template-string'];
-Prism.languages.coffee = Prism.languages.coffeescript;
+ Prism.languages.coffee = Prism.languages.coffeescript;
}(Prism));
/**
@@ -2025,22 +2130,25 @@ Prism.languages.coffee = Prism.languages.coffeescript;
'regex': [
{
pattern: RegExp(/%r/.source + '(?:' + [
- /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[gim]{0,3}/.source,
- /\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/.source,
+ /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
+ /\((?:[^()\\]|\\[\s\S])*\)/.source,
// Here we need to specifically allow interpolation
- /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/.source,
- /\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/.source,
- /<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/.source
- ].join('|') + ')'),
+ /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,
+ /\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,
+ /<(?:[^<>\\]|\\[\s\S])*>/.source
+ ].join('|') + ')' + /[egimnosux]{0,6}/.source),
greedy: true,
inside: {
'interpolation': interpolation
}
},
{
- pattern:
/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[gim]{0,3}(?=\s*(?:$|[\r\n,.;})]))/,
+ pattern:
/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,
lookbehind: true,
- greedy: true
+ greedy: true,
+ inside: {
+ 'interpolation': interpolation
+ }
}
],
'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,
@@ -2084,13 +2192,42 @@ Prism.languages.coffee = Prism.languages.coffeescript;
inside: {
'interpolation': interpolation
}
+ },
+ {
+ pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
+ alias: 'heredoc-string',
+ greedy: true,
+ inside: {
+ 'delimiter': {
+ pattern: /^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i,
+ alias: 'symbol',
+ inside: {
+ 'punctuation': /^<<[-~]?/
+ }
+ },
+ 'interpolation': interpolation
+ }
+ },
+ {
+ pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
+ alias: 'heredoc-string',
+ greedy: true,
+ inside: {
+ 'delimiter': {
+ pattern: /^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i,
+ alias: 'symbol',
+ inside: {
+ 'punctuation': /^<<[-~]?'|'$/,
+ }
+ }
+ }
}
];
Prism.languages.rb = Prism.languages.ruby;
}(Prism));
-(function(Prism) {
+(function (Prism) {
Prism.languages.crystal = Prism.languages.extend('ruby', {
keyword: [
/\b(?:abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|rescue|return|require|select|self|sizeof|struct|super|then|type|typeof|uninitialized|union|unless|until|when|while|with|yield|__DIR__|__END_LINE__|__FILE__|__LINE__)\b/,
@@ -2117,26 +2254,26 @@ Prism.languages.coffee = Prism.languages.coffeescript;
},
expansion: [
- {
- pattern: /\{\{.+?\}\}/,
- inside: {
- delimiter: {
- pattern: /^\{\{|\}\}$/,
- alias: 'tag'
- },
- rest: Prism.languages.crystal
- }
- },
- {
- pattern: /\{%.+?%\}/,
- inside: {
- delimiter: {
- pattern: /^\{%|%\}$/,
- alias: 'tag'
- },
- rest: Prism.languages.crystal
+ {
+ pattern: /\{\{.+?\}\}/,
+ inside: {
+ delimiter: {
+ pattern: /^\{\{|\}\}$/,
+ alias: 'tag'
+ },
+ rest: Prism.languages.crystal
+ }
+ },
+ {
+ pattern: /\{%.+?%\}/,
+ inside: {
+ delimiter: {
+ pattern: /^\{%|%\}$/,
+ alias: 'tag'
+ },
+ rest: Prism.languages.crystal
+ }
}
- }
]
});
@@ -2223,30 +2360,73 @@ Prism.languages.insertBefore('d', 'function', {
}
});
-Prism.languages.dart = Prism.languages.extend('clike', {
- 'string': [
- {
- pattern: /r?("""|''')[\s\S]*?\1/,
- greedy: true
- },
- {
- pattern: /r?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
- greedy: true
- }
- ],
- 'keyword': [
+(function (Prism) {
+ var keywords = [
/\b(?:async|sync|yield)\*/,
-
/\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extension|external|extends|factory|final|finally|for|Function|get|hide|if|implements|interface|import|in|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/
- ],
- 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
-});
+
/\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extension|external|extends|factory|final|finally|for|get|hide|if|implements|interface|import|in|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/
+ ];
-Prism.languages.insertBefore('dart','function',{
- 'metadata': {
- pattern: /@\w+/,
- alias: 'symbol'
- }
-});
+ // Handles named imports, such as http.Client
+ var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
+
+ // based on the dart naming conventions
+ var className = {
+ pattern: RegExp(packagePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),
+ lookbehind: true,
+ inside: {
+ 'namespace': {
+ pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
+ inside: {
+ 'punctuation': /\./
+ }
+ },
+ }
+ };
+
+ Prism.languages.dart = Prism.languages.extend('clike', {
+ 'string': [
+ {
+ pattern: /r?("""|''')[\s\S]*?\1/,
+ greedy: true
+ },
+ {
+ pattern: /r?(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
+ greedy: true
+ }
+ ],
+ 'class-name': [
+ className,
+ {
+ // variables and parameters
+ // this to support class names (or generic parameters) which do not contain a
lower case letter (also works for methods)
+ pattern: RegExp(packagePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),
+ lookbehind: true,
+ inside: className.inside
+ }
+ ],
+ 'keyword': keywords,
+ 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
+ });
+
+ Prism.languages.insertBefore('dart', 'function', {
+ 'metadata': {
+ pattern: /@\w+/,
+ alias: 'symbol'
+ }
+ });
+
+ Prism.languages.insertBefore('dart', 'class-name', {
+ 'generics': {
+ pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
+ inside: {
+ 'class-name': className,
+ 'keyword': keywords,
+ 'punctuation': /[<>(),.:]/,
+ 'operator': /[?&|]/
+ }
+ },
+ });
+}(Prism));
(function (Prism) {
@@ -2285,8 +2465,8 @@ Prism.languages.insertBefore('dart','function',{
if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"
alias.push(/\w+/.exec(name)[0]);
}
- if (name === "diff") {
- alias.push("bold");
+ if (name === 'diff') {
+ alias.push('bold');
}
Prism.languages.diff[name] = {
@@ -2354,8 +2534,9 @@ Prism.languages.insertBefore('dart','function',{
var placeholder;
// Check for existing strings
- while (env.code.indexOf(placeholder = getPlaceholder(language, i))
!== -1)
+ while (env.code.indexOf(placeholder = getPlaceholder(language, i))
!== -1) {
++i;
+ }
// Create a sparse array
tokenStack[i] = match;
@@ -2496,10 +2677,20 @@ Prism.languages.insertBefore('dart','function',{
markupTemplating.tokenizePlaceholders(env, 'jinja2');
});
-})(Prism);
+}(Prism));
Prism.languages.elixir = {
- 'comment': /#.*/m,
+ 'doc': {
+ pattern:
/@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,
+ inside: {
+ 'attribute': /^@\w+/,
+ 'string': /['"][\s\S]+/
+ }
+ },
+ 'comment': {
+ pattern: /#.*/m,
+ greedy: true
+ },
// ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo),
~r[foo], ~r{foo}, ~r<foo>
'regex': {
pattern:
/~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,
@@ -2536,14 +2727,12 @@ Prism.languages.elixir = {
lookbehind: true,
alias: 'symbol'
},
+ 'module': {
+ pattern: /\b[A-Z]\w*\b/,
+ alias: 'class-name'
+ },
// Look-ahead prevents bad highlighting of the :: operator
'attr-name': /\w+\??:(?!:)/,
- 'capture': {
- // Look-behind prevents bad highlighting of the && operator
- pattern: /(^|[^&])&(?:[^&\s\d()][^\s()]*|(?=\())/,
- lookbehind: true,
- alias: 'function'
- },
'argument': {
// Look-behind prevents bad highlighting of the && operator
pattern: /(^|[^&])&\d+/,
@@ -2554,8 +2743,9 @@ Prism.languages.elixir = {
pattern: /@\w+/,
alias: 'variable'
},
+ 'function': /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d+))/,
'number': /\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,
- 'keyword':
/\b(?:after|alias|and|case|catch|cond|def(?:callback|exception|impl|module|p|protocol|struct|delegate)?|do|else|end|fn|for|if|import|not|or|require|rescue|try|unless|use|when)\b/,
+ 'keyword':
/\b(?:after|alias|and|case|catch|cond|def(?:callback|exception|impl|module|p|protocol|struct|delegate)?|do|else|end|fn|for|if|import|not|or|raise|require|rescue|try|unless|use|when)\b/,
'boolean': /\b(?:true|false|nil)\b/,
'operator': [
/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,
@@ -2573,19 +2763,7 @@ Prism.languages.elixir = {
'punctuation': /<<|>>|[.,%\[\]{}()]/
};
-Prism.languages.insertBefore('elixir', 'keyword', {
- 'module': {
- pattern: /\b(defmodule\s)[A-Z][\w.\\]+/,
- lookbehind: true,
- alias: 'class-name'
- },
- 'function': {
- pattern: /\b(defp?\s)[\w.\\]+/,
- lookbehind: true
- }
-});
-
-Prism.languages.elixir.string.forEach(function(o) {
+Prism.languages.elixir.string.forEach(function (o) {
o.inside = {
'interpolation': {
pattern: /#\{[^}]+\}/,
@@ -2701,7 +2879,7 @@ Prism.languages.insertBefore('groovy', 'function', {
});
// Handle string interpolation
-Prism.hooks.add('wrap', function(env) {
+Prism.hooks.add('wrap', function (env) {
if (env.language === 'groovy' && env.type === 'string') {
var delimiter = env.content[0];
@@ -2791,7 +2969,7 @@ Prism.hooks.add('wrap', function(env) {
alias: 'punctuation'
},
'generics': {
- pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
+ pattern:
/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,
inside: {
'class-name': className,
'keyword': keywords,
@@ -2893,7 +3071,7 @@ Prism.languages.julia = {
'operator':
/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/
});
- delete Prism.languages.kotlin["class-name"];
+ delete Prism.languages.kotlin['class-name'];
Prism.languages.insertBefore('kotlin', 'string', {
'raw-string': {
@@ -2940,6 +3118,71 @@ Prism.languages.julia = {
Prism.languages.kts = Prism.languages.kotlin;
}(Prism));
+(function (Prism) {
+ var funcPattern = /\\(?:[^a-z()[\]]|[a-z*]+)/i;
+ var insideEqu = {
+ 'equation-command': {
+ pattern: funcPattern,
+ alias: 'regex'
+ }
+ };
+
+ Prism.languages.latex = {
+ 'comment': /%.*/m,
+ // the verbatim environment prints whitespace to the document
+ 'cdata': {
+ pattern: /(\\begin\{((?:verbatim|lstlisting)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
+ lookbehind: true
+ },
+ /*
+ * equations can be between $$ $$ or $ $ or \( \) or \[ \]
+ * (all are multiline)
+ */
+ 'equation': [
+ {
+ pattern:
/\$\$(?:\\[\s\S]|[^\\$])+\$\$|\$(?:\\[\s\S]|[^\\$])+\$|\\\([\s\S]*?\\\)|\\\[[\s\S]*?\\\]/,
+ inside: insideEqu,
+ alias: 'string'
+ },
+ {
+ pattern:
/(\\begin\{((?:equation|math|eqnarray|align|multline|gather)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
+ lookbehind: true,
+ inside: insideEqu,
+ alias: 'string'
+ }
+ ],
+ /*
+ * arguments which are keywords or references are highlighted
+ * as keywords
+ */
+ 'keyword': {
+ pattern:
/(\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
+ lookbehind: true
+ },
+ 'url': {
+ pattern: /(\\url\{)[^}]+(?=\})/,
+ lookbehind: true
+ },
+ /*
+ * section or chapter headlines are highlighted as bold so that
+ * they stand out more
+ */
+ 'headline': {
+ pattern:
/(\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\}(?:\[[^\]]+\])?)/,
+ lookbehind: true,
+ alias: 'class-name'
+ },
+ 'function': {
+ pattern: funcPattern,
+ alias: 'selector'
+ },
+ 'punctuation': /[[\]{}&]/
+ };
+
+ Prism.languages.tex = Prism.languages.latex;
+ Prism.languages.context = Prism.languages.latex;
+}(Prism));
+
Prism.languages.lua = {
'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,
// \z may be used to skip the following space
@@ -2978,17 +3221,58 @@ Prism.languages.matlab = {
'punctuation': /\.{3}|[.,;\[\](){}!]/
};
-Prism.languages.nginx = Prism.languages.extend('clike', {
- 'comment': {
- pattern: /(^|[^"{\\])#.*/,
- lookbehind: true
- },
- 'keyword':
/\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|events|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_si
ze|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transpa
rency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|p
erl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|pr
oxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stub_status|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timeout|timer_resolution|try_files
|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|use|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_rlimit_sigpending|working_directory|xclient|xml_entities|xslt_entities|xslt_stylesheet|xslt_types|ssl_session_tickets|ssl_stapling|ssl_stapling_verify|ssl_ecdh_curve|ssl_trusted_certificate|more_set_headers|ssl_early_data)\b/i
-});
+(function (Prism) {
-Prism.languages.insertBefore('nginx', 'keyword', {
- 'variable': /\$[a-z_]+/i
-});
+ var variable = /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;
+
+ Prism.languages.nginx = {
+ 'comment': {
+ pattern: /(^|[\s{};])#.*/,
+ lookbehind: true
+ },
+ 'directive': {
+ pattern:
/(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,
+ lookbehind: true,
+ greedy: true,
+ inside: {
+ 'string': {
+ pattern:
/((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,
+ lookbehind: true,
+ inside: {
+ 'escape': {
+ pattern: /\\["'\\nrt]/,
+ alias: 'entity'
+ },
+ 'variable': variable
+ }
+ },
+ 'comment': {
+ pattern: /(\s)#.*/,
+ lookbehind: true,
+ greedy: true
+ },
+ 'keyword': {
+ pattern: /^\S+/,
+ greedy: true
+ },
+
+ // other patterns
+
+ 'boolean': {
+ pattern: /(\s)(?:off|on)(?!\S)/,
+ lookbehind: true
+ },
+ 'number': {
+ pattern: /(\s)\d+[a-z]*(?!\S)/i,
+ lookbehind: true
+ },
+ 'variable': variable
+ }
+ },
+ 'punctuation': /[{};]/
+ };
+
+}(Prism));
Prism.languages.nim = {
'comment': /#.*/,
@@ -3023,6 +3307,7 @@ Prism.languages.nim = {
},
'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/
};
+
Prism.languages.ocaml = {
'comment': /\(\*[\s\S]*?\*\)/,
'string': [
@@ -3228,7 +3513,7 @@ Prism.languages.perl = {
// ${...}
/[&*$@%]#?(?=\{)/,
// $foo
- /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i,
+ /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/i,
// $1
/[&*$@%]\d+/,
// $_, @_, %!
@@ -3271,8 +3556,18 @@ Prism.languages.perl = {
pattern: /\b(?:false|true)\b/i,
alias: 'boolean'
},
- /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
+ {
+ pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,
+ greedy: true,
+ lookbehind: true,
+ },
+ {
+ pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,
+ greedy: true,
+ lookbehind: true,
+ },
/\b(?:null)\b/i,
+ /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
];
var number =
/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i;
var operator =
/<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
@@ -3297,6 +3592,11 @@ Prism.languages.perl = {
lookbehind: true,
alias: 'class-name'
},
+ 'function-definition': {
+ pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
+ lookbehind: true,
+ alias: 'function'
+ },
'keyword': [
{
pattern:
/(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,
@@ -3344,9 +3644,26 @@ Prism.languages.perl = {
alias: 'static-context',
greedy: true
},
-
/\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i
+ {
+ // yield from
+ pattern: /(\byield\s+)from\b/i,
+ lookbehind: true
+ },
+ // `class` is always a keyword unlike other keywords
+ /\bclass\b/i,
+ {
+ // https://www.php.net/manual/en/reserved.keywords.php
+ //
+ // keywords cannot be preceded by "->"
+ // the complex lookbehind means `(?<!(?:->|::)\s*)`
+ pattern:
/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,
+ lookbehind: true
+ }
],
- 'argument-name': /\b[a-z_]\w*(?=\s*:(?!:))/i,
+ 'argument-name': {
+ pattern: /([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,
+ lookbehind: true
+ },
'class-name': [
{
pattern:
/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,
@@ -3446,9 +3763,15 @@ Prism.languages.perl = {
}
],
'constant': constant,
- 'function': /\w+\s*(?=\()/,
+ 'function': {
+ pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
+ lookbehind: true,
+ inside: {
+ 'punctuation': /\\/
+ }
+ },
'property': {
- pattern: /(->)[\w]+/,
+ pattern: /(->\s*)\w+/,
lookbehind: true
},
'number': number,
@@ -3457,7 +3780,7 @@ Prism.languages.perl = {
};
var string_interpolation = {
- pattern:
/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)*)/,
+ pattern:
/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
lookbehind: true,
inside: Prism.languages.php
};
@@ -3489,7 +3812,7 @@ Prism.languages.perl = {
'punctuation': /^<<<"?|[";]$/
}
},
- 'interpolation': string_interpolation // See below
+ 'interpolation': string_interpolation
}
},
{
@@ -3507,16 +3830,13 @@ Prism.languages.perl = {
alias: 'double-quoted-string',
greedy: true,
inside: {
- 'interpolation': string_interpolation // See below
+ 'interpolation': string_interpolation
}
}
];
Prism.languages.insertBefore('php', 'variable', {
'string': string,
- });
-
- Prism.languages.insertBefore('php', 'variable', {
'attribute': {
pattern:
/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/mi,
greedy: true,
@@ -3562,7 +3882,7 @@ Prism.languages.perl = {
},
});
- Prism.hooks.add('before-tokenize', function(env) {
+ Prism.hooks.add('before-tokenize', function (env) {
if (!/<\?/.test(env.code)) {
return;
}
@@ -3571,7 +3891,7 @@ Prism.languages.perl = {
Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
});
- Prism.hooks.add('after-tokenize', function(env) {
+ Prism.hooks.add('after-tokenize', function (env) {
Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
});
@@ -3642,149 +3962,149 @@ Prism.languages.python['string-interpolation'].inside['interpolation'].inside.re
Prism.languages.py = Prism.languages.python;
-(function(Prism) {
+(function (Prism) {
-var javascript = Prism.util.clone(Prism.languages.javascript);
+ var javascript = Prism.util.clone(Prism.languages.javascript);
-var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
-var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
-var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
+ var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
+ var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
+ var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
-/**
- * @param {string} source
- * @param {string} [flags]
- */
-function re(source, flags) {
- source = source
- .replace(/<S>/g, function () { return space; })
- .replace(/<BRACES>/g, function () { return braces; })
- .replace(/<SPREAD>/g, function () { return spread; });
- return RegExp(source, flags);
-}
+ /**
+ * @param {string} source
+ * @param {string} [flags]
+ */
+ function re(source, flags) {
+ source = source
+ .replace(/<S>/g, function () { return space; })
+ .replace(/<BRACES>/g, function () { return braces; })
+ .replace(/<SPREAD>/g, function () { return spread; });
+ return RegExp(source, flags);
+ }
-spread = re(spread).source;
+ spread = re(spread).source;
-Prism.languages.jsx = Prism.languages.extend('markup', javascript);
-Prism.languages.jsx.tag.pattern = re(
-
/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
-);
+ Prism.languages.jsx = Prism.languages.extend('markup', javascript);
+ Prism.languages.jsx.tag.pattern = re(
+
/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
+ );
-Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
-Prism.languages.jsx.tag.inside['attr-value'].pattern =
/=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
-Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
-Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
+ Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
+ Prism.languages.jsx.tag.inside['attr-value'].pattern =
/=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
+ Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
+ Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
-Prism.languages.insertBefore('inside', 'attr-name', {
- 'spread': {
- pattern: re(/<SPREAD>/.source),
- inside: Prism.languages.jsx
- }
-}, Prism.languages.jsx.tag);
+ Prism.languages.insertBefore('inside', 'attr-name', {
+ 'spread': {
+ pattern: re(/<SPREAD>/.source),
+ inside: Prism.languages.jsx
+ }
+ }, Prism.languages.jsx.tag);
-Prism.languages.insertBefore('inside', 'attr-value',{
- 'script': {
- // Allow for two levels of nesting
- pattern: re(/=<BRACES>/.source),
- inside: {
- 'script-punctuation': {
- pattern: /^=(?={)/,
- alias: 'punctuation'
+ Prism.languages.insertBefore('inside', 'special-attr', {
+ 'script': {
+ // Allow for two levels of nesting
+ pattern: re(/=<BRACES>/.source),
+ inside: {
+ 'script-punctuation': {
+ pattern: /^=(?={)/,
+ alias: 'punctuation'
+ },
+ rest: Prism.languages.jsx
},
- rest: Prism.languages.jsx
- },
- 'alias': 'language-javascript'
- }
-}, Prism.languages.jsx.tag);
+ 'alias': 'language-javascript'
+ }
+ }, Prism.languages.jsx.tag);
-// The following will handle plain text inside tags
-var stringifyToken = function (token) {
- if (!token) {
- return '';
- }
- if (typeof token === 'string') {
- return token;
- }
- if (typeof token.content === 'string') {
- return token.content;
- }
- return token.content.map(stringifyToken).join('');
-};
+ // The following will handle plain text inside tags
+ var stringifyToken = function (token) {
+ if (!token) {
+ return '';
+ }
+ if (typeof token === 'string') {
+ return token;
+ }
+ if (typeof token.content === 'string') {
+ return token.content;
+ }
+ return token.content.map(stringifyToken).join('');
+ };
-var walkTokens = function (tokens) {
- var openedTags = [];
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- var notTagNorBrace = false;
-
- if (typeof token !== 'string') {
- if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
- // We found a tag, now find its kind
-
- if (token.content[0].content[0].content === '</') {
- // Closing tag
- if (openedTags.length > 0 && openedTags[openedTags.length -
1].tagName === stringifyToken(token.content[0].content[1])) {
- // Pop matching opening tag
- openedTags.pop();
- }
- } else {
- if (token.content[token.content.length - 1].content === '/>') {
- // Autoclosed tag, ignore
+ var walkTokens = function (tokens) {
+ var openedTags = [];
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+ var notTagNorBrace = false;
+
+ if (typeof token !== 'string') {
+ if (token.type === 'tag' && token.content[0] && token.content[0].type ===
'tag') {
+ // We found a tag, now find its kind
+
+ if (token.content[0].content[0].content === '</') {
+ // Closing tag
+ if (openedTags.length > 0 && openedTags[openedTags.length -
1].tagName === stringifyToken(token.content[0].content[1])) {
+ // Pop matching opening tag
+ openedTags.pop();
+ }
} else {
- // Opening tag
- openedTags.push({
- tagName: stringifyToken(token.content[0].content[1]),
- openedBraces: 0
- });
+ if (token.content[token.content.length - 1].content === '/>')
{
+ // Autoclosed tag, ignore
+ } else {
+ // Opening tag
+ openedTags.push({
+ tagName:
stringifyToken(token.content[0].content[1]),
+ openedBraces: 0
+ });
+ }
}
- }
- } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content ===
'{') {
+ } else if (openedTags.length > 0 && token.type === 'punctuation' &&
token.content === '{') {
- // Here we might have entered a JSX context inside a tag
- openedTags[openedTags.length - 1].openedBraces++;
+ // Here we might have entered a JSX context inside a tag
+ openedTags[openedTags.length - 1].openedBraces++;
- } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces >
0 && token.type === 'punctuation' && token.content === '}') {
+ } else if (openedTags.length > 0 && openedTags[openedTags.length -
1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
- // Here we might have left a JSX context inside a tag
- openedTags[openedTags.length - 1].openedBraces--;
+ // Here we might have left a JSX context inside a tag
+ openedTags[openedTags.length - 1].openedBraces--;
- } else {
- notTagNorBrace = true
- }
- }
- if (notTagNorBrace || typeof token === 'string') {
- if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
- // Here we are inside a tag, and not inside a JSX context.
- // That's plain text: drop any tokens matched.
- var plainText = stringifyToken(token);
-
- // And merge text with adjacent text
- if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i +
1].type === 'plain-text')) {
- plainText += stringifyToken(tokens[i + 1]);
- tokens.splice(i + 1, 1);
+ } else {
+ notTagNorBrace = true;
}
- if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type ===
'plain-text')) {
- plainText = stringifyToken(tokens[i - 1]) + plainText;
- tokens.splice(i - 1, 1);
- i--;
+ }
+ if (notTagNorBrace || typeof token === 'string') {
+ if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces
=== 0) {
+ // Here we are inside a tag, and not inside a JSX context.
+ // That's plain text: drop any tokens matched.
+ var plainText = stringifyToken(token);
+
+ // And merge text with adjacent text
+ if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' ||
tokens[i + 1].type === 'plain-text')) {
+ plainText += stringifyToken(tokens[i + 1]);
+ tokens.splice(i + 1, 1);
+ }
+ if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type
=== 'plain-text')) {
+ plainText = stringifyToken(tokens[i - 1]) + plainText;
+ tokens.splice(i - 1, 1);
+ i--;
+ }
+
+ tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
}
+ }
- tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
+ if (token.content && typeof token.content !== 'string') {
+ walkTokens(token.content);
}
}
+ };
- if (token.content && typeof token.content !== 'string') {
- walkTokens(token.content);
+ Prism.hooks.add('after-tokenize', function (env) {
+ if (env.language !== 'jsx' && env.language !== 'tsx') {
+ return;
}
- }
-};
-
-Prism.hooks.add('after-tokenize', function (env) {
- if (env.language !== 'jsx' && env.language !== 'tsx') {
- return;
- }
- walkTokens(env.tokens);
-});
+ walkTokens(env.tokens);
+ });
}(Prism));
@@ -4007,17 +4327,26 @@ Prism.languages.scss['atrule'].inside.rest = Prism.languages.scss;
var strings = [
// normal string
- // 1 capturing group
- /(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\1)[^\\`$])*\1/.source,
+ /"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,
+ /'[^']*'/.source,
+ /\$'(?:[^'\\]|\\[\s\S])*'/.source,
// here doc
// 2 capturing groups
- /<<-?\s*(["']?)(\w+)\2\s[\s\S]*?[\r\n]\3/.source
+ /<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source
].join('|');
Prism.languages['shell-session'] = {
'command': {
- pattern:
RegExp(/^(?:[^\s@:$#*!/\\]+@[^\s@:$#*!/\\]+(?::[^\0-\x1F$#*?"<>:;|]+)?|[^\0-\x1F$#*?"<>:;|]+)?[$#](?:[^\\\r\n'"<]|\\.|<<str>>)+/.source.replace(/<<str>>/g,
function () { return strings; }), 'm'),
+ pattern: RegExp(
+ // user info
+
/^(?:[^\s@:$#*!/\\]+@[^\s@:$#*!/\\]+(?::[^\0-\x1F$#*?"<>:;|]+)?|[^\0-\x1F$#*?"<>:;|]+)?/.source +
+ // shell symbol
+ /[$#]/.source +
+ // bash command
+
/(?:[^\\\r\n'"<$]|\\(?:[^\r]|\r\n?)|\$(?!')|<<str>>)+/.source.replace(/<<str>>/g, function () { return
strings; }),
+ 'm'
+ ),
greedy: true,
inside: {
'info': {
@@ -4085,11 +4414,16 @@ Prism.languages.sql = {
greedy: true,
inside: null // see below
},
- // From JavaScript Prism keyword list and TypeScript language spec:
https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words
- 'keyword':
/\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,
'builtin':
/\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,
});
+ // The keywords TypeScript adds to JavaScript
+ Prism.languages.typescript.keyword.push(
+ /\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\b/,
+ // keywords that have to be followed by an identifier
+ /\b(?:asserts|infer|interface|module|namespace|type)(?!\s*[^\s_${}*a-zA-Z\xA0-\uFFFF])/
+ );
+
// doesn't work with TS because TS is too complex
delete Prism.languages.typescript['parameter'];
@@ -4100,6 +4434,16 @@ Prism.languages.sql = {
Prism.languages.typescript['class-name'].inside = typeInside;
Prism.languages.insertBefore('typescript', 'function', {
+ 'decorator': {
+ pattern: /@[$\w\xA0-\uFFFF]+/,
+ inside: {
+ 'at': {
+ pattern: /^@/,
+ alias: 'operator'
+ },
+ 'function': /^[\s\S]+/
+ }
+ },
'generic-function': {
// e.g. foo<T extends "bar" | "baz">( ...
pattern:
/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
@@ -4146,7 +4490,7 @@ Prism.languages.sql = {
flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag
var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[
\t]*(?:$|,|]|}|(?:[\r\n]\s*)?#))/.source
.replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g,
function () { return value; });
- return RegExp(pattern, flags)
+ return RegExp(pattern, flags);
}
Prism.languages.yaml = {
@@ -4202,4 +4546,3 @@ Prism.languages.sql = {
Prism.languages.yml = Prism.languages.yaml;
}(Prism));
-
diff --git a/lib/docs/filters/latex/clean_html.rb b/lib/docs/filters/latex/clean_html.rb
index cc327b04..5902679f 100644
--- a/lib/docs/filters/latex/clean_html.rb
+++ b/lib/docs/filters/latex/clean_html.rb
@@ -13,6 +13,11 @@ module Docs
css('h1, h2, h3, h4').each { |node| node.content = node.content.sub /^[0-9A-Z]+(\.[0-9]+)* /, '' }
+ css('pre').each do |node|
+ node.delete 'class'
+ node['data-language'] = 'latex'
+ end
+
doc
end
end
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]