History

LaTeX: syntax highlighting

Simon Legner committed 5 years ago

Commit f1398021 parent 776ec5a2 files · +1647 −1299Browse files

Unified · Split

2 files
  1. assets/javascripts/vendor/prism.js +1642 −1299
  2. lib/docs/filters/latex/clean_html.rb +5 −0
assets/javascripts/vendor/prism.js+1642−1299
@@ -1,13 +1,13 @@
11 /* PrismJS 1.23.0
2−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 */
2+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 */
33 /// <reference lib="WebWorker"/>
44
55 var _self = (typeof window !== 'undefined')
66 ? window // if in browser
77 : (
88 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
9− ? self // if in worker
10− : {} // if in node js
9+ ? self // if in worker
10+ : {} // if in node js
1111 );
1212
1313 /**
@@ -18,1133 +18,1151 @@ var _self = (typeof window !== 'undefined') · 4 unmodified lines
1818 * @namespace
1919 * @public
2020 */
21−var Prism = (function (_self){
21+var Prism = (function (_self) {
2222
23−// Private helper vars
24−var lang = /\blang(?:uage)?-([\w-]+)\b/i;
25−var uniqueId = 0;
23+ // Private helper vars
24+ var lang = /\blang(?:uage)?-([\w-]+)\b/i;
25+ var uniqueId = 0;
2626
27+ // The grammar object for plaintext
28+ var plainTextGrammar = {};
2729
28−var _ = {
29− /**
30− * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
31− * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
32− * additional languages or plugins yourself.
33− *
34− * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
35− *
36− * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
37− * empty Prism object into the global scope before loading the Prism script like this:
38− *
39− * ```js
40− * window.Prism = window.Prism || {};
41− * Prism.manual = true;
42− * // add a new <script> to load Prism's script
43− * ```
44− *
45− * @default false
46− * @type {boolean}
47− * @memberof Prism
48− * @public
49− */
50− manual: _self.Prism && _self.Prism.manual,
51− disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
52−
53− /**
54− * A namespace for utility methods.
55− *
56− * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
57− * change or disappear at any time.
58− *
59− * @namespace
60− * @memberof Prism
61− */
62− util: {
63− encode: function encode(tokens) {
64− if (tokens instanceof Token) {
65− return new Token(tokens.type, encode(tokens.content), tokens.alias);
66− } else if (Array.isArray(tokens)) {
67− return tokens.map(encode);
68− } else {
69− return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
70− }
71− },
7230
31+ var _ = {
7332 /**
74− * Returns the name of the type of the given value.
33+ * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
34+ * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
35+ * additional languages or plugins yourself.
7536 *
76− * @param {any} o
77− * @returns {string}
78− * @example
79− * type(null) === 'Null'
80− * type(undefined) === 'Undefined'
81− * type(123) === 'Number'
82− * type('foo') === 'String'
83− * type(true) === 'Boolean'
84− * type([1, 2]) === 'Array'
85− * type({}) === 'Object'
86− * type(String) === 'Function'
87− * type(/abc+/) === 'RegExp'
88− */
89− type: function (o) {
90− return Object.prototype.toString.call(o).slice(8, -1);
91− },
92−
93− /**
94− * Returns a unique number for the given object. Later calls will still return the same number.
37+ * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
38+ *
39+ * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
40+ * empty Prism object into the global scope before loading the Prism script like this:
9541 *
96− * @param {Object} obj
97− * @returns {number}
42+ * ```js
43+ * window.Prism = window.Prism || {};
44+ * Prism.manual = true;
45+ * // add a new <script> to load Prism's script
46+ * ```
47+ *
48+ * @default false
49+ * @type {boolean}
50+ * @memberof Prism
51+ * @public
9852 */
99− objId: function (obj) {
100− if (!obj['__id']) {
101− Object.defineProperty(obj, '__id', { value: ++uniqueId });
102− }
103− return obj['__id'];
104− },
53+ manual: _self.Prism && _self.Prism.manual,
54+ disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
10555
10656 /**
107− * Creates a deep clone of the given object.
57+ * A namespace for utility methods.
10858 *
109− * The main intended use of this function is to clone language definitions.
59+ * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
60+ * change or disappear at any time.
11061 *
111− * @param {T} o
112− * @param {Record<number, any>} [visited]
113− * @returns {T}
114− * @template T
62+ * @namespace
63+ * @memberof Prism
11564 */
116− clone: function deepClone(o, visited) {
117− visited = visited || {};
118−
119− var clone, id;
120− switch (_.util.type(o)) {
121− case 'Object':
122− id = _.util.objId(o);
123− if (visited[id]) {
124− return visited[id];
125− }
126− clone = /** @type {Record<string, any>} */ ({});
127− visited[id] = clone;
65+ util: {
66+ encode: function encode(tokens) {
67+ if (tokens instanceof Token) {
68+ return new Token(tokens.type, encode(tokens.content), tokens.alias);
69+ } else if (Array.isArray(tokens)) {
70+ return tokens.map(encode);
71+ } else {
72+ return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
73+ }
74+ },
75+
76+ /**
77+ * Returns the name of the type of the given value.
78+ *
79+ * @param {any} o
80+ * @returns {string}
81+ * @example
82+ * type(null) === 'Null'
83+ * type(undefined) === 'Undefined'
84+ * type(123) === 'Number'
85+ * type('foo') === 'String'
86+ * type(true) === 'Boolean'
87+ * type([1, 2]) === 'Array'
88+ * type({}) === 'Object'
89+ * type(String) === 'Function'
90+ * type(/abc+/) === 'RegExp'
91+ */
92+ type: function (o) {
93+ return Object.prototype.toString.call(o).slice(8, -1);
94+ },
95+
96+ /**
97+ * Returns a unique number for the given object. Later calls will still return the same number.
98+ *
99+ * @param {Object} obj
100+ * @returns {number}
101+ */
102+ objId: function (obj) {
103+ if (!obj['__id']) {
104+ Object.defineProperty(obj, '__id', { value: ++uniqueId });
105+ }
106+ return obj['__id'];
107+ },
128108
129− for (var key in o) {
130− if (o.hasOwnProperty(key)) {
131− clone[key] = deepClone(o[key], visited);
109+ /**
110+ * Creates a deep clone of the given object.
111+ *
112+ * The main intended use of this function is to clone language definitions.
113+ *
114+ * @param {T} o
115+ * @param {Record<number, any>} [visited]
116+ * @returns {T}
117+ * @template T
118+ */
119+ clone: function deepClone(o, visited) {
120+ visited = visited || {};
121+
122+ var clone; var id;
123+ switch (_.util.type(o)) {
124+ case 'Object':
125+ id = _.util.objId(o);
126+ if (visited[id]) {
127+ return visited[id];
132128 }
133− }
129+ clone = /** @type {Record<string, any>} */ ({});
130+ visited[id] = clone;
134131
135− return /** @type {any} */ (clone);
132+ for (var key in o) {
133+ if (o.hasOwnProperty(key)) {
134+ clone[key] = deepClone(o[key], visited);
135+ }
136+ }
136137
137− case 'Array':
138− id = _.util.objId(o);
139− if (visited[id]) {
140− return visited[id];
141− }
142− clone = [];
143− visited[id] = clone;
138+ return /** @type {any} */ (clone);
144139
145− (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
146− clone[i] = deepClone(v, visited);
147− });
140+ case 'Array':
141+ id = _.util.objId(o);
142+ if (visited[id]) {
143+ return visited[id];
144+ }
145+ clone = [];
146+ visited[id] = clone;
148147
149− return /** @type {any} */ (clone);
148+ (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
149+ clone[i] = deepClone(v, visited);
150+ });
150151
151− default:
152− return o;
153− }
154− },
152+ return /** @type {any} */ (clone);
155153
156− /**
157− * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
158− *
159− * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
160− *
161− * @param {Element} element
162− * @returns {string}
163− */
164− getLanguage: function (element) {
165− while (element && !lang.test(element.className)) {
166− element = element.parentElement;
167− }
168− if (element) {
169− return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
170− }
171− return 'none';
172− },
154+ default:
155+ return o;
156+ }
157+ },
173158
174− /**
175− * Returns the script element that is currently executing.
176− *
177− * This does __not__ work for line script element.
178− *
179− * @returns {HTMLScriptElement | null}
180− */
181− currentScript: function () {
182− if (typeof document === 'undefined') {
183− return null;
184− }
185− if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
186− return /** @type {any} */ (document.currentScript);
187− }
159+ /**
160+ * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
161+ *
162+ * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
163+ *
164+ * @param {Element} element
165+ * @returns {string}
166+ */
167+ getLanguage: function (element) {
168+ while (element && !lang.test(element.className)) {
169+ element = element.parentElement;
170+ }
171+ if (element) {
172+ return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
173+ }
174+ return 'none';
175+ },
188176
189− // IE11 workaround
190− // we'll get the src of the current script by parsing IE11's error stack trace
191− // this will not work for inline scripts
177+ /**
178+ * Returns the script element that is currently executing.
179+ *
180+ * This does __not__ work for line script element.
181+ *
182+ * @returns {HTMLScriptElement | null}
183+ */
184+ currentScript: function () {
185+ if (typeof document === 'undefined') {
186+ return null;
187+ }
188+ if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
189+ return /** @type {any} */ (document.currentScript);
190+ }
192191
193− try {
194− throw new Error();
195− } catch (err) {
196− // Get file src url from stack. Specifically works with the format of stack traces in IE.
197− // A stack will look like this:
198− //
199− // Error
200− // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
201− // at Global code (http://localhost/components/prism-core.js:606:1)
202−
203− var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
204− if (src) {
205− var scripts = document.getElementsByTagName('script');
206− for (var i in scripts) {
207− if (scripts[i].src == src) {
208− return scripts[i];
192+ // IE11 workaround
193+ // we'll get the src of the current script by parsing IE11's error stack trace
194+ // this will not work for inline scripts
195+
196+ try {
197+ throw new Error();
198+ } catch (err) {
199+ // Get file src url from stack. Specifically works with the format of stack traces in IE.
200+ // A stack will look like this:
201+ //
202+ // Error
203+ // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
204+ // at Global code (http://localhost/components/prism-core.js:606:1)
205+
206+ var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
207+ if (src) {
208+ var scripts = document.getElementsByTagName('script');
209+ for (var i in scripts) {
210+ if (scripts[i].src == src) {
211+ return scripts[i];
212+ }
209213 }
210214 }
215+ return null;
216+ }
217+ },
218+
219+ /**
220+ * Returns whether a given class is active for `element`.
221+ *
222+ * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
223+ * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
224+ * given class is just the given class with a `no-` prefix.
225+ *
226+ * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
227+ * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
228+ * ancestors have the given class or the negated version of it, then the default activation will be returned.
229+ *
230+ * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
231+ * version of it, the class is considered active.
232+ *
233+ * @param {Element} element
234+ * @param {string} className
235+ * @param {boolean} [defaultActivation=false]
236+ * @returns {boolean}
237+ */
238+ isActive: function (element, className, defaultActivation) {
239+ var no = 'no-' + className;
240+
241+ while (element) {
242+ var classList = element.classList;
243+ if (classList.contains(className)) {
244+ return true;
245+ }
246+ if (classList.contains(no)) {
247+ return false;
248+ }
249+ element = element.parentElement;
211250 }
212− return null;
251+ return !!defaultActivation;
213252 }
214253 },
215254
216255 /**
217− * Returns whether a given class is active for `element`.
256+ * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
218257 *
219− * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
220− * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
221− * given class is just the given class with a `no-` prefix.
222− *
223− * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
224− * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
225− * ancestors have the given class or the negated version of it, then the default activation will be returned.
226− *
227− * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
228− * version of it, the class is considered active.
229− *
230− * @param {Element} element
231− * @param {string} className
232− * @param {boolean} [defaultActivation=false]
233− * @returns {boolean}
258+ * @namespace
259+ * @memberof Prism
260+ * @public
234261 */
235− isActive: function (element, className, defaultActivation) {
236− var no = 'no-' + className;
262+ languages: {
263+ /**
264+ * The grammar for plain, unformatted text.
265+ */
266+ plain: plainTextGrammar,
267+ plaintext: plainTextGrammar,
268+ text: plainTextGrammar,
269+ txt: plainTextGrammar,
237270
238− while (element) {
239− var classList = element.classList;
240− if (classList.contains(className)) {
241− return true;
271+ /**
272+ * Creates a deep copy of the language with the given id and appends the given tokens.
273+ *
274+ * If a token in `redef` also appears in the copied language, then the existing token in the copied language
275+ * will be overwritten at its original position.
276+ *
277+ * ## Best practices
278+ *
279+ * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
280+ * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
281+ * understand the language definition because, normally, the order of tokens matters in Prism grammars.
282+ *
283+ * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
284+ * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
285+ *
286+ * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
287+ * @param {Grammar} redef The new tokens to append.
288+ * @returns {Grammar} The new language created.
289+ * @public
290+ * @example
291+ * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
292+ * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
293+ * // at its original position
294+ * 'comment': { ... },
295+ * // CSS doesn't have a 'color' token, so this token will be appended
296+ * 'color': /\b(?:red|green|blue)\b/
297+ * });
298+ */
299+ extend: function (id, redef) {
300+ var lang = _.util.clone(_.languages[id]);
301+
302+ for (var key in redef) {
303+ lang[key] = redef[key];
304+ }
305+
306+ return lang;
307+ },
308+
309+ /**
310+ * Inserts tokens _before_ another token in a language definition or any other grammar.
311+ *
312+ * ## Usage
313+ *
314+ * This helper method makes it easy to modify existing languages. For example, the CSS language definition
315+ * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
316+ * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
317+ * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
318+ * this:
319+ *
320+ * ```js
321+ * Prism.languages.markup.style = {
322+ * // token
323+ * };
324+ * ```
325+ *
326+ * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
327+ * before existing tokens. For the CSS example above, you would use it like this:
328+ *
329+ * ```js
330+ * Prism.languages.insertBefore('markup', 'cdata', {
331+ * 'style': {
332+ * // token
333+ * }
334+ * });
335+ * ```
336+ *
337+ * ## Special cases
338+ *
339+ * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
340+ * will be ignored.
341+ *
342+ * This behavior can be used to insert tokens after `before`:
343+ *
344+ * ```js
345+ * Prism.languages.insertBefore('markup', 'comment', {
346+ * 'comment': Prism.languages.markup.comment,
347+ * // tokens after 'comment'
348+ * });
349+ * ```
350+ *
351+ * ## Limitations
352+ *
353+ * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
354+ * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
355+ * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
356+ * deleting properties which is necessary to insert at arbitrary positions.
357+ *
358+ * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
359+ * Instead, it will create a new object and replace all references to the target object with the new one. This
360+ * can be done without temporarily deleting properties, so the iteration order is well-defined.
361+ *
362+ * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
363+ * you hold the target object in a variable, then the value of the variable will not change.
364+ *
365+ * ```js
366+ * var oldMarkup = Prism.languages.markup;
367+ * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
368+ *
369+ * assert(oldMarkup !== Prism.languages.markup);
370+ * assert(newMarkup === Prism.languages.markup);
371+ * ```
372+ *
373+ * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
374+ * object to be modified.
375+ * @param {string} before The key to insert before.
376+ * @param {Grammar} insert An object containing the key-value pairs to be inserted.
377+ * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
378+ * object to be modified.
379+ *
380+ * Defaults to `Prism.languages`.
381+ * @returns {Grammar} The new grammar object.
382+ * @public
383+ */
384+ insertBefore: function (inside, before, insert, root) {
385+ root = root || /** @type {any} */ (_.languages);
386+ var grammar = root[inside];
387+ /** @type {Grammar} */
388+ var ret = {};
389+
390+ for (var token in grammar) {
391+ if (grammar.hasOwnProperty(token)) {
392+
393+ if (token == before) {
394+ for (var newToken in insert) {
395+ if (insert.hasOwnProperty(newToken)) {
396+ ret[newToken] = insert[newToken];
397+ }
398+ }
399+ }
400+
401+ // Do not insert token which also occur in insert. See #1525
402+ if (!insert.hasOwnProperty(token)) {
403+ ret[token] = grammar[token];
404+ }
405+ }
242406 }
243− if (classList.contains(no)) {
244− return false;
407+
408+ var old = root[inside];
409+ root[inside] = ret;
410+
411+ // Update references in other language definitions
412+ _.languages.DFS(_.languages, function (key, value) {
413+ if (value === old && key != inside) {
414+ this[key] = ret;
415+ }
416+ });
417+
418+ return ret;
419+ },
420+
421+ // Traverse a language definition with Depth First Search
422+ DFS: function DFS(o, callback, type, visited) {
423+ visited = visited || {};
424+
425+ var objId = _.util.objId;
426+
427+ for (var i in o) {
428+ if (o.hasOwnProperty(i)) {
429+ callback.call(o, i, o[i], type || i);
430+
431+ var property = o[i];
432+ var propertyType = _.util.type(property);
433+
434+ if (propertyType === 'Object' && !visited[objId(property)]) {
435+ visited[objId(property)] = true;
436+ DFS(property, callback, null, visited);
437+ } else if (propertyType === 'Array' && !visited[objId(property)]) {
438+ visited[objId(property)] = true;
439+ DFS(property, callback, i, visited);
440+ }
441+ }
245442 }
246− element = element.parentElement;
247443 }
248− return !!defaultActivation;
249− }
250− },
444+ },
445+
446+ plugins: {},
251447
252− /**
253− * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
254− *
255− * @namespace
256− * @memberof Prism
257− * @public
258− */
259− languages: {
260448 /**
261− * Creates a deep copy of the language with the given id and appends the given tokens.
449+ * This is the most high-level function in Prism’s API.
450+ * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
451+ * each one of them.
262452 *
263− * If a token in `redef` also appears in the copied language, then the existing token in the copied language
264− * will be overwritten at its original position.
453+ * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
265454 *
266− * ## Best practices
267− *
268− * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
269− * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
270− * understand the language definition because, normally, the order of tokens matters in Prism grammars.
455+ * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
456+ * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
457+ * @memberof Prism
458+ * @public
459+ */
460+ highlightAll: function (async, callback) {
461+ _.highlightAllUnder(document, async, callback);
462+ },
463+
464+ /**
465+ * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
466+ * {@link Prism.highlightElement} on each one of them.
271467 *
272− * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
273− * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
468+ * The following hooks will be run:
469+ * 1. `before-highlightall`
470+ * 2. `before-all-elements-highlight`
471+ * 3. All hooks of {@link Prism.highlightElement} for each element.
274472 *
275− * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
276− * @param {Grammar} redef The new tokens to append.
277− * @returns {Grammar} The new language created.
473+ * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
474+ * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
475+ * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
476+ * @memberof Prism
278477 * @public
279− * @example
280− * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
281− * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
282− * // at its original position
283− * 'comment': { ... },
284− * // CSS doesn't have a 'color' token, so this token will be appended
285− * 'color': /\b(?:red|green|blue)\b/
286− * });
287478 */
288− extend: function (id, redef) {
289− var lang = _.util.clone(_.languages[id]);
479+ highlightAllUnder: function (container, async, callback) {
480+ var env = {
481+ callback: callback,
482+ container: container,
483+ selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
484+ };
290485
291− for (var key in redef) {
292− lang[key] = redef[key];
293− }
486+ _.hooks.run('before-highlightall', env);
294487
295− return lang;
488+ env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
489+
490+ _.hooks.run('before-all-elements-highlight', env);
491+
492+ for (var i = 0, element; (element = env.elements[i++]);) {
493+ _.highlightElement(element, async === true, env.callback);
494+ }
296495 },
297496
298497 /**
299− * Inserts tokens _before_ another token in a language definition or any other grammar.
300− *
301− * ## Usage
302− *
303− * This helper method makes it easy to modify existing languages. For example, the CSS language definition
304− * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
305− * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
306− * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
307− * this:
308− *
309− * ```js
310− * Prism.languages.markup.style = {
311− * // token
312− * };
313− * ```
314− *
315− * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
316− * before existing tokens. For the CSS example above, you would use it like this:
317− *
318− * ```js
319− * Prism.languages.insertBefore('markup', 'cdata', {
320− * 'style': {
321− * // token
322− * }
323− * });
324− * ```
325− *
326− * ## Special cases
327− *
328− * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
329− * will be ignored.
330− *
331− * This behavior can be used to insert tokens after `before`:
332− *
333− * ```js
334− * Prism.languages.insertBefore('markup', 'comment', {
335− * 'comment': Prism.languages.markup.comment,
336− * // tokens after 'comment'
337− * });
338− * ```
339− *
340− * ## Limitations
341− *
342− * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
343− * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
344− * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
345− * deleting properties which is necessary to insert at arbitrary positions.
346− *
347− * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
348− * Instead, it will create a new object and replace all references to the target object with the new one. This
349− * can be done without temporarily deleting properties, so the iteration order is well-defined.
498+ * Highlights the code inside a single element.
350499 *
351− * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
352− * you hold the target object in a variable, then the value of the variable will not change.
500+ * The following hooks will be run:
501+ * 1. `before-sanity-check`
502+ * 2. `before-highlight`
503+ * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
504+ * 4. `before-insert`
505+ * 5. `after-highlight`
506+ * 6. `complete`
353507 *
354− * ```js
355− * var oldMarkup = Prism.languages.markup;
356− * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
357− *
358− * assert(oldMarkup !== Prism.languages.markup);
359− * assert(newMarkup === Prism.languages.markup);
360− * ```
508+ * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
509+ * the element's language.
361510 *
362− * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
363− * object to be modified.
364− * @param {string} before The key to insert before.
365− * @param {Grammar} insert An object containing the key-value pairs to be inserted.
366− * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
367− * object to be modified.
511+ * @param {Element} element The element containing the code.
512+ * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
513+ * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
514+ * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
515+ * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
368516 *
369− * Defaults to `Prism.languages`.
370− * @returns {Grammar} The new grammar object.
517+ * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
518+ * asynchronous highlighting to work. You can build your own bundle on the
519+ * [Download page](https://prismjs.com/download.html).
520+ * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
521+ * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
522+ * @memberof Prism
371523 * @public
372524 */
373− insertBefore: function (inside, before, insert, root) {
374− root = root || /** @type {any} */ (_.languages);
375− var grammar = root[inside];
376− /** @type {Grammar} */
377− var ret = {};
378−
379− for (var token in grammar) {
380− if (grammar.hasOwnProperty(token)) {
381−
382− if (token == before) {
383− for (var newToken in insert) {
384− if (insert.hasOwnProperty(newToken)) {
385− ret[newToken] = insert[newToken];
386− }
387− }
388− }
389−
390− // Do not insert token which also occur in insert. See #1525
391− if (!insert.hasOwnProperty(token)) {
392− ret[token] = grammar[token];
393− }
394− }
525+ highlightElement: function (element, async, callback) {
526+ // Find language
527+ var language = _.util.getLanguage(element);
528+ var grammar = _.languages[language];
529+
530+ // Set language on the element, if not present
531+ element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
532+
533+ // Set language on the parent, for styling
534+ var parent = element.parentElement;
535+ if (parent && parent.nodeName.toLowerCase() === 'pre') {
536+ parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
395537 }
396538
397− var old = root[inside];
398− root[inside] = ret;
539+ var code = element.textContent;
399540
400− // Update references in other language definitions
401− _.languages.DFS(_.languages, function(key, value) {
402− if (value === old && key != inside) {
403− this[key] = ret;
404− }
405− });
406−
407− return ret;
408− },
409−
410− // Traverse a language definition with Depth First Search
411− DFS: function DFS(o, callback, type, visited) {
412− visited = visited || {};
541+ var env = {
542+ element: element,
543+ language: language,
544+ grammar: grammar,
545+ code: code
546+ };
413547
414− var objId = _.util.objId;
548+ function insertHighlightedCode(highlightedCode) {
549+ env.highlightedCode = highlightedCode;
415550
416− for (var i in o) {
417− if (o.hasOwnProperty(i)) {
418− callback.call(o, i, o[i], type || i);
551+ _.hooks.run('before-insert', env);
419552
420− var property = o[i],
421− propertyType = _.util.type(property);
553+ env.element.innerHTML = env.highlightedCode;
422554
423− if (propertyType === 'Object' && !visited[objId(property)]) {
424− visited[objId(property)] = true;
425− DFS(property, callback, null, visited);
426− }
427− else if (propertyType === 'Array' && !visited[objId(property)]) {
428− visited[objId(property)] = true;
429− DFS(property, callback, i, visited);
430− }
431− }
555+ _.hooks.run('after-highlight', env);
556+ _.hooks.run('complete', env);
557+ callback && callback.call(env.element);
432558 }
433− }
434− },
435559
436− plugins: {},
560+ _.hooks.run('before-sanity-check', env);
437561
438− /**
439− * This is the most high-level function in Prism’s API.
440− * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
441− * each one of them.
442− *
443− * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
444− *
445− * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
446− * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
447− * @memberof Prism
448− * @public
449− */
450− highlightAll: function(async, callback) {
451− _.highlightAllUnder(document, async, callback);
452− },
453−
454− /**
455− * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
456− * {@link Prism.highlightElement} on each one of them.
457− *
458− * The following hooks will be run:
459− * 1. `before-highlightall`
460− * 2. `before-all-elements-highlight`
461− * 3. All hooks of {@link Prism.highlightElement} for each element.
462− *
463− * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
464− * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
465− * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
466− * @memberof Prism
467− * @public
468− */
469− highlightAllUnder: function(container, async, callback) {
470− var env = {
471− callback: callback,
472− container: container,
473− selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
474− };
475−
476− _.hooks.run('before-highlightall', env);
562+ // plugins may change/add the parent/element
563+ parent = env.element.parentElement;
564+ if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
565+ parent.setAttribute('tabindex', '0');
566+ }
477567
478− env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
568+ if (!env.code) {
569+ _.hooks.run('complete', env);
570+ callback && callback.call(env.element);
571+ return;
572+ }
479573
480− _.hooks.run('before-all-elements-highlight', env);
574+ _.hooks.run('before-highlight', env);
481575
482− for (var i = 0, element; element = env.elements[i++];) {
483− _.highlightElement(element, async === true, env.callback);
484− }
485− },
576+ if (!env.grammar) {
577+ insertHighlightedCode(_.util.encode(env.code));
578+ return;
579+ }
486580
487− /**
488− * Highlights the code inside a single element.
489− *
490− * The following hooks will be run:
491− * 1. `before-sanity-check`
492− * 2. `before-highlight`
493− * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
494− * 4. `before-insert`
495− * 5. `after-highlight`
496− * 6. `complete`
497− *
498− * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
499− * the element's language.
500− *
501− * @param {Element} element The element containing the code.
502− * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
503− * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
504− * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
505− * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
506− *
507− * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
508− * asynchronous highlighting to work. You can build your own bundle on the
509− * [Download page](https://prismjs.com/download.html).
510− * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
511− * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
512− * @memberof Prism
513− * @public
514− */
515− highlightElement: function(element, async, callback) {
516− // Find language
517− var language = _.util.getLanguage(element);
518− var grammar = _.languages[language];
519−
520− // Set language on the element, if not present
521− element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
522−
523− // Set language on the parent, for styling
524− var parent = element.parentElement;
525− if (parent && parent.nodeName.toLowerCase() === 'pre') {
526− parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
527− }
581+ if (async && _self.Worker) {
582+ var worker = new Worker(_.filename);
528583
529− var code = element.textContent;
584+ worker.onmessage = function (evt) {
585+ insertHighlightedCode(evt.data);
586+ };
530587
531− var env = {
532− element: element,
533− language: language,
534− grammar: grammar,
535− code: code
536− };
588+ worker.postMessage(JSON.stringify({
589+ language: env.language,
590+ code: env.code,
591+ immediateClose: true
592+ }));
593+ } else {
594+ insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
595+ }
596+ },
537597
538− function insertHighlightedCode(highlightedCode) {
539− env.highlightedCode = highlightedCode;
598+ /**
599+ * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
600+ * and the language definitions to use, and returns a string with the HTML produced.
601+ *
602+ * The following hooks will be run:
603+ * 1. `before-tokenize`
604+ * 2. `after-tokenize`
605+ * 3. `wrap`: On each {@link Token}.
606+ *
607+ * @param {string} text A string with the code to be highlighted.
608+ * @param {Grammar} grammar An object containing the tokens to use.
609+ *
610+ * Usually a language definition like `Prism.languages.markup`.
611+ * @param {string} language The name of the language definition passed to `grammar`.
612+ * @returns {string} The highlighted HTML.
613+ * @memberof Prism
614+ * @public
615+ * @example
616+ * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
617+ */
618+ highlight: function (text, grammar, language) {
619+ var env = {
620+ code: text,
621+ grammar: grammar,
622+ language: language
623+ };
624+ _.hooks.run('before-tokenize', env);
625+ env.tokens = _.tokenize(env.code, env.grammar);
626+ _.hooks.run('after-tokenize', env);
627+ return Token.stringify(_.util.encode(env.tokens), env.language);
628+ },
540629
541− _.hooks.run('before-insert', env);
630+ /**
631+ * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
632+ * and the language definitions to use, and returns an array with the tokenized code.
633+ *
634+ * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
635+ *
636+ * This method could be useful in other contexts as well, as a very crude parser.
637+ *
638+ * @param {string} text A string with the code to be highlighted.
639+ * @param {Grammar} grammar An object containing the tokens to use.
640+ *
641+ * Usually a language definition like `Prism.languages.markup`.
642+ * @returns {TokenStream} An array of strings and tokens, a token stream.
643+ * @memberof Prism
644+ * @public
645+ * @example
646+ * let code = `var foo = 0;`;
647+ * let tokens = Prism.tokenize(code, Prism.languages.javascript);
648+ * tokens.forEach(token => {
649+ * if (token instanceof Prism.Token && token.type === 'number') {
650+ * console.log(`Found numeric literal: ${token.content}`);
651+ * }
652+ * });
653+ */
654+ tokenize: function (text, grammar) {
655+ var rest = grammar.rest;
656+ if (rest) {
657+ for (var token in rest) {
658+ grammar[token] = rest[token];
659+ }
542660
543− env.element.innerHTML = env.highlightedCode;
661+ delete grammar.rest;
662+ }
544663
545− _.hooks.run('after-highlight', env);
546− _.hooks.run('complete', env);
547− callback && callback.call(env.element);
548− }
664+ var tokenList = new LinkedList();
665+ addAfter(tokenList, tokenList.head, text);
549666
550− _.hooks.run('before-sanity-check', env);
667+ matchGrammar(text, tokenList, grammar, tokenList.head, 0);
551668
552− if (!env.code) {
553− _.hooks.run('complete', env);
554− callback && callback.call(env.element);
555− return;
556− }
669+ return toArray(tokenList);
670+ },
557671
558− _.hooks.run('before-highlight', env);
672+ /**
673+ * @namespace
674+ * @memberof Prism
675+ * @public
676+ */
677+ hooks: {
678+ all: {},
559679
560− if (!env.grammar) {
561− insertHighlightedCode(_.util.encode(env.code));
562− return;
563− }
680+ /**
681+ * Adds the given callback to the list of callbacks for the given hook.
682+ *
683+ * The callback will be invoked when the hook it is registered for is run.
684+ * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
685+ *
686+ * One callback function can be registered to multiple hooks and the same hook multiple times.
687+ *
688+ * @param {string} name The name of the hook.
689+ * @param {HookCallback} callback The callback function which is given environment variables.
690+ * @public
691+ */
692+ add: function (name, callback) {
693+ var hooks = _.hooks.all;
564694
565− if (async && _self.Worker) {
566− var worker = new Worker(_.filename);
695+ hooks[name] = hooks[name] || [];
567696
568− worker.onmessage = function(evt) {
569− insertHighlightedCode(evt.data);
570− };
697+ hooks[name].push(callback);
698+ },
571699
572− worker.postMessage(JSON.stringify({
573− language: env.language,
574− code: env.code,
575− immediateClose: true
576− }));
577− }
578− else {
579− insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
580− }
581− },
700+ /**
701+ * Runs a hook invoking all registered callbacks with the given environment variables.
702+ *
703+ * Callbacks will be invoked synchronously and in the order in which they were registered.
704+ *
705+ * @param {string} name The name of the hook.
706+ * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
707+ * @public
708+ */
709+ run: function (name, env) {
710+ var callbacks = _.hooks.all[name];
582711
583− /**
584− * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
585− * and the language definitions to use, and returns a string with the HTML produced.
586− *
587− * The following hooks will be run:
588− * 1. `before-tokenize`
589− * 2. `after-tokenize`
590− * 3. `wrap`: On each {@link Token}.
591− *
592− * @param {string} text A string with the code to be highlighted.
593− * @param {Grammar} grammar An object containing the tokens to use.
594− *
595− * Usually a language definition like `Prism.languages.markup`.
596− * @param {string} language The name of the language definition passed to `grammar`.
597− * @returns {string} The highlighted HTML.
598− * @memberof Prism
599− * @public
600− * @example
601− * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
602− */
603− highlight: function (text, grammar, language) {
604− var env = {
605− code: text,
606− grammar: grammar,
607− language: language
608− };
609− _.hooks.run('before-tokenize', env);
610− env.tokens = _.tokenize(env.code, env.grammar);
611− _.hooks.run('after-tokenize', env);
612− return Token.stringify(_.util.encode(env.tokens), env.language);
613− },
712+ if (!callbacks || !callbacks.length) {
713+ return;
714+ }
614715
615− /**
616− * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
617− * and the language definitions to use, and returns an array with the tokenized code.
618− *
619− * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
620− *
621− * This method could be useful in other contexts as well, as a very crude parser.
622− *
623− * @param {string} text A string with the code to be highlighted.
624− * @param {Grammar} grammar An object containing the tokens to use.
625− *
626− * Usually a language definition like `Prism.languages.markup`.
627− * @returns {TokenStream} An array of strings and tokens, a token stream.
628− * @memberof Prism
629− * @public
630− * @example
631− * let code = `var foo = 0;`;
632− * let tokens = Prism.tokenize(code, Prism.languages.javascript);
633− * tokens.forEach(token => {
634− * if (token instanceof Prism.Token && token.type === 'number') {
635− * console.log(`Found numeric literal: ${token.content}`);
636− * }
637− * });
638− */
639− tokenize: function(text, grammar) {
640− var rest = grammar.rest;
641− if (rest) {
642− for (var token in rest) {
643− grammar[token] = rest[token];
716+ for (var i = 0, callback; (callback = callbacks[i++]);) {
717+ callback(env);
718+ }
644719 }
720+ },
645721
646− delete grammar.rest;
647− }
648−
649− var tokenList = new LinkedList();
650− addAfter(tokenList, tokenList.head, text);
722+ Token: Token
723+ };
724+ _self.Prism = _;
651725
652− matchGrammar(text, tokenList, grammar, tokenList.head, 0);
653726
654− return toArray(tokenList);
655− },
727+ // Typescript note:
728+ // The following can be used to import the Token type in JSDoc:
729+ //
730+ // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
656731
657732 /**
658− * @namespace
659− * @memberof Prism
733+ * Creates a new token.
734+ *
735+ * @param {string} type See {@link Token#type type}
736+ * @param {string | TokenStream} content See {@link Token#content content}
737+ * @param {string|string[]} [alias] The alias(es) of the token.
738+ * @param {string} [matchedStr=""] A copy of the full string this token was created from.
739+ * @class
740+ * @global
660741 * @public
661742 */
662− hooks: {
663− all: {},
664−
743+ function Token(type, content, alias, matchedStr) {
665744 /**
666− * Adds the given callback to the list of callbacks for the given hook.
745+ * The type of the token.
667746 *
668− * The callback will be invoked when the hook it is registered for is run.
669− * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
747+ * This is usually the key of a pattern in a {@link Grammar}.
670748 *
671− * One callback function can be registered to multiple hooks and the same hook multiple times.
672− *
673− * @param {string} name The name of the hook.
674− * @param {HookCallback} callback The callback function which is given environment variables.
749+ * @type {string}
750+ * @see GrammarToken
675751 * @public
676752 */
677− add: function (name, callback) {
678− var hooks = _.hooks.all;
679−
680− hooks[name] = hooks[name] || [];
681−
682− hooks[name].push(callback);
683− },
684−
753+ this.type = type;
685754 /**
686− * Runs a hook invoking all registered callbacks with the given environment variables.
755+ * The strings or tokens contained by this token.
687756 *
688− * Callbacks will be invoked synchronously and in the order in which they were registered.
757+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
689758 *
690− * @param {string} name The name of the hook.
691− * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
759+ * @type {string | TokenStream}
692760 * @public
693761 */
694− run: function (name, env) {
695− var callbacks = _.hooks.all[name];
696−
697− if (!callbacks || !callbacks.length) {
698− return;
699− }
700−
701− for (var i=0, callback; callback = callbacks[i++];) {
702− callback(env);
703− }
704− }
705− },
706−
707− Token: Token
708−};
709−_self.Prism = _;
710−
711−
712−// Typescript note:
713−// The following can be used to import the Token type in JSDoc:
714−//
715−// @typedef {InstanceType<import("./prism-core")["Token"]>} Token
762+ this.content = content;
763+ /**
764+ * The alias(es) of the token.
765+ *
766+ * @type {string|string[]}
767+ * @see GrammarToken
768+ * @public
769+ */
770+ this.alias = alias;
771+ // Copy of the full string this token was created from
772+ this.length = (matchedStr || '').length | 0;
773+ }
716774
717−/**
718− * Creates a new token.
719− *
720− * @param {string} type See {@link Token#type type}
721− * @param {string | TokenStream} content See {@link Token#content content}
722− * @param {string|string[]} [alias] The alias(es) of the token.
723− * @param {string} [matchedStr=""] A copy of the full string this token was created from.
724− * @class
725− * @global
726− * @public
727− */
728−function Token(type, content, alias, matchedStr) {
729775 /**
730− * The type of the token.
776+ * A token stream is an array of strings and {@link Token Token} objects.
731777 *
732− * This is usually the key of a pattern in a {@link Grammar}.
778+ * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
779+ * them.
733780 *
734− * @type {string}
735− * @see GrammarToken
736− * @public
737− */
738− this.type = type;
739− /**
740− * The strings or tokens contained by this token.
781+ * 1. No adjacent strings.
782+ * 2. No empty strings.
741783 *
742− * This will be a token stream if the pattern matched also defined an `inside` grammar.
784+ * The only exception here is the token stream that only contains the empty string and nothing else.
743785 *
744− * @type {string | TokenStream}
786+ * @typedef {Array<string | Token>} TokenStream
787+ * @global
745788 * @public
746789 */
747− this.content = content;
790+
748791 /**
749− * The alias(es) of the token.
792+ * Converts the given token or token stream to an HTML representation.
750793 *
751− * @type {string|string[]}
752− * @see GrammarToken
753− * @public
794+ * The following hooks will be run:
795+ * 1. `wrap`: On each {@link Token}.
796+ *
797+ * @param {string | Token | TokenStream} o The token or token stream to be converted.
798+ * @param {string} language The name of current language.
799+ * @returns {string} The HTML representation of the token or token stream.
800+ * @memberof Token
801+ * @static
754802 */
755− this.alias = alias;
756− // Copy of the full string this token was created from
757− this.length = (matchedStr || '').length | 0;
758−}
759−
760−/**
761− * A token stream is an array of strings and {@link Token Token} objects.
762− *
763− * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
764− * them.
765− *
766− * 1. No adjacent strings.
767− * 2. No empty strings.
768− *
769− * The only exception here is the token stream that only contains the empty string and nothing else.
770− *
771− * @typedef {Array<string | Token>} TokenStream
772− * @global
773− * @public
774− */
775−
776−/**
777− * Converts the given token or token stream to an HTML representation.
778− *
779− * The following hooks will be run:
780− * 1. `wrap`: On each {@link Token}.
781− *
782− * @param {string | Token | TokenStream} o The token or token stream to be converted.
783− * @param {string} language The name of current language.
784− * @returns {string} The HTML representation of the token or token stream.
785− * @memberof Token
786− * @static
787− */
788−Token.stringify = function stringify(o, language) {
789− if (typeof o == 'string') {
790− return o;
791− }
792− if (Array.isArray(o)) {
793− var s = '';
794− o.forEach(function (e) {
795− s += stringify(e, language);
796− });
797− return s;
798− }
799−
800− var env = {
801− type: o.type,
802− content: stringify(o.content, language),
803− tag: 'span',
804− classes: ['token', o.type],
805− attributes: {},
806− language: language
807− };
808−
809− var aliases = o.alias;
810− if (aliases) {
811− if (Array.isArray(aliases)) {
812− Array.prototype.push.apply(env.classes, aliases);
813− } else {
814− env.classes.push(aliases);
803+ Token.stringify = function stringify(o, language) {
804+ if (typeof o == 'string') {
805+ return o;
806+ }
807+ if (Array.isArray(o)) {
808+ var s = '';
809+ o.forEach(function (e) {
810+ s += stringify(e, language);
811+ });
812+ return s;
815813 }
816− }
817814
818− _.hooks.run('wrap', env);
815+ var env = {
816+ type: o.type,
817+ content: stringify(o.content, language),
818+ tag: 'span',
819+ classes: ['token', o.type],
820+ attributes: {},
821+ language: language
822+ };
819823
820− var attributes = '';
821− for (var name in env.attributes) {
822− attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
823− }
824+ var aliases = o.alias;
825+ if (aliases) {
826+ if (Array.isArray(aliases)) {
827+ Array.prototype.push.apply(env.classes, aliases);
828+ } else {
829+ env.classes.push(aliases);
830+ }
831+ }
824832
825− return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
826−};
833+ _.hooks.run('wrap', env);
827834
828−/**
829− * @param {RegExp} pattern
830− * @param {number} pos
831− * @param {string} text
832− * @param {boolean} lookbehind
833− * @returns {RegExpExecArray | null}
834− */
835−function matchPattern(pattern, pos, text, lookbehind) {
836− pattern.lastIndex = pos;
837− var match = pattern.exec(text);
838− if (match && lookbehind && match[1]) {
839− // change the match to remove the text matched by the Prism lookbehind group
840− var lookbehindLength = match[1].length;
841− match.index += lookbehindLength;
842− match[0] = match[0].slice(lookbehindLength);
843− }
844− return match;
845−}
846−
847−/**
848− * @param {string} text
849− * @param {LinkedList<string | Token>} tokenList
850− * @param {any} grammar
851− * @param {LinkedListNode<string | Token>} startNode
852− * @param {number} startPos
853− * @param {RematchOptions} [rematch]
854− * @returns {void}
855− * @private
856− *
857− * @typedef RematchOptions
858− * @property {string} cause
859− * @property {number} reach
860− */
861−function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
862− for (var token in grammar) {
863− if (!grammar.hasOwnProperty(token) || !grammar[token]) {
864− continue;
835+ var attributes = '';
836+ for (var name in env.attributes) {
837+ attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
865838 }
866839
867− var patterns = grammar[token];
868− patterns = Array.isArray(patterns) ? patterns : [patterns];
869−
870− for (var j = 0; j < patterns.length; ++j) {
871− if (rematch && rematch.cause == token + ',' + j) {
872− return;
873− }
840+ return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
841+ };
874842
875− var patternObj = patterns[j],
876− inside = patternObj.inside,
877− lookbehind = !!patternObj.lookbehind,
878− greedy = !!patternObj.greedy,
879− alias = patternObj.alias;
843+ /**
844+ * @param {RegExp} pattern
845+ * @param {number} pos
846+ * @param {string} text
847+ * @param {boolean} lookbehind
848+ * @returns {RegExpExecArray | null}
849+ */
850+ function matchPattern(pattern, pos, text, lookbehind) {
851+ pattern.lastIndex = pos;
852+ var match = pattern.exec(text);
853+ if (match && lookbehind && match[1]) {
854+ // change the match to remove the text matched by the Prism lookbehind group
855+ var lookbehindLength = match[1].length;
856+ match.index += lookbehindLength;
857+ match[0] = match[0].slice(lookbehindLength);
858+ }
859+ return match;
860+ }
880861
881− if (greedy && !patternObj.pattern.global) {
882− // Without the global flag, lastIndex won't work
883− var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
884− patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
862+ /**
863+ * @param {string} text
864+ * @param {LinkedList<string | Token>} tokenList
865+ * @param {any} grammar
866+ * @param {LinkedListNode<string | Token>} startNode
867+ * @param {number} startPos
868+ * @param {RematchOptions} [rematch]
869+ * @returns {void}
870+ * @private
871+ *
872+ * @typedef RematchOptions
873+ * @property {string} cause
874+ * @property {number} reach
875+ */
876+ function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
877+ for (var token in grammar) {
878+ if (!grammar.hasOwnProperty(token) || !grammar[token]) {
879+ continue;
885880 }
886881
887− /** @type {RegExp} */
888− var pattern = patternObj.pattern || patternObj;
889−
890− for ( // iterate the token list and keep track of the current token/string position
891− var currentNode = startNode.next, pos = startPos;
892− currentNode !== tokenList.tail;
893− pos += currentNode.value.length, currentNode = currentNode.next
894− ) {
882+ var patterns = grammar[token];
883+ patterns = Array.isArray(patterns) ? patterns : [patterns];
895884
896− if (rematch && pos >= rematch.reach) {
897− break;
885+ for (var j = 0; j < patterns.length; ++j) {
886+ if (rematch && rematch.cause == token + ',' + j) {
887+ return;
898888 }
899889
900− var str = currentNode.value;
890+ var patternObj = patterns[j];
891+ var inside = patternObj.inside;
892+ var lookbehind = !!patternObj.lookbehind;
893+ var greedy = !!patternObj.greedy;
894+ var alias = patternObj.alias;
901895
902− if (tokenList.length > text.length) {
903− // Something went terribly wrong, ABORT, ABORT!
904− return;
896+ if (greedy && !patternObj.pattern.global) {
897+ // Without the global flag, lastIndex won't work
898+ var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
899+ patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
905900 }
906901
907− if (str instanceof Token) {
908− continue;
909− }
902+ /** @type {RegExp} */
903+ var pattern = patternObj.pattern || patternObj;
910904
911− var removeCount = 1; // this is the to parameter of removeBetween
912− var match;
905+ for ( // iterate the token list and keep track of the current token/string position
906+ var currentNode = startNode.next, pos = startPos;
907+ currentNode !== tokenList.tail;
908+ pos += currentNode.value.length, currentNode = currentNode.next
909+ ) {
913910
914− if (greedy) {
915− match = matchPattern(pattern, pos, text, lookbehind);
916− if (!match) {
911+ if (rematch && pos >= rematch.reach) {
917912 break;
918913 }
919914
920− var from = match.index;
921− var to = match.index + match[0].length;
922− var p = pos;
915+ var str = currentNode.value;
923916
924− // find the node that contains the match
925− p += currentNode.value.length;
926− while (from >= p) {
927− currentNode = currentNode.next;
928− p += currentNode.value.length;
917+ if (tokenList.length > text.length) {
918+ // Something went terribly wrong, ABORT, ABORT!
919+ return;
929920 }
930− // adjust pos (and p)
931− p -= currentNode.value.length;
932− pos = p;
933921
934− // the current node is a Token, then the match starts inside another Token, which is invalid
935− if (currentNode.value instanceof Token) {
922+ if (str instanceof Token) {
936923 continue;
937924 }
938925
939− // find the last node which is affected by this match
940− for (
941− var k = currentNode;
942− k !== tokenList.tail && (p < to || typeof k.value === 'string');
943− k = k.next
944− ) {
945− removeCount++;
946− p += k.value.length;
947− }
948− removeCount--;
926+ var removeCount = 1; // this is the to parameter of removeBetween
927+ var match;
949928
950− // replace with the new match
951− str = text.slice(pos, p);
952− match.index -= pos;
953− } else {
954− match = matchPattern(pattern, 0, str, lookbehind);
955− if (!match) {
956− continue;
929+ if (greedy) {
930+ match = matchPattern(pattern, pos, text, lookbehind);
931+ if (!match) {
932+ break;
933+ }
934+
935+ var from = match.index;
936+ var to = match.index + match[0].length;
937+ var p = pos;
938+
939+ // find the node that contains the match
940+ p += currentNode.value.length;
941+ while (from >= p) {
942+ currentNode = currentNode.next;
943+ p += currentNode.value.length;
944+ }
945+ // adjust pos (and p)
946+ p -= currentNode.value.length;
947+ pos = p;
948+
949+ // the current node is a Token, then the match starts inside another Token, which is invalid
950+ if (currentNode.value instanceof Token) {
951+ continue;
952+ }
953+
954+ // find the last node which is affected by this match
955+ for (
956+ var k = currentNode;
957+ k !== tokenList.tail && (p < to || typeof k.value === 'string');
958+ k = k.next
959+ ) {
960+ removeCount++;
961+ p += k.value.length;
962+ }
963+ removeCount--;
964+
965+ // replace with the new match
966+ str = text.slice(pos, p);
967+ match.index -= pos;
968+ } else {
969+ match = matchPattern(pattern, 0, str, lookbehind);
970+ if (!match) {
971+ continue;
972+ }
957973 }
958− }
959974
960− var from = match.index,
961− matchStr = match[0],
962− before = str.slice(0, from),
963− after = str.slice(from + matchStr.length);
975+ // eslint-disable-next-line no-redeclare
976+ var from = match.index;
977+ var matchStr = match[0];
978+ var before = str.slice(0, from);
979+ var after = str.slice(from + matchStr.length);
964980
965− var reach = pos + str.length;
966− if (rematch && reach > rematch.reach) {
967− rematch.reach = reach;
968− }
981+ var reach = pos + str.length;
982+ if (rematch && reach > rematch.reach) {
983+ rematch.reach = reach;
984+ }
969985
970− var removeFrom = currentNode.prev;
986+ var removeFrom = currentNode.prev;
971987
972− if (before) {
973− removeFrom = addAfter(tokenList, removeFrom, before);
974− pos += before.length;
975− }
988+ if (before) {
989+ removeFrom = addAfter(tokenList, removeFrom, before);
990+ pos += before.length;
991+ }
976992
977− removeRange(tokenList, removeFrom, removeCount);
993+ removeRange(tokenList, removeFrom, removeCount);
978994
979− var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
980− currentNode = addAfter(tokenList, removeFrom, wrapped);
995+ var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
996+ currentNode = addAfter(tokenList, removeFrom, wrapped);
981997
982− if (after) {
983− addAfter(tokenList, currentNode, after);
984− }
998+ if (after) {
999+ addAfter(tokenList, currentNode, after);
1000+ }
9851001
986− if (removeCount > 1) {
987− // at least one Token object was removed, so we have to do some rematching
988− // this can only happen if the current pattern is greedy
1002+ if (removeCount > 1) {
1003+ // at least one Token object was removed, so we have to do some rematching
1004+ // this can only happen if the current pattern is greedy
9891005
990− /** @type {RematchOptions} */
991− var nestedRematch = {
992− cause: token + ',' + j,
993− reach: reach
994− };
995− matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
1006+ /** @type {RematchOptions} */
1007+ var nestedRematch = {
1008+ cause: token + ',' + j,
1009+ reach: reach
1010+ };
1011+ matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
9961012
997− // the reach might have been extended because of the rematching
998− if (rematch && nestedRematch.reach > rematch.reach) {
999− rematch.reach = nestedRematch.reach;
1013+ // the reach might have been extended because of the rematching
1014+ if (rematch && nestedRematch.reach > rematch.reach) {
1015+ rematch.reach = nestedRematch.reach;
1016+ }
10001017 }
10011018 }
10021019 }
10031020 }
10041021 }
1005−}
10061022
1007−/**
1008− * @typedef LinkedListNode
1009− * @property {T} value
1010− * @property {LinkedListNode<T> | null} prev The previous node.
1011− * @property {LinkedListNode<T> | null} next The next node.
1012− * @template T
1013− * @private
1014− */
1023+ /**
1024+ * @typedef LinkedListNode
1025+ * @property {T} value
1026+ * @property {LinkedListNode<T> | null} prev The previous node.
1027+ * @property {LinkedListNode<T> | null} next The next node.
1028+ * @template T
1029+ * @private
1030+ */
10151031
1016−/**
1017− * @template T
1018− * @private
1019− */
1020−function LinkedList() {
1021− /** @type {LinkedListNode<T>} */
1022− var head = { value: null, prev: null, next: null };
1023− /** @type {LinkedListNode<T>} */
1024− var tail = { value: null, prev: head, next: null };
1025− head.next = tail;
1026−
1027− /** @type {LinkedListNode<T>} */
1028− this.head = head;
1029− /** @type {LinkedListNode<T>} */
1030− this.tail = tail;
1031− this.length = 0;
1032−}
1032+ /**
1033+ * @template T
1034+ * @private
1035+ */
1036+ function LinkedList() {
1037+ /** @type {LinkedListNode<T>} */
1038+ var head = { value: null, prev: null, next: null };
1039+ /** @type {LinkedListNode<T>} */
1040+ var tail = { value: null, prev: head, next: null };
1041+ head.next = tail;
1042+
1043+ /** @type {LinkedListNode<T>} */
1044+ this.head = head;
1045+ /** @type {LinkedListNode<T>} */
1046+ this.tail = tail;
1047+ this.length = 0;
1048+ }
10331049
1034−/**
1035− * Adds a new node with the given value to the list.
1036− * @param {LinkedList<T>} list
1037− * @param {LinkedListNode<T>} node
1038− * @param {T} value
1039− * @returns {LinkedListNode<T>} The added node.
1040− * @template T
1041− */
1042−function addAfter(list, node, value) {
1043− // assumes that node != list.tail && values.length >= 0
1044− var next = node.next;
1050+ /**
1051+ * Adds a new node with the given value to the list.
1052+ *
1053+ * @param {LinkedList<T>} list
1054+ * @param {LinkedListNode<T>} node
1055+ * @param {T} value
1056+ * @returns {LinkedListNode<T>} The added node.
1057+ * @template T
1058+ */
1059+ function addAfter(list, node, value) {
1060+ // assumes that node != list.tail && values.length >= 0
1061+ var next = node.next;
10451062
1046− var newNode = { value: value, prev: node, next: next };
1047− node.next = newNode;
1048− next.prev = newNode;
1049− list.length++;
1063+ var newNode = { value: value, prev: node, next: next };
1064+ node.next = newNode;
1065+ next.prev = newNode;
1066+ list.length++;
10501067
1051− return newNode;
1052−}
1053−/**
1054− * Removes `count` nodes after the given node. The given node will not be removed.
1055− * @param {LinkedList<T>} list
1056− * @param {LinkedListNode<T>} node
1057− * @param {number} count
1058− * @template T
1059− */
1060−function removeRange(list, node, count) {
1061− var next = node.next;
1062− for (var i = 0; i < count && next !== list.tail; i++) {
1063− next = next.next;
1068+ return newNode;
10641069 }
1065− node.next = next;
1066− next.prev = node;
1067− list.length -= i;
1068−}
1069−/**
1070− * @param {LinkedList<T>} list
1071− * @returns {T[]}
1072− * @template T
1073− */
1074−function toArray(list) {
1075− var array = [];
1076− var node = list.head.next;
1077− while (node !== list.tail) {
1078− array.push(node.value);
1079− node = node.next;
1070+ /**
1071+ * Removes `count` nodes after the given node. The given node will not be removed.
1072+ *
1073+ * @param {LinkedList<T>} list
1074+ * @param {LinkedListNode<T>} node
1075+ * @param {number} count
1076+ * @template T
1077+ */
1078+ function removeRange(list, node, count) {
1079+ var next = node.next;
1080+ for (var i = 0; i < count && next !== list.tail; i++) {
1081+ next = next.next;
1082+ }
1083+ node.next = next;
1084+ next.prev = node;
1085+ list.length -= i;
1086+ }
1087+ /**
1088+ * @param {LinkedList<T>} list
1089+ * @returns {T[]}
1090+ * @template T
1091+ */
1092+ function toArray(list) {
1093+ var array = [];
1094+ var node = list.head.next;
1095+ while (node !== list.tail) {
1096+ array.push(node.value);
1097+ node = node.next;
1098+ }
1099+ return array;
10801100 }
1081− return array;
1082−}
10831101
10841102
1085−if (!_self.document) {
1086− if (!_self.addEventListener) {
1087− // in Node.js
1088− return _;
1089− }
1103+ if (!_self.document) {
1104+ if (!_self.addEventListener) {
1105+ // in Node.js
1106+ return _;
1107+ }
10901108
1091− if (!_.disableWorkerMessageHandler) {
1092− // In worker
1093− _self.addEventListener('message', function (evt) {
1094− var message = JSON.parse(evt.data),
1095− lang = message.language,
1096− code = message.code,
1097− immediateClose = message.immediateClose;
1098−
1099− _self.postMessage(_.highlight(code, _.languages[lang], lang));
1100− if (immediateClose) {
1101− _self.close();
1102− }
1103− }, false);
1104− }
1109+ if (!_.disableWorkerMessageHandler) {
1110+ // In worker
1111+ _self.addEventListener('message', function (evt) {
1112+ var message = JSON.parse(evt.data);
1113+ var lang = message.language;
1114+ var code = message.code;
1115+ var immediateClose = message.immediateClose;
1116+
1117+ _self.postMessage(_.highlight(code, _.languages[lang], lang));
1118+ if (immediateClose) {
1119+ _self.close();
1120+ }
1121+ }, false);
1122+ }
11051123
1106− return _;
1107−}
1124+ return _;
1125+ }
11081126
1109−// Get current script and highlight
1110−var script = _.util.currentScript();
1127+ // Get current script and highlight
1128+ var script = _.util.currentScript();
11111129
1112−if (script) {
1113− _.filename = script.src;
1130+ if (script) {
1131+ _.filename = script.src;
11141132
1115− if (script.hasAttribute('data-manual')) {
1116− _.manual = true;
1133+ if (script.hasAttribute('data-manual')) {
1134+ _.manual = true;
1135+ }
11171136 }
1118−}
11191137
1120−function highlightAutomaticallyCallback() {
1121− if (!_.manual) {
1122− _.highlightAll();
1138+ function highlightAutomaticallyCallback() {
1139+ if (!_.manual) {
1140+ _.highlightAll();
1141+ }
11231142 }
1124−}
11251143
1126−if (!_.manual) {
1127− // If the document state is "loading", then we'll use DOMContentLoaded.
1128− // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
1129− // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
1130− // might take longer one animation frame to execute which can create a race condition where only some plugins have
1131− // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
1132− // See https://github.com/PrismJS/prism/issues/2102
1133− var readyState = document.readyState;
1134− if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
1135− document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
1136− } else {
1137− if (window.requestAnimationFrame) {
1138− window.requestAnimationFrame(highlightAutomaticallyCallback);
1144+ if (!_.manual) {
1145+ // If the document state is "loading", then we'll use DOMContentLoaded.
1146+ // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
1147+ // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
1148+ // might take longer one animation frame to execute which can create a race condition where only some plugins have
1149+ // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
1150+ // See https://github.com/PrismJS/prism/issues/2102
1151+ var readyState = document.readyState;
1152+ if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
1153+ document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
11391154 } else {
1140− window.setTimeout(highlightAutomaticallyCallback, 16);
1155+ if (window.requestAnimationFrame) {
1156+ window.requestAnimationFrame(highlightAutomaticallyCallback);
1157+ } else {
1158+ window.setTimeout(highlightAutomaticallyCallback, 16);
1159+ }
11411160 }
11421161 }
1143−}
11441162
1145−return _;
1163+ return _;
11461164
1147−})(_self);
1165+}(_self));
11481166
11491167 if (typeof module !== 'undefined' && module.exports) {
11501168 module.exports = Prism;
@@ -1176,7 +1194,7 @@ if (typeof global !== 'undefined') { · 25 unmodified lines
11761194 * each another.
11771195 * @global
11781196 * @public
1179−*/
1197+ */
11801198
11811199 /**
11821200 * @typedef Grammar
@@ -1194,7 +1212,7 @@ if (typeof global !== 'undefined') { · 11 unmodified lines
11941212 * @returns {void}
11951213 * @global
11961214 * @public
1197−*/
1215+ */
11981216
11991217 /**
12001218 * @callback HookCallback
@@ -1239,6 +1257,7 @@ Prism.languages.markup = { · 38 unmodified lines
12391257 'namespace': /^[^\s>\/:]+:/
12401258 }
12411259 },
1260+ 'special-attr': [],
12421261 'attr-value': {
12431262 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
12441263 inside: {
@@ -1325,6 +1344,49 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { · 80 unmodified lines
13251344 Prism.languages.insertBefore('markup', 'cdata', def);
13261345 }
13271346 });
1347+Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
1348+ /**
1349+ * Adds an pattern to highlight languages embedded in HTML attributes.
1350+ *
1351+ * An example of an inlined language is CSS with `style` attributes.
1352+ *
1353+ * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
1354+ * case insensitive.
1355+ * @param {string} lang The language key.
1356+ * @example
1357+ * addAttribute('style', 'css');
1358+ */
1359+ value: function (attrName, lang) {
1360+ Prism.languages.markup.tag.inside['special-attr'].push({
1361+ pattern: RegExp(
1362+ /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
1363+ 'i'
1364+ ),
1365+ lookbehind: true,
1366+ inside: {
1367+ 'attr-name': /^[^\s=]+/,
1368+ 'attr-value': {
1369+ pattern: /=[\s\S]+/,
1370+ inside: {
1371+ 'value': {
1372+ pattern: /(=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
1373+ lookbehind: true,
1374+ alias: [lang, 'language-' + lang],
1375+ inside: Prism.languages[lang]
1376+ },
1377+ 'punctuation': [
1378+ {
1379+ pattern: /^=/,
1380+ alias: 'attr-equals'
1381+ },
1382+ /"|'/
1383+ ]
1384+ }
1385+ }
1386+ }
1387+ });
1388+ }
1389+});
13281390
13291391 Prism.languages.html = Prism.languages.markup;
13301392 Prism.languages.mathml = Prism.languages.markup;
@@ -1386,34 +1448,7 @@ Prism.languages.rss = Prism.languages.xml; · 55 unmodified lines
13861448 var markup = Prism.languages.markup;
13871449 if (markup) {
13881450 markup.tag.addInlined('style', 'css');
1389−
1390− Prism.languages.insertBefore('inside', 'attr-value', {
1391− 'style-attr': {
1392− pattern: /(^|["'\s])style\s*=\s*(?:"[^"]*"|'[^']*')/i,
1393− lookbehind: true,
1394− inside: {
1395− 'attr-value': {
1396− pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
1397− inside: {
1398− 'style': {
1399− pattern: /(["'])[\s\S]+(?=["']$)/,
1400− lookbehind: true,
1401− alias: 'language-css',
1402− inside: Prism.languages.css
1403− },
1404− 'punctuation': [
1405− {
1406− pattern: /^=/,
1407− alias: 'attr-equals'
1408− },
1409− /"|'/
1410− ]
1411− }
1412− },
1413− 'attr-name': /^style/i
1414− }
1415− }
1416− }, markup.tag);
1451+ markup.tag.addAttribute('style', 'css');
14171452 }
14181453
14191454 }(Prism));
@@ -1464,7 +1499,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', { · 44 unmodified lines
14641499 lookbehind: true
14651500 },
14661501 {
1467− 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/,
1502+ 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/,
14681503 lookbehind: true
14691504 },
14701505 ],
@@ -1478,7 +1513,7 @@ Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|ext · 7 unmodified lines
14781513
14791514 Prism.languages.insertBefore('javascript', 'keyword', {
14801515 'regex': {
1481− pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
1516+ pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
14821517 lookbehind: true,
14831518 greedy: true,
14841519 inside: {
@@ -1522,6 +1557,11 @@ Prism.languages.insertBefore('javascript', 'keyword', { · 37 unmodified lines
15221557 });
15231558
15241559 Prism.languages.insertBefore('javascript', 'string', {
1560+ 'hashbang': {
1561+ pattern: /^#!.*/,
1562+ greedy: true,
1563+ alias: 'comment'
1564+ },
15251565 'template-string': {
15261566 pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,
15271567 greedy: true,
@@ -1548,11 +1588,18 @@ Prism.languages.insertBefore('javascript', 'string', { · 20 unmodified lines
15481588
15491589 if (Prism.languages.markup) {
15501590 Prism.languages.markup.tag.addInlined('script', 'javascript');
1591+
1592+ // add attribute support for all DOM events.
1593+ // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
1594+ Prism.languages.markup.tag.addAttribute(
1595+ /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,
1596+ 'javascript'
1597+ );
15511598 }
15521599
15531600 Prism.languages.js = Prism.languages.javascript;
15541601
1555−(function(Prism) {
1602+(function (Prism) {
15561603 // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
15571604 // + LC_ALL, RANDOM, REPLY, SECONDS.
15581605 // + make sure PS1..4 are here as they are not always set,
@@ -1569,7 +1616,7 @@ Prism.languages.js = Prism.languages.javascript; · 10 unmodified lines
15691616 var insideString = {
15701617 'bash': commandAfterHeredoc,
15711618 'environment': {
1572− pattern: RegExp("\\$" + envVars),
1619+ pattern: RegExp('\\$' + envVars),
15731620 alias: 'constant'
15741621 },
15751622 'variable': [
@@ -1609,7 +1656,7 @@ Prism.languages.js = Prism.languages.javascript; · 33 unmodified lines
16091656 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
16101657 'punctuation': /[\[\]]/,
16111658 'environment': {
1612− pattern: RegExp("(\\{)" + envVars),
1659+ pattern: RegExp('(\\{)' + envVars),
16131660 lookbehind: true,
16141661 alias: 'constant'
16151662 }
@@ -1637,13 +1684,13 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines
16371684 // but not “foo {”
16381685 {
16391686 // a) and c)
1640− pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,
1687+ pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
16411688 lookbehind: true,
16421689 alias: 'function'
16431690 },
16441691 {
16451692 // b)
1646− pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/,
1693+ pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
16471694 alias: 'function'
16481695 }
16491696 ],
@@ -1659,7 +1706,7 @@ Prism.languages.js = Prism.languages.javascript; · 9 unmodified lines
16591706 pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,
16601707 inside: {
16611708 'environment': {
1662− pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars),
1709+ pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
16631710 lookbehind: true,
16641711 alias: 'constant'
16651712 }
@@ -1687,14 +1734,29 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines
16871734 },
16881735 // “Normal” string
16891736 {
1690− pattern: /(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\2)[^\\`$])*\2/,
1737+ // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
1738+ pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
16911739 lookbehind: true,
16921740 greedy: true,
16931741 inside: insideString
1742+ },
1743+ {
1744+ // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
1745+ pattern: /(^|[^$\\])'[^']*'/,
1746+ lookbehind: true,
1747+ greedy: true
1748+ },
1749+ {
1750+ // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
1751+ pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
1752+ greedy: true,
1753+ inside: {
1754+ 'entity': insideString.entity
1755+ }
16941756 }
16951757 ],
16961758 'environment': {
1697− pattern: RegExp("\\$?" + envVars),
1759+ pattern: RegExp('\\$?' + envVars),
16981760 alias: 'constant'
16991761 },
17001762 'variable': insideString.variable,
@@ -1758,12 +1820,12 @@ Prism.languages.js = Prism.languages.javascript; · 57 unmodified lines
17581820 'number'
17591821 ];
17601822 var inside = insideString.variable[1].inside;
1761− for(var i = 0; i < toBeCopied.length; i++) {
1823+ for (var i = 0; i < toBeCopied.length; i++) {
17621824 inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
17631825 }
17641826
17651827 Prism.languages.shell = Prism.languages.bash;
1766−})(Prism);
1828+}(Prism));
17671829
17681830 Prism.languages.c = Prism.languages.extend('clike', {
17691831 'comment': {
@@ -1831,7 +1893,8 @@ delete Prism.languages.c['boolean']; · 61 unmodified lines
18311893
18321894 (function (Prism) {
18331895
1834− 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/;
1896+ 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/;
1897+ var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function () { return keyword.source; });
18351898
18361899 Prism.languages.cpp = Prism.languages.extend('c', {
18371900 'class-name': [
@@ -1857,11 +1920,31 @@ delete Prism.languages.c['boolean']; · 19 unmodified lines
18571920 pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,
18581921 greedy: true
18591922 },
1860− 'operator': />>=?|<<=?|->|([-+&|:])\1|[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
1923+ 'operator': />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,
18611924 'boolean': /\b(?:true|false)\b/
18621925 });
18631926
18641927 Prism.languages.insertBefore('cpp', 'string', {
1928+ 'module': {
1929+ // https://en.cppreference.com/w/cpp/language/modules
1930+ pattern: RegExp(
1931+ /(\b(?:module|import)\s+)/.source +
1932+ '(?:' +
1933+ // header-name
1934+ /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source +
1935+ '|' +
1936+ // module name or partition or both
1937+ /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function () { return modName; }) +
1938+ ')'
1939+ ),
1940+ lookbehind: true,
1941+ greedy: true,
1942+ inside: {
1943+ 'string': /^[<"][\s\S]+/,
1944+ 'operator': /:/,
1945+ 'punctuation': /\./
1946+ }
1947+ },
18651948 'raw-string': {
18661949 pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
18671950 alias: 'string',
@@ -1869,6 +1952,27 @@ delete Prism.languages.c['boolean']; · 1 unmodified line
18691952 }
18701953 });
18711954
1955+ Prism.languages.insertBefore('cpp', 'keyword', {
1956+ 'generic-function': {
1957+ pattern: /\b[a-z_]\w*\s*<(?:[^<>]|<(?:[^<>])*>)*>(?=\s*\()/i,
1958+ inside: {
1959+ 'function': /^\w+/,
1960+ 'generic': {
1961+ pattern: /<[\s\S]+/,
1962+ alias: 'class-name',
1963+ inside: Prism.languages.cpp
1964+ }
1965+ }
1966+ }
1967+ });
1968+
1969+ Prism.languages.insertBefore('cpp', 'operator', {
1970+ 'double-colon': {
1971+ pattern: /::/,
1972+ alias: 'punctuation'
1973+ }
1974+ });
1975+
18721976 Prism.languages.insertBefore('cpp', 'class-name', {
18731977 // the base clause is an optional list of parent classes
18741978 // https://en.cppreference.com/w/cpp/language/class
@@ -1879,108 +1983,109 @@ delete Prism.languages.c['boolean']; · 4 unmodified lines
18791983 inside: Prism.languages.extend('cpp', {})
18801984 }
18811985 });
1882− Prism.languages.insertBefore('inside', 'operator', {
1986+
1987+ Prism.languages.insertBefore('inside', 'double-colon', {
18831988 // All untokenized words that are not namespaces should be class names
18841989 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i
18851990 }, Prism.languages.cpp['base-clause']);
18861991
18871992 }(Prism));
18881993
1889−(function(Prism) {
1890−
1891−// Ignore comments starting with { to privilege string interpolation highlighting
1892−var comment = /#(?!\{).+/,
1893− interpolation = {
1894− pattern: /#\{[^}]+\}/,
1895− alias: 'variable'
1896− };
1994+(function (Prism) {
18971995
1898−Prism.languages.coffeescript = Prism.languages.extend('javascript', {
1899− 'comment': comment,
1900− 'string': [
1996+ // Ignore comments starting with { to privilege string interpolation highlighting
1997+ var comment = /#(?!\{).+/;
1998+ var interpolation = {
1999+ pattern: /#\{[^}]+\}/,
2000+ alias: 'variable'
2001+ };
19012002
1902− // Strings are multiline
1903− {
1904− pattern: /'(?:\\[\s\S]|[^\\'])*'/,
1905− greedy: true
1906− },
2003+ Prism.languages.coffeescript = Prism.languages.extend('javascript', {
2004+ 'comment': comment,
2005+ 'string': [
19072006
1908− {
19092007 // Strings are multiline
1910− pattern: /"(?:\\[\s\S]|[^\\"])*"/,
1911− greedy: true,
1912− inside: {
1913− 'interpolation': interpolation
2008+ {
2009+ pattern: /'(?:\\[\s\S]|[^\\'])*'/,
2010+ greedy: true
2011+ },
2012+
2013+ {
2014+ // Strings are multiline
2015+ pattern: /"(?:\\[\s\S]|[^\\"])*"/,
2016+ greedy: true,
2017+ inside: {
2018+ 'interpolation': interpolation
2019+ }
19142020 }
2021+ ],
2022+ '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/,
2023+ 'class-member': {
2024+ pattern: /@(?!\d)\w+/,
2025+ alias: 'variable'
19152026 }
1916− ],
1917− '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/,
1918− 'class-member': {
1919− pattern: /@(?!\d)\w+/,
1920− alias: 'variable'
1921− }
1922−});
1923−
1924−Prism.languages.insertBefore('coffeescript', 'comment', {
1925− 'multiline-comment': {
1926− pattern: /###[\s\S]+?###/,
1927− alias: 'comment'
1928− },
2027+ });
19292028
1930− // Block regexp can contain comments and interpolation
1931− 'block-regex': {
1932− pattern: /\/{3}[\s\S]*?\/{3}/,
1933− alias: 'regex',
1934− inside: {
1935− 'comment': comment,
1936− 'interpolation': interpolation
1937− }
1938− }
1939−});
2029+ Prism.languages.insertBefore('coffeescript', 'comment', {
2030+ 'multiline-comment': {
2031+ pattern: /###[\s\S]+?###/,
2032+ alias: 'comment'
2033+ },
19402034
1941−Prism.languages.insertBefore('coffeescript', 'string', {
1942− 'inline-javascript': {
1943− pattern: /`(?:\\[\s\S]|[^\\`])*`/,
1944− inside: {
1945− 'delimiter': {
1946− pattern: /^`|`$/,
1947− alias: 'punctuation'
1948− },
1949− 'script': {
1950− pattern: /[\s\S]+/,
1951− alias: 'language-javascript',
1952− inside: Prism.languages.javascript
2035+ // Block regexp can contain comments and interpolation
2036+ 'block-regex': {
2037+ pattern: /\/{3}[\s\S]*?\/{3}/,
2038+ alias: 'regex',
2039+ inside: {
2040+ 'comment': comment,
2041+ 'interpolation': interpolation
19532042 }
19542043 }
1955− },
2044+ });
19562045
1957− // Block strings
1958− 'multiline-string': [
1959− {
1960− pattern: /'''[\s\S]*?'''/,
1961− greedy: true,
1962− alias: 'string'
1963− },
1964− {
1965− pattern: /"""[\s\S]*?"""/,
1966− greedy: true,
1967− alias: 'string',
2046+ Prism.languages.insertBefore('coffeescript', 'string', {
2047+ 'inline-javascript': {
2048+ pattern: /`(?:\\[\s\S]|[^\\`])*`/,
19682049 inside: {
1969− interpolation: interpolation
2050+ 'delimiter': {
2051+ pattern: /^`|`$/,
2052+ alias: 'punctuation'
2053+ },
2054+ 'script': {
2055+ pattern: /[\s\S]+/,
2056+ alias: 'language-javascript',
2057+ inside: Prism.languages.javascript
2058+ }
19702059 }
1971− }
1972− ]
2060+ },
19732061
1974−});
2062+ // Block strings
2063+ 'multiline-string': [
2064+ {
2065+ pattern: /'''[\s\S]*?'''/,
2066+ greedy: true,
2067+ alias: 'string'
2068+ },
2069+ {
2070+ pattern: /"""[\s\S]*?"""/,
2071+ greedy: true,
2072+ alias: 'string',
2073+ inside: {
2074+ interpolation: interpolation
2075+ }
2076+ }
2077+ ]
19752078
1976−Prism.languages.insertBefore('coffeescript', 'keyword', {
1977− // Object property
1978− 'property': /(?!\d)\w+(?=\s*:(?!:))/
1979−});
2079+ });
2080+
2081+ Prism.languages.insertBefore('coffeescript', 'keyword', {
2082+ // Object property
2083+ 'property': /(?!\d)\w+(?=\s*:(?!:))/
2084+ });
19802085
1981−delete Prism.languages.coffeescript['template-string'];
2086+ delete Prism.languages.coffeescript['template-string'];
19822087
1983−Prism.languages.coffee = Prism.languages.coffeescript;
2088+ Prism.languages.coffee = Prism.languages.coffeescript;
19842089 }(Prism));
19852090
19862091 /**
@@ -2025,22 +2130,25 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 38 unmodified lines
20252130 'regex': [
20262131 {
20272132 pattern: RegExp(/%r/.source + '(?:' + [
2028− /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[gim]{0,3}/.source,
2029− /\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/.source,
2133+ /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
2134+ /\((?:[^()\\]|\\[\s\S])*\)/.source,
20302135 // Here we need to specifically allow interpolation
2031− /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/.source,
2032− /\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/.source,
2033− /<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/.source
2034− ].join('|') + ')'),
2136+ /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,
2137+ /\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,
2138+ /<(?:[^<>\\]|\\[\s\S])*>/.source
2139+ ].join('|') + ')' + /[egimnosux]{0,6}/.source),
20352140 greedy: true,
20362141 inside: {
20372142 'interpolation': interpolation
20382143 }
20392144 },
20402145 {
2041− pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[gim]{0,3}(?=\s*(?:$|[\r\n,.;})]))/,
2146+ pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,
20422147 lookbehind: true,
2043− greedy: true
2148+ greedy: true,
2149+ inside: {
2150+ 'interpolation': interpolation
2151+ }
20442152 }
20452153 ],
20462154 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,
@@ -2084,13 +2192,42 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 37 unmodified lines
20842192 inside: {
20852193 'interpolation': interpolation
20862194 }
2195+ },
2196+ {
2197+ pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
2198+ alias: 'heredoc-string',
2199+ greedy: true,
2200+ inside: {
2201+ 'delimiter': {
2202+ pattern: /^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i,
2203+ alias: 'symbol',
2204+ inside: {
2205+ 'punctuation': /^<<[-~]?/
2206+ }
2207+ },
2208+ 'interpolation': interpolation
2209+ }
2210+ },
2211+ {
2212+ pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,
2213+ alias: 'heredoc-string',
2214+ greedy: true,
2215+ inside: {
2216+ 'delimiter': {
2217+ pattern: /^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i,
2218+ alias: 'symbol',
2219+ inside: {
2220+ 'punctuation': /^<<[-~]?'|'$/,
2221+ }
2222+ }
2223+ }
20872224 }
20882225 ];
20892226
20902227 Prism.languages.rb = Prism.languages.ruby;
20912228 }(Prism));
20922229
2093−(function(Prism) {
2230+(function (Prism) {
20942231 Prism.languages.crystal = Prism.languages.extend('ruby', {
20952232 keyword: [
20962233 /\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; · 20 unmodified lines
21172254 },
21182255
21192256 expansion: [
2120− {
2121− pattern: /\{\{.+?\}\}/,
2122− inside: {
2123− delimiter: {
2124− pattern: /^\{\{|\}\}$/,
2125− alias: 'tag'
2126− },
2127− rest: Prism.languages.crystal
2128− }
2129− },
2130− {
2131− pattern: /\{%.+?%\}/,
2132− inside: {
2133− delimiter: {
2134− pattern: /^\{%|%\}$/,
2135− alias: 'tag'
2136− },
2137− rest: Prism.languages.crystal
2257+ {
2258+ pattern: /\{\{.+?\}\}/,
2259+ inside: {
2260+ delimiter: {
2261+ pattern: /^\{\{|\}\}$/,
2262+ alias: 'tag'
2263+ },
2264+ rest: Prism.languages.crystal
2265+ }
2266+ },
2267+ {
2268+ pattern: /\{%.+?%\}/,
2269+ inside: {
2270+ delimiter: {
2271+ pattern: /^\{%|%\}$/,
2272+ alias: 'tag'
2273+ },
2274+ rest: Prism.languages.crystal
2275+ }
21382276 }
2139− }
21402277 ]
21412278 });
21422279
@@ -2223,30 +2360,73 @@ Prism.languages.insertBefore('d', 'function', { · 80 unmodified lines
22232360 }
22242361 });
22252362
2226−Prism.languages.dart = Prism.languages.extend('clike', {
2227− 'string': [
2228− {
2229− pattern: /r?("""|''')[\s\S]*?\1/,
2230− greedy: true
2231− },
2232− {
2233− pattern: /r?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
2234− greedy: true
2235− }
2236− ],
2237− 'keyword': [
2363+(function (Prism) {
2364+ var keywords = [
22382365 /\b(?:async|sync|yield)\*/,
2239− /\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/
2240− ],
2241− 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
2242−});
2366+ /\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/
2367+ ];
22432368
2244−Prism.languages.insertBefore('dart','function',{
2245− 'metadata': {
2246− pattern: /@\w+/,
2247− alias: 'symbol'
2248− }
2249−});
2369+ // Handles named imports, such as http.Client
2370+ var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
2371+
2372+ // based on the dart naming conventions
2373+ var className = {
2374+ pattern: RegExp(packagePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),
2375+ lookbehind: true,
2376+ inside: {
2377+ 'namespace': {
2378+ pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,
2379+ inside: {
2380+ 'punctuation': /\./
2381+ }
2382+ },
2383+ }
2384+ };
2385+
2386+ Prism.languages.dart = Prism.languages.extend('clike', {
2387+ 'string': [
2388+ {
2389+ pattern: /r?("""|''')[\s\S]*?\1/,
2390+ greedy: true
2391+ },
2392+ {
2393+ pattern: /r?(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,
2394+ greedy: true
2395+ }
2396+ ],
2397+ 'class-name': [
2398+ className,
2399+ {
2400+ // variables and parameters
2401+ // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods)
2402+ pattern: RegExp(packagePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source),
2403+ lookbehind: true,
2404+ inside: className.inside
2405+ }
2406+ ],
2407+ 'keyword': keywords,
2408+ 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
2409+ });
2410+
2411+ Prism.languages.insertBefore('dart', 'function', {
2412+ 'metadata': {
2413+ pattern: /@\w+/,
2414+ alias: 'symbol'
2415+ }
2416+ });
2417+
2418+ Prism.languages.insertBefore('dart', 'class-name', {
2419+ 'generics': {
2420+ pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
2421+ inside: {
2422+ 'class-name': className,
2423+ 'keyword': keywords,
2424+ 'punctuation': /[<>(),.:]/,
2425+ 'operator': /[?&|]/
2426+ }
2427+ },
2428+ });
2429+}(Prism));
22502430
22512431 (function (Prism) {
22522432
@@ -2285,8 +2465,8 @@ Prism.languages.insertBefore('dart','function',{ · 32 unmodified lines
22852465 if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"
22862466 alias.push(/\w+/.exec(name)[0]);
22872467 }
2288− if (name === "diff") {
2289− alias.push("bold");
2468+ if (name === 'diff') {
2469+ alias.push('bold');
22902470 }
22912471
22922472 Prism.languages.diff[name] = {
@@ -2354,8 +2534,9 @@ Prism.languages.insertBefore('dart','function',{ · 61 unmodified lines
23542534 var placeholder;
23552535
23562536 // Check for existing strings
2357− while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1)
2537+ while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) {
23582538 ++i;
2539+ }
23592540
23602541 // Create a sparse array
23612542 tokenStack[i] = match;
@@ -2496,10 +2677,20 @@ Prism.languages.insertBefore('dart','function',{ · 134 unmodified lines
24962677 markupTemplating.tokenizePlaceholders(env, 'jinja2');
24972678 });
24982679
2499−})(Prism);
2680+}(Prism));
25002681
25012682 Prism.languages.elixir = {
2502− 'comment': /#.*/m,
2683+ 'doc': {
2684+ pattern: /@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/,
2685+ inside: {
2686+ 'attribute': /^@\w+/,
2687+ 'string': /['"][\s\S]+/
2688+ }
2689+ },
2690+ 'comment': {
2691+ pattern: /#.*/m,
2692+ greedy: true
2693+ },
25032694 // ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo), ~r[foo], ~r{foo}, ~r<foo>
25042695 'regex': {
25052696 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 = { · 30 unmodified lines
25362727 lookbehind: true,
25372728 alias: 'symbol'
25382729 },
2730+ 'module': {
2731+ pattern: /\b[A-Z]\w*\b/,
2732+ alias: 'class-name'
2733+ },
25392734 // Look-ahead prevents bad highlighting of the :: operator
25402735 'attr-name': /\w+\??:(?!:)/,
2541− 'capture': {
2542− // Look-behind prevents bad highlighting of the && operator
2543− pattern: /(^|[^&])&(?:[^&\s\d()][^\s()]*|(?=\())/,
2544− lookbehind: true,
2545− alias: 'function'
2546− },
25472736 'argument': {
25482737 // Look-behind prevents bad highlighting of the && operator
25492738 pattern: /(^|[^&])&\d+/,
@@ -2554,8 +2743,9 @@ Prism.languages.elixir = { · 4 unmodified lines
25542743 pattern: /@\w+/,
25552744 alias: 'variable'
25562745 },
2746+ 'function': /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d+))/,
25572747 'number': /\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,
2558− '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/,
2748+ '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/,
25592749 'boolean': /\b(?:true|false|nil)\b/,
25602750 'operator': [
25612751 /\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,
@@ -2573,19 +2763,7 @@ Prism.languages.elixir = { · 11 unmodified lines
25732763 'punctuation': /<<|>>|[.,%\[\]{}()]/
25742764 };
25752765
2576−Prism.languages.insertBefore('elixir', 'keyword', {
2577− 'module': {
2578− pattern: /\b(defmodule\s)[A-Z][\w.\\]+/,
2579− lookbehind: true,
2580− alias: 'class-name'
2581− },
2582− 'function': {
2583− pattern: /\b(defp?\s)[\w.\\]+/,
2584− lookbehind: true
2585− }
2586−});
2587−
2588−Prism.languages.elixir.string.forEach(function(o) {
2766+Prism.languages.elixir.string.forEach(function (o) {
25892767 o.inside = {
25902768 'interpolation': {
25912769 pattern: /#\{[^}]+\}/,
@@ -2701,7 +2879,7 @@ Prism.languages.insertBefore('groovy', 'function', { · 109 unmodified lines
27012879 });
27022880
27032881 // Handle string interpolation
2704−Prism.hooks.add('wrap', function(env) {
2882+Prism.hooks.add('wrap', function (env) {
27052883 if (env.language === 'groovy' && env.type === 'string') {
27062884 var delimiter = env.content[0];
27072885
@@ -2791,7 +2969,7 @@ Prism.hooks.add('wrap', function(env) { · 83 unmodified lines
27912969 alias: 'punctuation'
27922970 },
27932971 'generics': {
2794− pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,
2972+ pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,
27952973 inside: {
27962974 'class-name': className,
27972975 'keyword': keywords,
@@ -2893,7 +3071,7 @@ Prism.languages.julia = { · 95 unmodified lines
28933071 'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/
28943072 });
28953073
2896− delete Prism.languages.kotlin["class-name"];
3074+ delete Prism.languages.kotlin['class-name'];
28973075
28983076 Prism.languages.insertBefore('kotlin', 'string', {
28993077 'raw-string': {
@@ -2940,6 +3118,71 @@ Prism.languages.julia = { · 40 unmodified lines
29403118 Prism.languages.kts = Prism.languages.kotlin;
29413119 }(Prism));
29423120
3121+(function (Prism) {
3122+ var funcPattern = /\\(?:[^a-z()[\]]|[a-z*]+)/i;
3123+ var insideEqu = {
3124+ 'equation-command': {
3125+ pattern: funcPattern,
3126+ alias: 'regex'
3127+ }
3128+ };
3129+
3130+ Prism.languages.latex = {
3131+ 'comment': /%.*/m,
3132+ // the verbatim environment prints whitespace to the document
3133+ 'cdata': {
3134+ pattern: /(\\begin\{((?:verbatim|lstlisting)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
3135+ lookbehind: true
3136+ },
3137+ /*
3138+ * equations can be between $$ $$ or $ $ or \( \) or \[ \]
3139+ * (all are multiline)
3140+ */
3141+ 'equation': [
3142+ {
3143+ pattern: /\$\$(?:\\[\s\S]|[^\\$])+\$\$|\$(?:\\[\s\S]|[^\\$])+\$|\\\([\s\S]*?\\\)|\\\[[\s\S]*?\\\]/,
3144+ inside: insideEqu,
3145+ alias: 'string'
3146+ },
3147+ {
3148+ pattern: /(\\begin\{((?:equation|math|eqnarray|align|multline|gather)\*?)\})[\s\S]*?(?=\\end\{\2\})/,
3149+ lookbehind: true,
3150+ inside: insideEqu,
3151+ alias: 'string'
3152+ }
3153+ ],
3154+ /*
3155+ * arguments which are keywords or references are highlighted
3156+ * as keywords
3157+ */
3158+ 'keyword': {
3159+ pattern: /(\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,
3160+ lookbehind: true
3161+ },
3162+ 'url': {
3163+ pattern: /(\\url\{)[^}]+(?=\})/,
3164+ lookbehind: true
3165+ },
3166+ /*
3167+ * section or chapter headlines are highlighted as bold so that
3168+ * they stand out more
3169+ */
3170+ 'headline': {
3171+ pattern: /(\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\}(?:\[[^\]]+\])?)/,
3172+ lookbehind: true,
3173+ alias: 'class-name'
3174+ },
3175+ 'function': {
3176+ pattern: funcPattern,
3177+ alias: 'selector'
3178+ },
3179+ 'punctuation': /[[\]{}&]/
3180+ };
3181+
3182+ Prism.languages.tex = Prism.languages.latex;
3183+ Prism.languages.context = Prism.languages.latex;
3184+}(Prism));
3185+
29433186 Prism.languages.lua = {
29443187 'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,
29453188 // \z may be used to skip the following space
@@ -2978,17 +3221,58 @@ Prism.languages.matlab = { · 32 unmodified lines
29783221 'punctuation': /\.{3}|[.,;\[\](){}!]/
29793222 };
29803223
2981−Prism.languages.nginx = Prism.languages.extend('clike', {
2982− 'comment': {
2983− pattern: /(^|[^"{\\])#.*/,
2984− lookbehind: true
2985− },
2986− '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_size|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_transparency|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|perl_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|proxy_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
2987−});
3224+(function (Prism) {
29883225
2989−Prism.languages.insertBefore('nginx', 'keyword', {
2990− 'variable': /\$[a-z_]+/i
2991−});
3226+ var variable = /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;
3227+
3228+ Prism.languages.nginx = {
3229+ 'comment': {
3230+ pattern: /(^|[\s{};])#.*/,
3231+ lookbehind: true
3232+ },
3233+ 'directive': {
3234+ pattern: /(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/,
3235+ lookbehind: true,
3236+ greedy: true,
3237+ inside: {
3238+ 'string': {
3239+ pattern: /((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,
3240+ lookbehind: true,
3241+ inside: {
3242+ 'escape': {
3243+ pattern: /\\["'\\nrt]/,
3244+ alias: 'entity'
3245+ },
3246+ 'variable': variable
3247+ }
3248+ },
3249+ 'comment': {
3250+ pattern: /(\s)#.*/,
3251+ lookbehind: true,
3252+ greedy: true
3253+ },
3254+ 'keyword': {
3255+ pattern: /^\S+/,
3256+ greedy: true
3257+ },
3258+
3259+ // other patterns
3260+
3261+ 'boolean': {
3262+ pattern: /(\s)(?:off|on)(?!\S)/,
3263+ lookbehind: true
3264+ },
3265+ 'number': {
3266+ pattern: /(\s)\d+[a-z]*(?!\S)/i,
3267+ lookbehind: true
3268+ },
3269+ 'variable': variable
3270+ }
3271+ },
3272+ 'punctuation': /[{};]/
3273+ };
3274+
3275+}(Prism));
29923276
29933277 Prism.languages.nim = {
29943278 'comment': /#.*/,
@@ -3023,6 +3307,7 @@ Prism.languages.nim = { · 28 unmodified lines
30233307 },
30243308 'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/
30253309 };
3310+
30263311 Prism.languages.ocaml = {
30273312 'comment': /\(\*[\s\S]*?\*\)/,
30283313 'string': [
@@ -3228,7 +3513,7 @@ Prism.languages.perl = { · 199 unmodified lines
32283513 // ${...}
32293514 /[&*$@%]#?(?=\{)/,
32303515 // $foo
3231− /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i,
3516+ /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/i,
32323517 // $1
32333518 /[&*$@%]\d+/,
32343519 // $_, @_, %!
@@ -3271,8 +3556,18 @@ Prism.languages.perl = { · 36 unmodified lines
32713556 pattern: /\b(?:false|true)\b/i,
32723557 alias: 'boolean'
32733558 },
3274− /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
3559+ {
3560+ pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,
3561+ greedy: true,
3562+ lookbehind: true,
3563+ },
3564+ {
3565+ pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,
3566+ greedy: true,
3567+ lookbehind: true,
3568+ },
32753569 /\b(?:null)\b/i,
3570+ /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
32763571 ];
32773572 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;
32783573 var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
@@ -3297,6 +3592,11 @@ Prism.languages.perl = { · 18 unmodified lines
32973592 lookbehind: true,
32983593 alias: 'class-name'
32993594 },
3595+ 'function-definition': {
3596+ pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
3597+ lookbehind: true,
3598+ alias: 'function'
3599+ },
33003600 'keyword': [
33013601 {
33023602 pattern: /(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,
@@ -3344,9 +3644,26 @@ Prism.languages.perl = { · 41 unmodified lines
33443644 alias: 'static-context',
33453645 greedy: true
33463646 },
3347− /\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
3647+ {
3648+ // yield from
3649+ pattern: /(\byield\s+)from\b/i,
3650+ lookbehind: true
3651+ },
3652+ // `class` is always a keyword unlike other keywords
3653+ /\bclass\b/i,
3654+ {
3655+ // https://www.php.net/manual/en/reserved.keywords.php
3656+ //
3657+ // keywords cannot be preceded by "->"
3658+ // the complex lookbehind means `(?<!(?:->|::)\s*)`
3659+ 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,
3660+ lookbehind: true
3661+ }
33483662 ],
3349− 'argument-name': /\b[a-z_]\w*(?=\s*:(?!:))/i,
3663+ 'argument-name': {
3664+ pattern: /([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,
3665+ lookbehind: true
3666+ },
33503667 'class-name': [
33513668 {
33523669 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 = { · 93 unmodified lines
34463763 }
34473764 ],
34483765 'constant': constant,
3449− 'function': /\w+\s*(?=\()/,
3766+ 'function': {
3767+ pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
3768+ lookbehind: true,
3769+ inside: {
3770+ 'punctuation': /\\/
3771+ }
3772+ },
34503773 'property': {
3451− pattern: /(->)[\w]+/,
3774+ pattern: /(->\s*)\w+/,
34523775 lookbehind: true
34533776 },
34543777 'number': number,
@@ -3457,7 +3780,7 @@ Prism.languages.perl = { · 2 unmodified lines
34573780 };
34583781
34593782 var string_interpolation = {
3460− pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)*)/,
3783+ pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
34613784 lookbehind: true,
34623785 inside: Prism.languages.php
34633786 };
@@ -3489,7 +3812,7 @@ Prism.languages.perl = { · 25 unmodified lines
34893812 'punctuation': /^<<<"?|[";]$/
34903813 }
34913814 },
3492− 'interpolation': string_interpolation // See below
3815+ 'interpolation': string_interpolation
34933816 }
34943817 },
34953818 {
@@ -3507,16 +3830,13 @@ Prism.languages.perl = { · 11 unmodified lines
35073830 alias: 'double-quoted-string',
35083831 greedy: true,
35093832 inside: {
3510− 'interpolation': string_interpolation // See below
3833+ 'interpolation': string_interpolation
35113834 }
35123835 }
35133836 ];
35143837
35153838 Prism.languages.insertBefore('php', 'variable', {
35163839 'string': string,
3517− });
3518−
3519− Prism.languages.insertBefore('php', 'variable', {
35203840 'attribute': {
35213841 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/mi,
35223842 greedy: true,
@@ -3562,7 +3882,7 @@ Prism.languages.perl = { · 39 unmodified lines
35623882 },
35633883 });
35643884
3565− Prism.hooks.add('before-tokenize', function(env) {
3885+ Prism.hooks.add('before-tokenize', function (env) {
35663886 if (!/<\?/.test(env.code)) {
35673887 return;
35683888 }
@@ -3571,7 +3891,7 @@ Prism.languages.perl = { · 2 unmodified lines
35713891 Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
35723892 });
35733893
3574− Prism.hooks.add('after-tokenize', function(env) {
3894+ Prism.hooks.add('after-tokenize', function (env) {
35753895 Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
35763896 });
35773897
@@ -3642,149 +3962,149 @@ Prism.languages.python['string-interpolation'].inside['interpolation'].inside.re · 64 unmodified lines
36423962
36433963 Prism.languages.py = Prism.languages.python;
36443964
3645−(function(Prism) {
3965+(function (Prism) {
36463966
3647−var javascript = Prism.util.clone(Prism.languages.javascript);
3967+ var javascript = Prism.util.clone(Prism.languages.javascript);
36483968
3649−var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
3650−var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
3651−var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
3969+ var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
3970+ var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
3971+ var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
36523972
3653−/**
3654− * @param {string} source
3655− * @param {string} [flags]
3656− */
3657−function re(source, flags) {
3658− source = source
3659− .replace(/<S>/g, function () { return space; })
3660− .replace(/<BRACES>/g, function () { return braces; })
3661− .replace(/<SPREAD>/g, function () { return spread; });
3662− return RegExp(source, flags);
3663−}
3973+ /**
3974+ * @param {string} source
3975+ * @param {string} [flags]
3976+ */
3977+ function re(source, flags) {
3978+ source = source
3979+ .replace(/<S>/g, function () { return space; })
3980+ .replace(/<BRACES>/g, function () { return braces; })
3981+ .replace(/<SPREAD>/g, function () { return spread; });
3982+ return RegExp(source, flags);
3983+ }
36643984
3665−spread = re(spread).source;
3985+ spread = re(spread).source;
36663986
36673987
3668−Prism.languages.jsx = Prism.languages.extend('markup', javascript);
3669−Prism.languages.jsx.tag.pattern = re(
3670− /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
3671−);
3988+ Prism.languages.jsx = Prism.languages.extend('markup', javascript);
3989+ Prism.languages.jsx.tag.pattern = re(
3990+ /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
3991+ );
36723992
3673−Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
3674−Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
3675−Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
3676−Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
3993+ Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
3994+ Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
3995+ Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
3996+ Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
36773997
3678−Prism.languages.insertBefore('inside', 'attr-name', {
3679− 'spread': {
3680− pattern: re(/<SPREAD>/.source),
3681− inside: Prism.languages.jsx
3682− }
3683−}, Prism.languages.jsx.tag);
3998+ Prism.languages.insertBefore('inside', 'attr-name', {
3999+ 'spread': {
4000+ pattern: re(/<SPREAD>/.source),
4001+ inside: Prism.languages.jsx
4002+ }
4003+ }, Prism.languages.jsx.tag);
36844004
3685−Prism.languages.insertBefore('inside', 'attr-value',{
3686− 'script': {
3687− // Allow for two levels of nesting
3688− pattern: re(/=<BRACES>/.source),
3689− inside: {
3690− 'script-punctuation': {
3691− pattern: /^=(?={)/,
3692− alias: 'punctuation'
4005+ Prism.languages.insertBefore('inside', 'special-attr', {
4006+ 'script': {
4007+ // Allow for two levels of nesting
4008+ pattern: re(/=<BRACES>/.source),
4009+ inside: {
4010+ 'script-punctuation': {
4011+ pattern: /^=(?={)/,
4012+ alias: 'punctuation'
4013+ },
4014+ rest: Prism.languages.jsx
36934015 },
3694− rest: Prism.languages.jsx
3695− },
3696− 'alias': 'language-javascript'
3697− }
3698−}, Prism.languages.jsx.tag);
4016+ 'alias': 'language-javascript'
4017+ }
4018+ }, Prism.languages.jsx.tag);
36994019
3700−// The following will handle plain text inside tags
3701−var stringifyToken = function (token) {
3702− if (!token) {
3703− return '';
3704− }
3705− if (typeof token === 'string') {
3706− return token;
3707− }
3708− if (typeof token.content === 'string') {
3709− return token.content;
3710− }
3711− return token.content.map(stringifyToken).join('');
3712−};
4020+ // The following will handle plain text inside tags
4021+ var stringifyToken = function (token) {
4022+ if (!token) {
4023+ return '';
4024+ }
4025+ if (typeof token === 'string') {
4026+ return token;
4027+ }
4028+ if (typeof token.content === 'string') {
4029+ return token.content;
4030+ }
4031+ return token.content.map(stringifyToken).join('');
4032+ };
37134033
3714−var walkTokens = function (tokens) {
3715− var openedTags = [];
3716− for (var i = 0; i < tokens.length; i++) {
3717− var token = tokens[i];
3718− var notTagNorBrace = false;
3719−
3720− if (typeof token !== 'string') {
3721− if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
3722− // We found a tag, now find its kind
3723−
3724− if (token.content[0].content[0].content === '</') {
3725− // Closing tag
3726− if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
3727− // Pop matching opening tag
3728− openedTags.pop();
3729− }
3730− } else {
3731− if (token.content[token.content.length - 1].content === '/>') {
3732− // Autoclosed tag, ignore
4034+ var walkTokens = function (tokens) {
4035+ var openedTags = [];
4036+ for (var i = 0; i < tokens.length; i++) {
4037+ var token = tokens[i];
4038+ var notTagNorBrace = false;
4039+
4040+ if (typeof token !== 'string') {
4041+ if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
4042+ // We found a tag, now find its kind
4043+
4044+ if (token.content[0].content[0].content === '</') {
4045+ // Closing tag
4046+ if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
4047+ // Pop matching opening tag
4048+ openedTags.pop();
4049+ }
37334050 } else {
3734− // Opening tag
3735− openedTags.push({
3736− tagName: stringifyToken(token.content[0].content[1]),
3737− openedBraces: 0
3738− });
4051+ if (token.content[token.content.length - 1].content === '/>') {
4052+ // Autoclosed tag, ignore
4053+ } else {
4054+ // Opening tag
4055+ openedTags.push({
4056+ tagName: stringifyToken(token.content[0].content[1]),
4057+ openedBraces: 0
4058+ });
4059+ }
37394060 }
3740− }
3741− } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
4061+ } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
37424062
3743− // Here we might have entered a JSX context inside a tag
3744− openedTags[openedTags.length - 1].openedBraces++;
4063+ // Here we might have entered a JSX context inside a tag
4064+ openedTags[openedTags.length - 1].openedBraces++;
37454065
3746− } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
4066+ } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
37474067
3748− // Here we might have left a JSX context inside a tag
3749− openedTags[openedTags.length - 1].openedBraces--;
4068+ // Here we might have left a JSX context inside a tag
4069+ openedTags[openedTags.length - 1].openedBraces--;
37504070
3751− } else {
3752− notTagNorBrace = true
3753− }
3754− }
3755− if (notTagNorBrace || typeof token === 'string') {
3756− if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
3757− // Here we are inside a tag, and not inside a JSX context.
3758− // That's plain text: drop any tokens matched.
3759− var plainText = stringifyToken(token);
3760−
3761− // And merge text with adjacent text
3762− if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
3763− plainText += stringifyToken(tokens[i + 1]);
3764− tokens.splice(i + 1, 1);
4071+ } else {
4072+ notTagNorBrace = true;
37654073 }
3766− if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
3767− plainText = stringifyToken(tokens[i - 1]) + plainText;
3768− tokens.splice(i - 1, 1);
3769− i--;
4074+ }
4075+ if (notTagNorBrace || typeof token === 'string') {
4076+ if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
4077+ // Here we are inside a tag, and not inside a JSX context.
4078+ // That's plain text: drop any tokens matched.
4079+ var plainText = stringifyToken(token);
4080+
4081+ // And merge text with adjacent text
4082+ if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
4083+ plainText += stringifyToken(tokens[i + 1]);
4084+ tokens.splice(i + 1, 1);
4085+ }
4086+ if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
4087+ plainText = stringifyToken(tokens[i - 1]) + plainText;
4088+ tokens.splice(i - 1, 1);
4089+ i--;
4090+ }
4091+
4092+ tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
37704093 }
4094+ }
37714095
3772− tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
4096+ if (token.content && typeof token.content !== 'string') {
4097+ walkTokens(token.content);
37734098 }
37744099 }
4100+ };
37754101
3776− if (token.content && typeof token.content !== 'string') {
3777− walkTokens(token.content);
4102+ Prism.hooks.add('after-tokenize', function (env) {
4103+ if (env.language !== 'jsx' && env.language !== 'tsx') {
4104+ return;
37784105 }
3779− }
3780−};
3781−
3782−Prism.hooks.add('after-tokenize', function (env) {
3783− if (env.language !== 'jsx' && env.language !== 'tsx') {
3784− return;
3785− }
3786− walkTokens(env.tokens);
3787−});
4106+ walkTokens(env.tokens);
4107+ });
37884108
37894109 }(Prism));
37904110
@@ -4007,17 +4327,26 @@ Prism.languages.scss['atrule'].inside.rest = Prism.languages.scss; · 216 unmodified lines
40074327
40084328 var strings = [
40094329 // normal string
4010− // 1 capturing group
4011− /(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\1)[^\\`$])*\1/.source,
4330+ /"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,
4331+ /'[^']*'/.source,
4332+ /\$'(?:[^'\\]|\\[\s\S])*'/.source,
40124333
40134334 // here doc
40144335 // 2 capturing groups
4015− /<<-?\s*(["']?)(\w+)\2\s[\s\S]*?[\r\n]\3/.source
4336+ /<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source
40164337 ].join('|');
40174338
40184339 Prism.languages['shell-session'] = {
40194340 'command': {
4020− pattern: RegExp(/^(?:[^\s@:$#*!/\\]+@[^\s@:$#*!/\\]+(?::[^\0-\x1F$#*?"<>:;|]+)?|[^\0-\x1F$#*?"<>:;|]+)?[$#](?:[^\\\r\n'"<]|\\.|<<str>>)+/.source.replace(/<<str>>/g, function () { return strings; }), 'm'),
4341+ pattern: RegExp(
4342+ // user info
4343+ /^(?:[^\s@:$#*!/\\]+@[^\s@:$#*!/\\]+(?::[^\0-\x1F$#*?"<>:;|]+)?|[^\0-\x1F$#*?"<>:;|]+)?/.source +
4344+ // shell symbol
4345+ /[$#]/.source +
4346+ // bash command
4347+ /(?:[^\\\r\n'"<$]|\\(?:[^\r]|\r\n?)|\$(?!')|<<str>>)+/.source.replace(/<<str>>/g, function () { return strings; }),
4348+ 'm'
4349+ ),
40214350 greedy: true,
40224351 inside: {
40234352 'info': {
@@ -4085,11 +4414,16 @@ Prism.languages.sql = { · 61 unmodified lines
40854414 greedy: true,
40864415 inside: null // see below
40874416 },
4088− // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words
4089− '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/,
40904417 'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,
40914418 });
40924419
4420+ // The keywords TypeScript adds to JavaScript
4421+ Prism.languages.typescript.keyword.push(
4422+ /\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\b/,
4423+ // keywords that have to be followed by an identifier
4424+ /\b(?:asserts|infer|interface|module|namespace|type)(?!\s*[^\s_${}*a-zA-Z\xA0-\uFFFF])/
4425+ );
4426+
40934427 // doesn't work with TS because TS is too complex
40944428 delete Prism.languages.typescript['parameter'];
40954429
@@ -4100,6 +4434,16 @@ Prism.languages.sql = { · 4 unmodified lines
41004434 Prism.languages.typescript['class-name'].inside = typeInside;
41014435
41024436 Prism.languages.insertBefore('typescript', 'function', {
4437+ 'decorator': {
4438+ pattern: /@[$\w\xA0-\uFFFF]+/,
4439+ inside: {
4440+ 'at': {
4441+ pattern: /^@/,
4442+ alias: 'operator'
4443+ },
4444+ 'function': /^[\s\S]+/
4445+ }
4446+ },
41034447 'generic-function': {
41044448 // e.g. foo<T extends "bar" | "baz">( ...
41054449 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
@@ -4146,7 +4490,7 @@ Prism.languages.sql = { · 40 unmodified lines
41464490 flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag
41474491 var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|]|}|(?:[\r\n]\s*)?#))/.source
41484492 .replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g, function () { return value; });
4149− return RegExp(pattern, flags)
4493+ return RegExp(pattern, flags);
41504494 }
41514495
41524496 Prism.languages.yaml = {
@@ -4202,4 +4546,3 @@ Prism.languages.sql = { · 49 unmodified lines
42024546 Prism.languages.yml = Prism.languages.yaml;
42034547
42044548 }(Prism));
4205−
lib/docs/filters/latex/clean_html.rb+5−0
@@ -13,6 +13,11 @@ module Docs · 12 unmodified lines
1313
1414 css('h1, h2, h3, h4').each { |node| node.content = node.content.sub /^[0-9A-Z]+(\.[0-9]+)* /, '' }
1515
16+ css('pre').each do |node|
17+ node.delete 'class'
18+ node['data-language'] = 'latex'
19+ end
20+
1621 doc
1722 end
1823 end