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 @@
1/* PrismJS 1.23.01/* PrismJS 1.23.0
2https://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 */2https://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 */
3/// <reference lib="WebWorker"/>3/// <reference lib="WebWorker"/>
4 4
5var _self = (typeof window !== 'undefined')5var _self = (typeof window !== 'undefined')
6 ? window // if in browser6 ? window // if in browser
7 : (7 : (
8 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)8 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
9 ? self // if in worker9 ? self // if in worker
10 : {} // if in node js10 : {} // if in node js
11 );11 );
12 12
13/**13/**
@@ -18,1133 +18,1151 @@ var _self = (typeof window !== 'undefined') · 4 unmodified lines
18 * @namespace18 * @namespace
19 * @public19 * @public
20 */20 */
21var Prism = (function (_self){21var Prism = (function (_self) {
22 22
23// Private helper vars23 // Private helper vars
24var lang = /\blang(?:uage)?-([\w-]+)\b/i;24 var lang = /\blang(?:uage)?-([\w-]+)\b/i;
25var uniqueId = 0;25 var uniqueId = 0;
26 26
27 // The grammar object for plaintext
28 var plainTextGrammar = {};
27 29
28var _ = {
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 },
72 30
31 var _ = {
73 /**32 /**
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.
75 *36 *
76 * @param {any} o37 * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
77 * @returns {string}38 *
78 * @example39 * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
79 * type(null) === 'Null'40 * empty Prism object into the global scope before loading the Prism script like this:
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.
95 *41 *
96 * @param {Object} obj42 * ```js
97 * @returns {number}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
98 */52 */
99 objId: function (obj) {53 manual: _self.Prism && _self.Prism.manual,
100 if (!obj['__id']) {54 disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
101 Object.defineProperty(obj, '__id', { value: ++uniqueId });
102 }
103 return obj['__id'];
104 },
105 55
106 /**56 /**
107 * Creates a deep clone of the given object.57 * A namespace for utility methods.
108 *58 *
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.
110 *61 *
111 * @param {T} o62 * @namespace
112 * @param {Record<number, any>} [visited]63 * @memberof Prism
113 * @returns {T}
114 * @template T
115 */64 */
116 clone: function deepClone(o, visited) {65 util: {
117 visited = visited || {};66 encode: function encode(tokens) {
118 67 if (tokens instanceof Token) {
119 var clone, id;68 return new Token(tokens.type, encode(tokens.content), tokens.alias);
120 switch (_.util.type(o)) {69 } else if (Array.isArray(tokens)) {
121 case 'Object':70 return tokens.map(encode);
122 id = _.util.objId(o);71 } else {
123 if (visited[id]) {72 return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
124 return visited[id];73 }
125 }74 },
126 clone = /** @type {Record<string, any>} */ ({});75
127 visited[id] = clone;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 },
128 108
129 for (var key in o) {109 /**
130 if (o.hasOwnProperty(key)) {110 * Creates a deep clone of the given object.
131 clone[key] = deepClone(o[key], visited);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];
132 }128 }
133 }129 clone = /** @type {Record<string, any>} */ ({});
130 visited[id] = clone;
134 131
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 }
136 137
137 case 'Array':138 return /** @type {any} */ (clone);
138 id = _.util.objId(o);
139 if (visited[id]) {
140 return visited[id];
141 }
142 clone = [];
143 visited[id] = clone;
144 139
145 (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {140 case 'Array':
146 clone[i] = deepClone(v, visited);141 id = _.util.objId(o);
147 });142 if (visited[id]) {
143 return visited[id];
144 }
145 clone = [];
146 visited[id] = clone;
148 147
149 return /** @type {any} */ (clone);148 (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
149 clone[i] = deepClone(v, visited);
150 });
150 151
151 default:152 return /** @type {any} */ (clone);
152 return o;
153 }
154 },
155 153
156 /**154 default:
157 * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.155 return o;
158 *156 }
159 * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.157 },
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 },
173 158
174 /**159 /**
175 * Returns the script element that is currently executing.160 * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
176 *161 *
177 * This does __not__ work for line script element.162 * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
178 *163 *
179 * @returns {HTMLScriptElement | null}164 * @param {Element} element
180 */165 * @returns {string}
181 currentScript: function () {166 */
182 if (typeof document === 'undefined') {167 getLanguage: function (element) {
183 return null;168 while (element && !lang.test(element.className)) {
184 }169 element = element.parentElement;
185 if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {170 }
186 return /** @type {any} */ (document.currentScript);171 if (element) {
187 }172 return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
173 }
174 return 'none';
175 },
188 176
189 // IE11 workaround177 /**
190 // we'll get the src of the current script by parsing IE11's error stack trace178 * Returns the script element that is currently executing.
191 // this will not work for inline scripts179 *
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 }
192 191
193 try {192 // IE11 workaround
194 throw new Error();193 // we'll get the src of the current script by parsing IE11's error stack trace
195 } catch (err) {194 // this will not work for inline scripts
196 // Get file src url from stack. Specifically works with the format of stack traces in IE.195
197 // A stack will look like this:196 try {
198 //197 throw new Error();
199 // Error198 } catch (err) {
200 // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)199 // Get file src url from stack. Specifically works with the format of stack traces in IE.
201 // at Global code (http://localhost/components/prism-core.js:606:1)200 // A stack will look like this:
202 201 //
203 var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];202 // Error
204 if (src) {203 // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
205 var scripts = document.getElementsByTagName('script');204 // at Global code (http://localhost/components/prism-core.js:606:1)
206 for (var i in scripts) {205
207 if (scripts[i].src == src) {206 var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
208 return scripts[i];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 }
209 }213 }
210 }214 }
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;
211 }250 }
212 return null;251 return !!defaultActivation;
213 }252 }
214 },253 },
215 254
216 /**255 /**
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.
218 *257 *
219 * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated258 * @namespace
220 * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the259 * @memberof Prism
221 * given class is just the given class with a `no-` prefix.260 * @public
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}
234 */261 */
235 isActive: function (element, className, defaultActivation) {262 languages: {
236 var no = 'no-' + className;263 /**
264 * The grammar for plain, unformatted text.
265 */
266 plain: plainTextGrammar,
267 plaintext: plainTextGrammar,
268 text: plainTextGrammar,
269 txt: plainTextGrammar,
237 270
238 while (element) {271 /**
239 var classList = element.classList;272 * Creates a deep copy of the language with the given id and appends the given tokens.
240 if (classList.contains(className)) {273 *
241 return true;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 }
242 }406 }
243 if (classList.contains(no)) {407
244 return false;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 }
245 }442 }
246 element = element.parentElement;
247 }443 }
248 return !!defaultActivation;444 },
249 }445
250 },446 plugins: {},
251 447
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: {
260 /**448 /**
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.
262 *452 *
263 * If a token in `redef` also appears in the copied language, then the existing token in the copied language453 * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
264 * will be overwritten at its original position.
265 *454 *
266 * ## Best practices455 * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
267 *456 * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
268 * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)457 * @memberof Prism
269 * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to458 * @public
270 * understand the language definition because, normally, the order of tokens matters in Prism grammars.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.
271 *467 *
272 * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.468 * The following hooks will be run:
273 * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.469 * 1. `before-highlightall`
470 * 2. `before-all-elements-highlight`
471 * 3. All hooks of {@link Prism.highlightElement} for each element.
274 *472 *
275 * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.473 * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
276 * @param {Grammar} redef The new tokens to append.474 * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
277 * @returns {Grammar} The new language created.475 * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
476 * @memberof Prism
278 * @public477 * @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 * });
287 */478 */
288 extend: function (id, redef) {479 highlightAllUnder: function (container, async, callback) {
289 var lang = _.util.clone(_.languages[id]);480 var env = {
481 callback: callback,
482 container: container,
483 selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
484 };
290 485
291 for (var key in redef) {486 _.hooks.run('before-highlightall', env);
292 lang[key] = redef[key];
293 }
294 487
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 }
296 },495 },
297 496
298 /**497 /**
299 * Inserts tokens _before_ another token in a language definition or any other grammar.498 * Highlights the code inside a single element.
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.
350 *499 *
351 * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if500 * The following hooks will be run:
352 * you hold the target object in a variable, then the value of the variable will not change.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`
353 *507 *
354 * ```js508 * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
355 * var oldMarkup = Prism.languages.markup;509 * the element's language.
356 * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
357 *
358 * assert(oldMarkup !== Prism.languages.markup);
359 * assert(newMarkup === Prism.languages.markup);
360 * ```
361 *510 *
362 * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the511 * @param {Element} element The element containing the code.
363 * object to be modified.512 * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
364 * @param {string} before The key to insert before.513 * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
365 * @param {Grammar} insert An object containing the key-value pairs to be inserted.514 * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
366 * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the515 * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
367 * object to be modified.
368 *516 *
369 * Defaults to `Prism.languages`.517 * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
370 * @returns {Grammar} The new grammar object.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
371 * @public523 * @public
372 */524 */
373 insertBefore: function (inside, before, insert, root) {525 highlightElement: function (element, async, callback) {
374 root = root || /** @type {any} */ (_.languages);526 // Find language
375 var grammar = root[inside];527 var language = _.util.getLanguage(element);
376 /** @type {Grammar} */528 var grammar = _.languages[language];
377 var ret = {};529
378 530 // Set language on the element, if not present
379 for (var token in grammar) {531 element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
380 if (grammar.hasOwnProperty(token)) {532
381 533 // Set language on the parent, for styling
382 if (token == before) {534 var parent = element.parentElement;
383 for (var newToken in insert) {535 if (parent && parent.nodeName.toLowerCase() === 'pre') {
384 if (insert.hasOwnProperty(newToken)) {536 parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
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 }
395 }537 }
396 538
397 var old = root[inside];539 var code = element.textContent;
398 root[inside] = ret;
399 540
400 // Update references in other language definitions541 var env = {
401 _.languages.DFS(_.languages, function(key, value) {542 element: element,
402 if (value === old && key != inside) {543 language: language,
403 this[key] = ret;544 grammar: grammar,
404 }545 code: code
405 });546 };
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 || {};
413 547
414 var objId = _.util.objId;548 function insertHighlightedCode(highlightedCode) {
549 env.highlightedCode = highlightedCode;
415 550
416 for (var i in o) {551 _.hooks.run('before-insert', env);
417 if (o.hasOwnProperty(i)) {
418 callback.call(o, i, o[i], type || i);
419 552
420 var property = o[i],553 env.element.innerHTML = env.highlightedCode;
421 propertyType = _.util.type(property);
422 554
423 if (propertyType === 'Object' && !visited[objId(property)]) {555 _.hooks.run('after-highlight', env);
424 visited[objId(property)] = true;556 _.hooks.run('complete', env);
425 DFS(property, callback, null, visited);557 callback && callback.call(env.element);
426 }
427 else if (propertyType === 'Array' && !visited[objId(property)]) {
428 visited[objId(property)] = true;
429 DFS(property, callback, i, visited);
430 }
431 }
432 }558 }
433 }
434 },
435 559
436 plugins: {},560 _.hooks.run('before-sanity-check', env);
437 561
438 /**562 // plugins may change/add the parent/element
439 * This is the most high-level function in Prism’s API.563 parent = env.element.parentElement;
440 * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on564 if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
441 * each one of them.565 parent.setAttribute('tabindex', '0');
442 *566 }
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);
477 567
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 }
479 573
480 _.hooks.run('before-all-elements-highlight', env);574 _.hooks.run('before-highlight', env);
481 575
482 for (var i = 0, element; element = env.elements[i++];) {576 if (!env.grammar) {
483 _.highlightElement(element, async === true, env.callback);577 insertHighlightedCode(_.util.encode(env.code));
484 }578 return;
485 },579 }
486 580
487 /**581 if (async && _self.Worker) {
488 * Highlights the code inside a single element.582 var worker = new Worker(_.filename);
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 }
528 583
529 var code = element.textContent;584 worker.onmessage = function (evt) {
585 insertHighlightedCode(evt.data);
586 };
530 587
531 var env = {588 worker.postMessage(JSON.stringify({
532 element: element,589 language: env.language,
533 language: language,590 code: env.code,
534 grammar: grammar,591 immediateClose: true
535 code: code592 }));
536 };593 } else {
594 insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
595 }
596 },
537 597
538 function insertHighlightedCode(highlightedCode) {598 /**
539 env.highlightedCode = highlightedCode;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 },
540 629
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 }
542 660
543 env.element.innerHTML = env.highlightedCode;661 delete grammar.rest;
662 }
544 663
545 _.hooks.run('after-highlight', env);664 var tokenList = new LinkedList();
546 _.hooks.run('complete', env);665 addAfter(tokenList, tokenList.head, text);
547 callback && callback.call(env.element);
548 }
549 666
550 _.hooks.run('before-sanity-check', env);667 matchGrammar(text, tokenList, grammar, tokenList.head, 0);
551 668
552 if (!env.code) {669 return toArray(tokenList);
553 _.hooks.run('complete', env);670 },
554 callback && callback.call(env.element);
555 return;
556 }
557 671
558 _.hooks.run('before-highlight', env);672 /**
673 * @namespace
674 * @memberof Prism
675 * @public
676 */
677 hooks: {
678 all: {},
559 679
560 if (!env.grammar) {680 /**
561 insertHighlightedCode(_.util.encode(env.code));681 * Adds the given callback to the list of callbacks for the given hook.
562 return;682 *
563 }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;
564 694
565 if (async && _self.Worker) {695 hooks[name] = hooks[name] || [];
566 var worker = new Worker(_.filename);
567 696
568 worker.onmessage = function(evt) {697 hooks[name].push(callback);
569 insertHighlightedCode(evt.data);698 },
570 };
571 699
572 worker.postMessage(JSON.stringify({700 /**
573 language: env.language,701 * Runs a hook invoking all registered callbacks with the given environment variables.
574 code: env.code,702 *
575 immediateClose: true703 * Callbacks will be invoked synchronously and in the order in which they were registered.
576 }));704 *
577 }705 * @param {string} name The name of the hook.
578 else {706 * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
579 insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));707 * @public
580 }708 */
581 },709 run: function (name, env) {
710 var callbacks = _.hooks.all[name];
582 711
583 /**712 if (!callbacks || !callbacks.length) {
584 * Low-level function, only use if you know what you’re doing. It accepts a string of text as input713 return;
585 * and the language definitions to use, and returns a string with the HTML produced.714 }
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 },
614 715
615 /**716 for (var i = 0, callback; (callback = callbacks[i++]);) {
616 * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input717 callback(env);
617 * and the language definitions to use, and returns an array with the tokenized code.718 }
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];
644 }719 }
720 },
645 721
646 delete grammar.rest;722 Token: Token
647 }723 };
648 724 _self.Prism = _;
649 var tokenList = new LinkedList();
650 addAfter(tokenList, tokenList.head, text);
651 725
652 matchGrammar(text, tokenList, grammar, tokenList.head, 0);
653 726
654 return toArray(tokenList);727 // Typescript note:
655 },728 // The following can be used to import the Token type in JSDoc:
729 //
730 // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
656 731
657 /**732 /**
658 * @namespace733 * Creates a new token.
659 * @memberof Prism734 *
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
660 * @public741 * @public
661 */742 */
662 hooks: {743 function Token(type, content, alias, matchedStr) {
663 all: {},
664
665 /**744 /**
666 * Adds the given callback to the list of callbacks for the given hook.745 * The type of the token.
667 *746 *
668 * The callback will be invoked when the hook it is registered for is run.747 * This is usually the key of a pattern in a {@link Grammar}.
669 * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
670 *748 *
671 * One callback function can be registered to multiple hooks and the same hook multiple times.749 * @type {string}
672 *750 * @see GrammarToken
673 * @param {string} name The name of the hook.
674 * @param {HookCallback} callback The callback function which is given environment variables.
675 * @public751 * @public
676 */752 */
677 add: function (name, callback) {753 this.type = type;
678 var hooks = _.hooks.all;
679
680 hooks[name] = hooks[name] || [];
681
682 hooks[name].push(callback);
683 },
684
685 /**754 /**
686 * Runs a hook invoking all registered callbacks with the given environment variables.755 * The strings or tokens contained by this token.
687 *756 *
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.
689 *758 *
690 * @param {string} name The name of the hook.759 * @type {string | TokenStream}
691 * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
692 * @public760 * @public
693 */761 */
694 run: function (name, env) {762 this.content = content;
695 var callbacks = _.hooks.all[name];763 /**
696 764 * The alias(es) of the token.
697 if (!callbacks || !callbacks.length) {765 *
698 return;766 * @type {string|string[]}
699 }767 * @see GrammarToken
700 768 * @public
701 for (var i=0, callback; callback = callbacks[i++];) {769 */
702 callback(env);770 this.alias = alias;
703 }771 // Copy of the full string this token was created from
704 }772 this.length = (matchedStr || '').length | 0;
705 },773 }
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
716 774
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 */
728function Token(type, content, alias, matchedStr) {
729 /**775 /**
730 * The type of the token.776 * A token stream is an array of strings and {@link Token Token} objects.
731 *777 *
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.
733 *780 *
734 * @type {string}781 * 1. No adjacent strings.
735 * @see GrammarToken782 * 2. No empty strings.
736 * @public
737 */
738 this.type = type;
739 /**
740 * The strings or tokens contained by this token.
741 *783 *
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.
743 *785 *
744 * @type {string | TokenStream}786 * @typedef {Array<string | Token>} TokenStream
787 * @global
745 * @public788 * @public
746 */789 */
747 this.content = content;790
748 /**791 /**
749 * The alias(es) of the token.792 * Converts the given token or token stream to an HTML representation.
750 *793 *
751 * @type {string|string[]}794 * The following hooks will be run:
752 * @see GrammarToken795 * 1. `wrap`: On each {@link Token}.
753 * @public796 *
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
754 */802 */
755 this.alias = alias;803 Token.stringify = function stringify(o, language) {
756 // Copy of the full string this token was created from804 if (typeof o == 'string') {
757 this.length = (matchedStr || '').length | 0;805 return o;
758}806 }
759 807 if (Array.isArray(o)) {
760/**808 var s = '';
761 * A token stream is an array of strings and {@link Token Token} objects.809 o.forEach(function (e) {
762 *810 s += stringify(e, language);
763 * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process811 });
764 * them.812 return s;
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 */
788Token.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);
815 }813 }
816 }
817 814
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 };
819 823
820 var attributes = '';824 var aliases = o.alias;
821 for (var name in env.attributes) {825 if (aliases) {
822 attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';826 if (Array.isArray(aliases)) {
823 }827 Array.prototype.push.apply(env.classes, aliases);
828 } else {
829 env.classes.push(aliases);
830 }
831 }
824 832
825 return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';833 _.hooks.run('wrap', env);
826};
827 834
828/**835 var attributes = '';
829 * @param {RegExp} pattern836 for (var name in env.attributes) {
830 * @param {number} pos837 attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
831 * @param {string} text
832 * @param {boolean} lookbehind
833 * @returns {RegExpExecArray | null}
834 */
835function 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 */
861function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
862 for (var token in grammar) {
863 if (!grammar.hasOwnProperty(token) || !grammar[token]) {
864 continue;
865 }838 }
866 839
867 var patterns = grammar[token];840 return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
868 patterns = Array.isArray(patterns) ? patterns : [patterns];841 };
869
870 for (var j = 0; j < patterns.length; ++j) {
871 if (rematch && rematch.cause == token + ',' + j) {
872 return;
873 }
874 842
875 var patternObj = patterns[j],843 /**
876 inside = patternObj.inside,844 * @param {RegExp} pattern
877 lookbehind = !!patternObj.lookbehind,845 * @param {number} pos
878 greedy = !!patternObj.greedy,846 * @param {string} text
879 alias = patternObj.alias;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 }
880 861
881 if (greedy && !patternObj.pattern.global) {862 /**
882 // Without the global flag, lastIndex won't work863 * @param {string} text
883 var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];864 * @param {LinkedList<string | Token>} tokenList
884 patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');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;
885 }880 }
886 881
887 /** @type {RegExp} */882 var patterns = grammar[token];
888 var pattern = patternObj.pattern || patternObj;883 patterns = Array.isArray(patterns) ? patterns : [patterns];
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 ) {
895 884
896 if (rematch && pos >= rematch.reach) {885 for (var j = 0; j < patterns.length; ++j) {
897 break;886 if (rematch && rematch.cause == token + ',' + j) {
887 return;
898 }888 }
899 889
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;
901 895
902 if (tokenList.length > text.length) {896 if (greedy && !patternObj.pattern.global) {
903 // Something went terribly wrong, ABORT, ABORT!897 // Without the global flag, lastIndex won't work
904 return;898 var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
899 patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
905 }900 }
906 901
907 if (str instanceof Token) {902 /** @type {RegExp} */
908 continue;903 var pattern = patternObj.pattern || patternObj;
909 }
910 904
911 var removeCount = 1; // this is the to parameter of removeBetween905 for ( // iterate the token list and keep track of the current token/string position
912 var match;906 var currentNode = startNode.next, pos = startPos;
907 currentNode !== tokenList.tail;
908 pos += currentNode.value.length, currentNode = currentNode.next
909 ) {
913 910
914 if (greedy) {911 if (rematch && pos >= rematch.reach) {
915 match = matchPattern(pattern, pos, text, lookbehind);
916 if (!match) {
917 break;912 break;
918 }913 }
919 914
920 var from = match.index;915 var str = currentNode.value;
921 var to = match.index + match[0].length;
922 var p = pos;
923 916
924 // find the node that contains the match917 if (tokenList.length > text.length) {
925 p += currentNode.value.length;918 // Something went terribly wrong, ABORT, ABORT!
926 while (from >= p) {919 return;
927 currentNode = currentNode.next;
928 p += currentNode.value.length;
929 }920 }
930 // adjust pos (and p)
931 p -= currentNode.value.length;
932 pos = p;
933 921
934 // the current node is a Token, then the match starts inside another Token, which is invalid922 if (str instanceof Token) {
935 if (currentNode.value instanceof Token) {
936 continue;923 continue;
937 }924 }
938 925
939 // find the last node which is affected by this match926 var removeCount = 1; // this is the to parameter of removeBetween
940 for (927 var match;
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--;
949 928
950 // replace with the new match929 if (greedy) {
951 str = text.slice(pos, p);930 match = matchPattern(pattern, pos, text, lookbehind);
952 match.index -= pos;931 if (!match) {
953 } else {932 break;
954 match = matchPattern(pattern, 0, str, lookbehind);933 }
955 if (!match) {934
956 continue;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 }
957 }973 }
958 }
959 974
960 var from = match.index,975 // eslint-disable-next-line no-redeclare
961 matchStr = match[0],976 var from = match.index;
962 before = str.slice(0, from),977 var matchStr = match[0];
963 after = str.slice(from + matchStr.length);978 var before = str.slice(0, from);
979 var after = str.slice(from + matchStr.length);
964 980
965 var reach = pos + str.length;981 var reach = pos + str.length;
966 if (rematch && reach > rematch.reach) {982 if (rematch && reach > rematch.reach) {
967 rematch.reach = reach;983 rematch.reach = reach;
968 }984 }
969 985
970 var removeFrom = currentNode.prev;986 var removeFrom = currentNode.prev;
971 987
972 if (before) {988 if (before) {
973 removeFrom = addAfter(tokenList, removeFrom, before);989 removeFrom = addAfter(tokenList, removeFrom, before);
974 pos += before.length;990 pos += before.length;
975 }991 }
976 992
977 removeRange(tokenList, removeFrom, removeCount);993 removeRange(tokenList, removeFrom, removeCount);
978 994
979 var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);995 var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
980 currentNode = addAfter(tokenList, removeFrom, wrapped);996 currentNode = addAfter(tokenList, removeFrom, wrapped);
981 997
982 if (after) {998 if (after) {
983 addAfter(tokenList, currentNode, after);999 addAfter(tokenList, currentNode, after);
984 }1000 }
985 1001
986 if (removeCount > 1) {1002 if (removeCount > 1) {
987 // at least one Token object was removed, so we have to do some rematching1003 // at least one Token object was removed, so we have to do some rematching
988 // this can only happen if the current pattern is greedy1004 // this can only happen if the current pattern is greedy
989 1005
990 /** @type {RematchOptions} */1006 /** @type {RematchOptions} */
991 var nestedRematch = {1007 var nestedRematch = {
992 cause: token + ',' + j,1008 cause: token + ',' + j,
993 reach: reach1009 reach: reach
994 };1010 };
995 matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);1011 matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
996 1012
997 // the reach might have been extended because of the rematching1013 // the reach might have been extended because of the rematching
998 if (rematch && nestedRematch.reach > rematch.reach) {1014 if (rematch && nestedRematch.reach > rematch.reach) {
999 rematch.reach = nestedRematch.reach;1015 rematch.reach = nestedRematch.reach;
1016 }
1000 }1017 }
1001 }1018 }
1002 }1019 }
1003 }1020 }
1004 }1021 }
1005}
1006 1022
1007/**1023 /**
1008 * @typedef LinkedListNode1024 * @typedef LinkedListNode
1009 * @property {T} value1025 * @property {T} value
1010 * @property {LinkedListNode<T> | null} prev The previous node.1026 * @property {LinkedListNode<T> | null} prev The previous node.
1011 * @property {LinkedListNode<T> | null} next The next node.1027 * @property {LinkedListNode<T> | null} next The next node.
1012 * @template T1028 * @template T
1013 * @private1029 * @private
1014 */1030 */
1015 1031
1016/**1032 /**
1017 * @template T1033 * @template T
1018 * @private1034 * @private
1019 */1035 */
1020function LinkedList() {1036 function LinkedList() {
1021 /** @type {LinkedListNode<T>} */1037 /** @type {LinkedListNode<T>} */
1022 var head = { value: null, prev: null, next: null };1038 var head = { value: null, prev: null, next: null };
1023 /** @type {LinkedListNode<T>} */1039 /** @type {LinkedListNode<T>} */
1024 var tail = { value: null, prev: head, next: null };1040 var tail = { value: null, prev: head, next: null };
1025 head.next = tail;1041 head.next = tail;
1026 1042
1027 /** @type {LinkedListNode<T>} */1043 /** @type {LinkedListNode<T>} */
1028 this.head = head;1044 this.head = head;
1029 /** @type {LinkedListNode<T>} */1045 /** @type {LinkedListNode<T>} */
1030 this.tail = tail;1046 this.tail = tail;
1031 this.length = 0;1047 this.length = 0;
1032}1048 }
1033 1049
1034/**1050 /**
1035 * Adds a new node with the given value to the list.1051 * Adds a new node with the given value to the list.
1036 * @param {LinkedList<T>} list1052 *
1037 * @param {LinkedListNode<T>} node1053 * @param {LinkedList<T>} list
1038 * @param {T} value1054 * @param {LinkedListNode<T>} node
1039 * @returns {LinkedListNode<T>} The added node.1055 * @param {T} value
1040 * @template T1056 * @returns {LinkedListNode<T>} The added node.
1041 */1057 * @template T
1042function addAfter(list, node, value) {1058 */
1043 // assumes that node != list.tail && values.length >= 01059 function addAfter(list, node, value) {
1044 var next = node.next;1060 // assumes that node != list.tail && values.length >= 0
1061 var next = node.next;
1045 1062
1046 var newNode = { value: value, prev: node, next: next };1063 var newNode = { value: value, prev: node, next: next };
1047 node.next = newNode;1064 node.next = newNode;
1048 next.prev = newNode;1065 next.prev = newNode;
1049 list.length++;1066 list.length++;
1050 1067
1051 return newNode;1068 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 */
1060function removeRange(list, node, count) {
1061 var next = node.next;
1062 for (var i = 0; i < count && next !== list.tail; i++) {
1063 next = next.next;
1064 }1069 }
1065 node.next = next;1070 /**
1066 next.prev = node;1071 * Removes `count` nodes after the given node. The given node will not be removed.
1067 list.length -= i;1072 *
1068}1073 * @param {LinkedList<T>} list
1069/**1074 * @param {LinkedListNode<T>} node
1070 * @param {LinkedList<T>} list1075 * @param {number} count
1071 * @returns {T[]}1076 * @template T
1072 * @template T1077 */
1073 */1078 function removeRange(list, node, count) {
1074function toArray(list) {1079 var next = node.next;
1075 var array = [];1080 for (var i = 0; i < count && next !== list.tail; i++) {
1076 var node = list.head.next;1081 next = next.next;
1077 while (node !== list.tail) {1082 }
1078 array.push(node.value);1083 node.next = next;
1079 node = node.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;
1080 }1100 }
1081 return array;
1082}
1083 1101
1084 1102
1085if (!_self.document) {1103 if (!_self.document) {
1086 if (!_self.addEventListener) {1104 if (!_self.addEventListener) {
1087 // in Node.js1105 // in Node.js
1088 return _;1106 return _;
1089 }1107 }
1090 1108
1091 if (!_.disableWorkerMessageHandler) {1109 if (!_.disableWorkerMessageHandler) {
1092 // In worker1110 // In worker
1093 _self.addEventListener('message', function (evt) {1111 _self.addEventListener('message', function (evt) {
1094 var message = JSON.parse(evt.data),1112 var message = JSON.parse(evt.data);
1095 lang = message.language,1113 var lang = message.language;
1096 code = message.code,1114 var code = message.code;
1097 immediateClose = message.immediateClose;1115 var immediateClose = message.immediateClose;
1098 1116
1099 _self.postMessage(_.highlight(code, _.languages[lang], lang));1117 _self.postMessage(_.highlight(code, _.languages[lang], lang));
1100 if (immediateClose) {1118 if (immediateClose) {
1101 _self.close();1119 _self.close();
1102 }1120 }
1103 }, false);1121 }, false);
1104 }1122 }
1105 1123
1106 return _;1124 return _;
1107}1125 }
1108 1126
1109// Get current script and highlight1127 // Get current script and highlight
1110var script = _.util.currentScript();1128 var script = _.util.currentScript();
1111 1129
1112if (script) {1130 if (script) {
1113 _.filename = script.src;1131 _.filename = script.src;
1114 1132
1115 if (script.hasAttribute('data-manual')) {1133 if (script.hasAttribute('data-manual')) {
1116 _.manual = true;1134 _.manual = true;
1135 }
1117 }1136 }
1118}
1119 1137
1120function highlightAutomaticallyCallback() {1138 function highlightAutomaticallyCallback() {
1121 if (!_.manual) {1139 if (!_.manual) {
1122 _.highlightAll();1140 _.highlightAll();
1141 }
1123 }1142 }
1124}
1125 1143
1126if (!_.manual) {1144 if (!_.manual) {
1127 // If the document state is "loading", then we'll use DOMContentLoaded.1145 // 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 the1146 // 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 they1147 // 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 have1148 // 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.1149 // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
1132 // See https://github.com/PrismJS/prism/issues/21021150 // See https://github.com/PrismJS/prism/issues/2102
1133 var readyState = document.readyState;1151 var readyState = document.readyState;
1134 if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {1152 if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
1135 document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);1153 document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
1136 } else {
1137 if (window.requestAnimationFrame) {
1138 window.requestAnimationFrame(highlightAutomaticallyCallback);
1139 } else {1154 } else {
1140 window.setTimeout(highlightAutomaticallyCallback, 16);1155 if (window.requestAnimationFrame) {
1156 window.requestAnimationFrame(highlightAutomaticallyCallback);
1157 } else {
1158 window.setTimeout(highlightAutomaticallyCallback, 16);
1159 }
1141 }1160 }
1142 }1161 }
1143}
1144 1162
1145return _;1163 return _;
1146 1164
1147})(_self);1165}(_self));
1148 1166
1149if (typeof module !== 'undefined' && module.exports) {1167if (typeof module !== 'undefined' && module.exports) {
1150 module.exports = Prism;1168 module.exports = Prism;
@@ -1176,7 +1194,7 @@ if (typeof global !== 'undefined') { · 25 unmodified lines
1176 * each another.1194 * each another.
1177 * @global1195 * @global
1178 * @public1196 * @public
1179*/1197 */
1180 1198
1181/**1199/**
1182 * @typedef Grammar1200 * @typedef Grammar
@@ -1194,7 +1212,7 @@ if (typeof global !== 'undefined') { · 11 unmodified lines
1194 * @returns {void}1212 * @returns {void}
1195 * @global1213 * @global
1196 * @public1214 * @public
1197*/1215 */
1198 1216
1199/**1217/**
1200 * @callback HookCallback1218 * @callback HookCallback
@@ -1239,6 +1257,7 @@ Prism.languages.markup = { · 38 unmodified lines
1239 'namespace': /^[^\s>\/:]+:/1257 'namespace': /^[^\s>\/:]+:/
1240 }1258 }
1241 },1259 },
1260 'special-attr': [],
1242 'attr-value': {1261 'attr-value': {
1243 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,1262 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
1244 inside: {1263 inside: {
@@ -1325,6 +1344,49 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { · 80 unmodified lines
1325 Prism.languages.insertBefore('markup', 'cdata', def);1344 Prism.languages.insertBefore('markup', 'cdata', def);
1326 }1345 }
1327});1346});
1347Object.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});
1328 1390
1329Prism.languages.html = Prism.languages.markup;1391Prism.languages.html = Prism.languages.markup;
1330Prism.languages.mathml = Prism.languages.markup;1392Prism.languages.mathml = Prism.languages.markup;
@@ -1386,34 +1448,7 @@ Prism.languages.rss = Prism.languages.xml; · 55 unmodified lines
1386 var markup = Prism.languages.markup;1448 var markup = Prism.languages.markup;
1387 if (markup) {1449 if (markup) {
1388 markup.tag.addInlined('style', 'css');1450 markup.tag.addInlined('style', 'css');
1389 1451 markup.tag.addAttribute('style', 'css');
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);
1417 }1452 }
1418 1453
1419}(Prism));1454}(Prism));
@@ -1464,7 +1499,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', { · 44 unmodified lines
1464 lookbehind: true1499 lookbehind: true
1465 },1500 },
1466 {1501 {
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/,
1468 lookbehind: true1503 lookbehind: true
1469 },1504 },
1470 ],1505 ],
@@ -1478,7 +1513,7 @@ Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|ext · 7 unmodified lines
1478 1513
1479Prism.languages.insertBefore('javascript', 'keyword', {1514Prism.languages.insertBefore('javascript', 'keyword', {
1480 'regex': {1515 '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,.;:})\]]|\/\/))/,
1482 lookbehind: true,1517 lookbehind: true,
1483 greedy: true,1518 greedy: true,
1484 inside: {1519 inside: {
@@ -1522,6 +1557,11 @@ Prism.languages.insertBefore('javascript', 'keyword', { · 37 unmodified lines
1522});1557});
1523 1558
1524Prism.languages.insertBefore('javascript', 'string', {1559Prism.languages.insertBefore('javascript', 'string', {
1560 'hashbang': {
1561 pattern: /^#!.*/,
1562 greedy: true,
1563 alias: 'comment'
1564 },
1525 'template-string': {1565 'template-string': {
1526 pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,1566 pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,
1527 greedy: true,1567 greedy: true,
@@ -1548,11 +1588,18 @@ Prism.languages.insertBefore('javascript', 'string', { · 20 unmodified lines
1548 1588
1549if (Prism.languages.markup) {1589if (Prism.languages.markup) {
1550 Prism.languages.markup.tag.addInlined('script', 'javascript');1590 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 );
1551}1598}
1552 1599
1553Prism.languages.js = Prism.languages.javascript;1600Prism.languages.js = Prism.languages.javascript;
1554 1601
1555(function(Prism) {1602(function (Prism) {
1556 // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'1603 // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
1557 // + LC_ALL, RANDOM, REPLY, SECONDS.1604 // + LC_ALL, RANDOM, REPLY, SECONDS.
1558 // + make sure PS1..4 are here as they are not always set,1605 // + 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
1569 var insideString = {1616 var insideString = {
1570 'bash': commandAfterHeredoc,1617 'bash': commandAfterHeredoc,
1571 'environment': {1618 'environment': {
1572 pattern: RegExp("\\$" + envVars),1619 pattern: RegExp('\\$' + envVars),
1573 alias: 'constant'1620 alias: 'constant'
1574 },1621 },
1575 'variable': [1622 'variable': [
@@ -1609,7 +1656,7 @@ Prism.languages.js = Prism.languages.javascript; · 33 unmodified lines
1609 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,1656 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
1610 'punctuation': /[\[\]]/,1657 'punctuation': /[\[\]]/,
1611 'environment': {1658 'environment': {
1612 pattern: RegExp("(\\{)" + envVars),1659 pattern: RegExp('(\\{)' + envVars),
1613 lookbehind: true,1660 lookbehind: true,
1614 alias: 'constant'1661 alias: 'constant'
1615 }1662 }
@@ -1637,13 +1684,13 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines
1637 // but not “foo {”1684 // but not “foo {”
1638 {1685 {
1639 // a) and c)1686 // a) and c)
1640 pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,1687 pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
1641 lookbehind: true,1688 lookbehind: true,
1642 alias: 'function'1689 alias: 'function'
1643 },1690 },
1644 {1691 {
1645 // b)1692 // b)
1646 pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/,1693 pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
1647 alias: 'function'1694 alias: 'function'
1648 }1695 }
1649 ],1696 ],
@@ -1659,7 +1706,7 @@ Prism.languages.js = Prism.languages.javascript; · 9 unmodified lines
1659 pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,1706 pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,
1660 inside: {1707 inside: {
1661 'environment': {1708 'environment': {
1662 pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars),1709 pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
1663 lookbehind: true,1710 lookbehind: true,
1664 alias: 'constant'1711 alias: 'constant'
1665 }1712 }
@@ -1687,14 +1734,29 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines
1687 },1734 },
1688 // “Normal” string1735 // “Normal” string
1689 {1736 {
1690 pattern: /(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\2)[^\\`$])*\2/,1737 // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
1738 pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
1691 lookbehind: true,1739 lookbehind: true,
1692 greedy: true,1740 greedy: true,
1693 inside: insideString1741 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 }
1694 }1756 }
1695 ],1757 ],
1696 'environment': {1758 'environment': {
1697 pattern: RegExp("\\$?" + envVars),1759 pattern: RegExp('\\$?' + envVars),
1698 alias: 'constant'1760 alias: 'constant'
1699 },1761 },
1700 'variable': insideString.variable,1762 'variable': insideString.variable,
@@ -1758,12 +1820,12 @@ Prism.languages.js = Prism.languages.javascript; · 57 unmodified lines
1758 'number'1820 'number'
1759 ];1821 ];
1760 var inside = insideString.variable[1].inside;1822 var inside = insideString.variable[1].inside;
1761 for(var i = 0; i < toBeCopied.length; i++) {1823 for (var i = 0; i < toBeCopied.length; i++) {
1762 inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];1824 inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
1763 }1825 }
1764 1826
1765 Prism.languages.shell = Prism.languages.bash;1827 Prism.languages.shell = Prism.languages.bash;
1766})(Prism);1828}(Prism));
1767 1829
1768Prism.languages.c = Prism.languages.extend('clike', {1830Prism.languages.c = Prism.languages.extend('clike', {
1769 'comment': {1831 'comment': {
@@ -1831,7 +1893,8 @@ delete Prism.languages.c['boolean']; · 61 unmodified lines
1831 1893
1832(function (Prism) {1894(function (Prism) {
1833 1895
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; });
1835 1898
1836 Prism.languages.cpp = Prism.languages.extend('c', {1899 Prism.languages.cpp = Prism.languages.extend('c', {
1837 'class-name': [1900 'class-name': [
@@ -1857,11 +1920,31 @@ delete Prism.languages.c['boolean']; · 19 unmodified lines
1857 pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,1920 pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,
1858 greedy: true1921 greedy: true
1859 },1922 },
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/,
1861 'boolean': /\b(?:true|false)\b/1924 'boolean': /\b(?:true|false)\b/
1862 });1925 });
1863 1926
1864 Prism.languages.insertBefore('cpp', 'string', {1927 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 },
1865 'raw-string': {1948 'raw-string': {
1866 pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,1949 pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
1867 alias: 'string',1950 alias: 'string',
@@ -1869,6 +1952,27 @@ delete Prism.languages.c['boolean']; · 1 unmodified line
1869 }1952 }
1870 });1953 });
1871 1954
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
1872 Prism.languages.insertBefore('cpp', 'class-name', {1976 Prism.languages.insertBefore('cpp', 'class-name', {
1873 // the base clause is an optional list of parent classes1977 // the base clause is an optional list of parent classes
1874 // https://en.cppreference.com/w/cpp/language/class1978 // https://en.cppreference.com/w/cpp/language/class
@@ -1879,108 +1983,109 @@ delete Prism.languages.c['boolean']; · 4 unmodified lines
1879 inside: Prism.languages.extend('cpp', {})1983 inside: Prism.languages.extend('cpp', {})
1880 }1984 }
1881 });1985 });
1882 Prism.languages.insertBefore('inside', 'operator', {1986
1987 Prism.languages.insertBefore('inside', 'double-colon', {
1883 // All untokenized words that are not namespaces should be class names1988 // All untokenized words that are not namespaces should be class names
1884 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i1989 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i
1885 }, Prism.languages.cpp['base-clause']);1990 }, Prism.languages.cpp['base-clause']);
1886 1991
1887}(Prism));1992}(Prism));
1888 1993
1889(function(Prism) {1994(function (Prism) {
1890
1891// Ignore comments starting with { to privilege string interpolation highlighting
1892var comment = /#(?!\{).+/,
1893 interpolation = {
1894 pattern: /#\{[^}]+\}/,
1895 alias: 'variable'
1896 };
1897 1995
1898Prism.languages.coffeescript = Prism.languages.extend('javascript', {1996 // Ignore comments starting with { to privilege string interpolation highlighting
1899 'comment': comment,1997 var comment = /#(?!\{).+/;
1900 'string': [1998 var interpolation = {
1999 pattern: /#\{[^}]+\}/,
2000 alias: 'variable'
2001 };
1901 2002
1902 // Strings are multiline2003 Prism.languages.coffeescript = Prism.languages.extend('javascript', {
1903 {2004 'comment': comment,
1904 pattern: /'(?:\\[\s\S]|[^\\'])*'/,2005 'string': [
1905 greedy: true
1906 },
1907 2006
1908 {
1909 // Strings are multiline2007 // Strings are multiline
1910 pattern: /"(?:\\[\s\S]|[^\\"])*"/,2008 {
1911 greedy: true,2009 pattern: /'(?:\\[\s\S]|[^\\'])*'/,
1912 inside: {2010 greedy: true
1913 'interpolation': interpolation2011 },
2012
2013 {
2014 // Strings are multiline
2015 pattern: /"(?:\\[\s\S]|[^\\"])*"/,
2016 greedy: true,
2017 inside: {
2018 'interpolation': interpolation
2019 }
1914 }2020 }
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'
1915 }2026 }
1916 ],2027 });
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
1924Prism.languages.insertBefore('coffeescript', 'comment', {
1925 'multiline-comment': {
1926 pattern: /###[\s\S]+?###/,
1927 alias: 'comment'
1928 },
1929 2028
1930 // Block regexp can contain comments and interpolation2029 Prism.languages.insertBefore('coffeescript', 'comment', {
1931 'block-regex': {2030 'multiline-comment': {
1932 pattern: /\/{3}[\s\S]*?\/{3}/,2031 pattern: /###[\s\S]+?###/,
1933 alias: 'regex',2032 alias: 'comment'
1934 inside: {2033 },
1935 'comment': comment,
1936 'interpolation': interpolation
1937 }
1938 }
1939});
1940 2034
1941Prism.languages.insertBefore('coffeescript', 'string', {2035 // Block regexp can contain comments and interpolation
1942 'inline-javascript': {2036 'block-regex': {
1943 pattern: /`(?:\\[\s\S]|[^\\`])*`/,2037 pattern: /\/{3}[\s\S]*?\/{3}/,
1944 inside: {2038 alias: 'regex',
1945 'delimiter': {2039 inside: {
1946 pattern: /^`|`$/,2040 'comment': comment,
1947 alias: 'punctuation'2041 'interpolation': interpolation
1948 },
1949 'script': {
1950 pattern: /[\s\S]+/,
1951 alias: 'language-javascript',
1952 inside: Prism.languages.javascript
1953 }2042 }
1954 }2043 }
1955 },2044 });
1956 2045
1957 // Block strings2046 Prism.languages.insertBefore('coffeescript', 'string', {
1958 'multiline-string': [2047 'inline-javascript': {
1959 {2048 pattern: /`(?:\\[\s\S]|[^\\`])*`/,
1960 pattern: /'''[\s\S]*?'''/,
1961 greedy: true,
1962 alias: 'string'
1963 },
1964 {
1965 pattern: /"""[\s\S]*?"""/,
1966 greedy: true,
1967 alias: 'string',
1968 inside: {2049 inside: {
1969 interpolation: interpolation2050 'delimiter': {
2051 pattern: /^`|`$/,
2052 alias: 'punctuation'
2053 },
2054 'script': {
2055 pattern: /[\s\S]+/,
2056 alias: 'language-javascript',
2057 inside: Prism.languages.javascript
2058 }
1970 }2059 }
1971 }2060 },
1972 ]
1973 2061
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 ]
1975 2078
1976Prism.languages.insertBefore('coffeescript', 'keyword', {2079 });
1977 // Object property2080
1978 'property': /(?!\d)\w+(?=\s*:(?!:))/2081 Prism.languages.insertBefore('coffeescript', 'keyword', {
1979});2082 // Object property
2083 'property': /(?!\d)\w+(?=\s*:(?!:))/
2084 });
1980 2085
1981delete Prism.languages.coffeescript['template-string'];2086 delete Prism.languages.coffeescript['template-string'];
1982 2087
1983Prism.languages.coffee = Prism.languages.coffeescript;2088 Prism.languages.coffee = Prism.languages.coffeescript;
1984}(Prism));2089}(Prism));
1985 2090
1986/**2091/**
@@ -2025,22 +2130,25 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 38 unmodified lines
2025 'regex': [2130 'regex': [
2026 {2131 {
2027 pattern: RegExp(/%r/.source + '(?:' + [2132 pattern: RegExp(/%r/.source + '(?:' + [
2028 /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[gim]{0,3}/.source,2133 /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,
2029 /\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/.source,2134 /\((?:[^()\\]|\\[\s\S])*\)/.source,
2030 // Here we need to specifically allow interpolation2135 // Here we need to specifically allow interpolation
2031 /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/.source,2136 /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source,
2032 /\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/.source,2137 /\[(?:[^\[\]\\]|\\[\s\S])*\]/.source,
2033 /<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/.source2138 /<(?:[^<>\\]|\\[\s\S])*>/.source
2034 ].join('|') + ')'),2139 ].join('|') + ')' + /[egimnosux]{0,6}/.source),
2035 greedy: true,2140 greedy: true,
2036 inside: {2141 inside: {
2037 'interpolation': interpolation2142 'interpolation': interpolation
2038 }2143 }
2039 },2144 },
2040 {2145 {
2041 pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[gim]{0,3}(?=\s*(?:$|[\r\n,.;})]))/,2146 pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,
2042 lookbehind: true,2147 lookbehind: true,
2043 greedy: true2148 greedy: true,
2149 inside: {
2150 'interpolation': interpolation
2151 }
2044 }2152 }
2045 ],2153 ],
2046 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,2154 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,
@@ -2084,13 +2192,42 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 37 unmodified lines
2084 inside: {2192 inside: {
2085 'interpolation': interpolation2193 'interpolation': interpolation
2086 }2194 }
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 }
2087 }2224 }
2088 ];2225 ];
2089 2226
2090 Prism.languages.rb = Prism.languages.ruby;2227 Prism.languages.rb = Prism.languages.ruby;
2091}(Prism));2228}(Prism));
2092 2229
2093(function(Prism) {2230(function (Prism) {
2094 Prism.languages.crystal = Prism.languages.extend('ruby', {2231 Prism.languages.crystal = Prism.languages.extend('ruby', {
2095 keyword: [2232 keyword: [
2096 /\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/,2233 /\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
2117 },2254 },
2118 2255
2119 expansion: [2256 expansion: [
2120 {2257 {
2121 pattern: /\{\{.+?\}\}/,2258 pattern: /\{\{.+?\}\}/,
2122 inside: {2259 inside: {
2123 delimiter: {2260 delimiter: {
2124 pattern: /^\{\{|\}\}$/,2261 pattern: /^\{\{|\}\}$/,
2125 alias: 'tag'2262 alias: 'tag'
2126 },2263 },
2127 rest: Prism.languages.crystal2264 rest: Prism.languages.crystal
2128 }2265 }
2129 },2266 },
2130 {2267 {
2131 pattern: /\{%.+?%\}/,2268 pattern: /\{%.+?%\}/,
2132 inside: {2269 inside: {
2133 delimiter: {2270 delimiter: {
2134 pattern: /^\{%|%\}$/,2271 pattern: /^\{%|%\}$/,
2135 alias: 'tag'2272 alias: 'tag'
2136 },2273 },
2137 rest: Prism.languages.crystal2274 rest: Prism.languages.crystal
2275 }
2138 }2276 }
2139 }
2140 ]2277 ]
2141 });2278 });
2142 2279
@@ -2223,30 +2360,73 @@ Prism.languages.insertBefore('d', 'function', { · 80 unmodified lines
2223 }2360 }
2224});2361});
2225 2362
2226Prism.languages.dart = Prism.languages.extend('clike', {2363(function (Prism) {
2227 'string': [2364 var keywords = [
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': [
2238 /\b(?:async|sync|yield)\*/,2365 /\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/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/
2240 ],2367 ];
2241 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/
2242});
2243 2368
2244Prism.languages.insertBefore('dart','function',{2369 // Handles named imports, such as http.Client
2245 'metadata': {2370 var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source;
2246 pattern: /@\w+/,2371
2247 alias: 'symbol'2372 // based on the dart naming conventions
2248 }2373 var className = {
2249});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));
2250 2430
2251(function (Prism) {2431(function (Prism) {
2252 2432
@@ -2285,8 +2465,8 @@ Prism.languages.insertBefore('dart','function',{ · 32 unmodified lines
2285 if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"2465 if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted"
2286 alias.push(/\w+/.exec(name)[0]);2466 alias.push(/\w+/.exec(name)[0]);
2287 }2467 }
2288 if (name === "diff") {2468 if (name === 'diff') {
2289 alias.push("bold");2469 alias.push('bold');
2290 }2470 }
2291 2471
2292 Prism.languages.diff[name] = {2472 Prism.languages.diff[name] = {
@@ -2354,8 +2534,9 @@ Prism.languages.insertBefore('dart','function',{ · 61 unmodified lines
2354 var placeholder;2534 var placeholder;
2355 2535
2356 // Check for existing strings2536 // Check for existing strings
2357 while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1)2537 while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) {
2358 ++i;2538 ++i;
2539 }
2359 2540
2360 // Create a sparse array2541 // Create a sparse array
2361 tokenStack[i] = match;2542 tokenStack[i] = match;
@@ -2496,10 +2677,20 @@ Prism.languages.insertBefore('dart','function',{ · 134 unmodified lines
2496 markupTemplating.tokenizePlaceholders(env, 'jinja2');2677 markupTemplating.tokenizePlaceholders(env, 'jinja2');
2497 });2678 });
2498 2679
2499})(Prism);2680}(Prism));
2500 2681
2501Prism.languages.elixir = {2682Prism.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 },
2503 // ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo), ~r[foo], ~r{foo}, ~r<foo>2694 // ~r"""foo""" (multi-line), ~r'''foo''' (multi-line), ~r/foo/, ~r|foo|, ~r"foo", ~r'foo', ~r(foo), ~r[foo], ~r{foo}, ~r<foo>
2504 'regex': {2695 'regex': {
2505 pattern: /~[rR](?:("""|''')(?:\\[\s\S]|(?!\1)[^\\])+\1|([\/|"'])(?:\\.|(?!\2)[^\\\r\n])+\2|\((?:\\.|[^\\)\r\n])+\)|\[(?:\\.|[^\\\]\r\n])+\]|\{(?:\\.|[^\\}\r\n])+\}|<(?:\\.|[^\\>\r\n])+>)[uismxfr]*/,2696 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
2536 lookbehind: true,2727 lookbehind: true,
2537 alias: 'symbol'2728 alias: 'symbol'
2538 },2729 },
2730 'module': {
2731 pattern: /\b[A-Z]\w*\b/,
2732 alias: 'class-name'
2733 },
2539 // Look-ahead prevents bad highlighting of the :: operator2734 // Look-ahead prevents bad highlighting of the :: operator
2540 'attr-name': /\w+\??:(?!:)/,2735 '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 },
2547 'argument': {2736 'argument': {
2548 // Look-behind prevents bad highlighting of the && operator2737 // Look-behind prevents bad highlighting of the && operator
2549 pattern: /(^|[^&])&\d+/,2738 pattern: /(^|[^&])&\d+/,
@@ -2554,8 +2743,9 @@ Prism.languages.elixir = { · 4 unmodified lines
2554 pattern: /@\w+/,2743 pattern: /@\w+/,
2555 alias: 'variable'2744 alias: 'variable'
2556 },2745 },
2746 'function': /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d+))/,
2557 'number': /\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,2747 '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/,
2559 'boolean': /\b(?:true|false|nil)\b/,2749 'boolean': /\b(?:true|false|nil)\b/,
2560 'operator': [2750 'operator': [
2561 /\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,2751 /\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,
@@ -2573,19 +2763,7 @@ Prism.languages.elixir = { · 11 unmodified lines
2573 'punctuation': /<<|>>|[.,%\[\]{}()]/2763 'punctuation': /<<|>>|[.,%\[\]{}()]/
2574};2764};
2575 2765
2576Prism.languages.insertBefore('elixir', 'keyword', {2766Prism.languages.elixir.string.forEach(function (o) {
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
2588Prism.languages.elixir.string.forEach(function(o) {
2589 o.inside = {2767 o.inside = {
2590 'interpolation': {2768 'interpolation': {
2591 pattern: /#\{[^}]+\}/,2769 pattern: /#\{[^}]+\}/,
@@ -2701,7 +2879,7 @@ Prism.languages.insertBefore('groovy', 'function', { · 109 unmodified lines
2701});2879});
2702 2880
2703// Handle string interpolation2881// Handle string interpolation
2704Prism.hooks.add('wrap', function(env) {2882Prism.hooks.add('wrap', function (env) {
2705 if (env.language === 'groovy' && env.type === 'string') {2883 if (env.language === 'groovy' && env.type === 'string') {
2706 var delimiter = env.content[0];2884 var delimiter = env.content[0];
2707 2885
@@ -2791,7 +2969,7 @@ Prism.hooks.add('wrap', function(env) { · 83 unmodified lines
2791 alias: 'punctuation'2969 alias: 'punctuation'
2792 },2970 },
2793 'generics': {2971 'generics': {
2794 pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,2972 pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,
2795 inside: {2973 inside: {
2796 'class-name': className,2974 'class-name': className,
2797 'keyword': keywords,2975 'keyword': keywords,
@@ -2893,7 +3071,7 @@ Prism.languages.julia = { · 95 unmodified lines
2893 'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/3071 'operator': /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/
2894 });3072 });
2895 3073
2896 delete Prism.languages.kotlin["class-name"];3074 delete Prism.languages.kotlin['class-name'];
2897 3075
2898 Prism.languages.insertBefore('kotlin', 'string', {3076 Prism.languages.insertBefore('kotlin', 'string', {
2899 'raw-string': {3077 'raw-string': {
@@ -2940,6 +3118,71 @@ Prism.languages.julia = { · 40 unmodified lines
2940 Prism.languages.kts = Prism.languages.kotlin;3118 Prism.languages.kts = Prism.languages.kotlin;
2941}(Prism));3119}(Prism));
2942 3120
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
2943Prism.languages.lua = {3186Prism.languages.lua = {
2944 'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,3187 'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,
2945 // \z may be used to skip the following space3188 // \z may be used to skip the following space
@@ -2978,17 +3221,58 @@ Prism.languages.matlab = { · 32 unmodified lines
2978 'punctuation': /\.{3}|[.,;\[\](){}!]/3221 'punctuation': /\.{3}|[.,;\[\](){}!]/
2979};3222};
2980 3223
2981Prism.languages.nginx = Prism.languages.extend('clike', {3224(function (Prism) {
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});
2988 3225
2989Prism.languages.insertBefore('nginx', 'keyword', {3226 var variable = /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i;
2990 'variable': /\$[a-z_]+/i3227
2991});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));
2992 3276
2993Prism.languages.nim = {3277Prism.languages.nim = {
2994 'comment': /#.*/,3278 'comment': /#.*/,
@@ -3023,6 +3307,7 @@ Prism.languages.nim = { · 28 unmodified lines
3023 },3307 },
3024 'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/3308 'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/
3025};3309};
3310
3026Prism.languages.ocaml = {3311Prism.languages.ocaml = {
3027 'comment': /\(\*[\s\S]*?\*\)/,3312 'comment': /\(\*[\s\S]*?\*\)/,
3028 'string': [3313 'string': [
@@ -3228,7 +3513,7 @@ Prism.languages.perl = { · 199 unmodified lines
3228 // ${...}3513 // ${...}
3229 /[&*$@%]#?(?=\{)/,3514 /[&*$@%]#?(?=\{)/,
3230 // $foo3515 // $foo
3231 /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i,3516 /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/i,
3232 // $13517 // $1
3233 /[&*$@%]\d+/,3518 /[&*$@%]\d+/,
3234 // $_, @_, %!3519 // $_, @_, %!
@@ -3271,8 +3556,18 @@ Prism.languages.perl = { · 36 unmodified lines
3271 pattern: /\b(?:false|true)\b/i,3556 pattern: /\b(?:false|true)\b/i,
3272 alias: 'boolean'3557 alias: 'boolean'
3273 },3558 },
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 },
3275 /\b(?:null)\b/i,3569 /\b(?:null)\b/i,
3570 /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
3276 ];3571 ];
3277 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;3572 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;
3278 var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;3573 var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
@@ -3297,6 +3592,11 @@ Prism.languages.perl = { · 18 unmodified lines
3297 lookbehind: true,3592 lookbehind: true,
3298 alias: 'class-name'3593 alias: 'class-name'
3299 },3594 },
3595 'function-definition': {
3596 pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
3597 lookbehind: true,
3598 alias: 'function'
3599 },
3300 'keyword': [3600 'keyword': [
3301 {3601 {
3302 pattern: /(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,3602 pattern: /(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,
@@ -3344,9 +3644,26 @@ Prism.languages.perl = { · 41 unmodified lines
3344 alias: 'static-context',3644 alias: 'static-context',
3345 greedy: true3645 greedy: true
3346 },3646 },
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/i3647 {
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 }
3348 ],3662 ],
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 },
3350 'class-name': [3667 'class-name': [
3351 {3668 {
3352 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,3669 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
3446 }3763 }
3447 ],3764 ],
3448 'constant': constant,3765 '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 },
3450 'property': {3773 'property': {
3451 pattern: /(->)[\w]+/,3774 pattern: /(->\s*)\w+/,
3452 lookbehind: true3775 lookbehind: true
3453 },3776 },
3454 'number': number,3777 'number': number,
@@ -3457,7 +3780,7 @@ Prism.languages.perl = { · 2 unmodified lines
3457 };3780 };
3458 3781
3459 var string_interpolation = {3782 var string_interpolation = {
3460 pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)*)/,3783 pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
3461 lookbehind: true,3784 lookbehind: true,
3462 inside: Prism.languages.php3785 inside: Prism.languages.php
3463 };3786 };
@@ -3489,7 +3812,7 @@ Prism.languages.perl = { · 25 unmodified lines
3489 'punctuation': /^<<<"?|[";]$/3812 'punctuation': /^<<<"?|[";]$/
3490 }3813 }
3491 },3814 },
3492 'interpolation': string_interpolation // See below3815 'interpolation': string_interpolation
3493 }3816 }
3494 },3817 },
3495 {3818 {
@@ -3507,16 +3830,13 @@ Prism.languages.perl = { · 11 unmodified lines
3507 alias: 'double-quoted-string',3830 alias: 'double-quoted-string',
3508 greedy: true,3831 greedy: true,
3509 inside: {3832 inside: {
3510 'interpolation': string_interpolation // See below3833 'interpolation': string_interpolation
3511 }3834 }
3512 }3835 }
3513 ];3836 ];
3514 3837
3515 Prism.languages.insertBefore('php', 'variable', {3838 Prism.languages.insertBefore('php', 'variable', {
3516 'string': string,3839 'string': string,
3517 });
3518
3519 Prism.languages.insertBefore('php', 'variable', {
3520 'attribute': {3840 'attribute': {
3521 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/mi,3841 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/mi,
3522 greedy: true,3842 greedy: true,
@@ -3562,7 +3882,7 @@ Prism.languages.perl = { · 39 unmodified lines
3562 },3882 },
3563 });3883 });
3564 3884
3565 Prism.hooks.add('before-tokenize', function(env) {3885 Prism.hooks.add('before-tokenize', function (env) {
3566 if (!/<\?/.test(env.code)) {3886 if (!/<\?/.test(env.code)) {
3567 return;3887 return;
3568 }3888 }
@@ -3571,7 +3891,7 @@ Prism.languages.perl = { · 2 unmodified lines
3571 Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);3891 Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
3572 });3892 });
3573 3893
3574 Prism.hooks.add('after-tokenize', function(env) {3894 Prism.hooks.add('after-tokenize', function (env) {
3575 Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');3895 Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
3576 });3896 });
3577 3897
@@ -3642,149 +3962,149 @@ Prism.languages.python['string-interpolation'].inside['interpolation'].inside.re · 64 unmodified lines
3642 3962
3643Prism.languages.py = Prism.languages.python;3963Prism.languages.py = Prism.languages.python;
3644 3964
3645(function(Prism) {3965(function (Prism) {
3646 3966
3647var javascript = Prism.util.clone(Prism.languages.javascript);3967 var javascript = Prism.util.clone(Prism.languages.javascript);
3648 3968
3649var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;3969 var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
3650var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;3970 var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
3651var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;3971 var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
3652 3972
3653/**3973 /**
3654 * @param {string} source3974 * @param {string} source
3655 * @param {string} [flags]3975 * @param {string} [flags]
3656 */3976 */
3657function re(source, flags) {3977 function re(source, flags) {
3658 source = source3978 source = source
3659 .replace(/<S>/g, function () { return space; })3979 .replace(/<S>/g, function () { return space; })
3660 .replace(/<BRACES>/g, function () { return braces; })3980 .replace(/<BRACES>/g, function () { return braces; })
3661 .replace(/<SPREAD>/g, function () { return spread; });3981 .replace(/<SPREAD>/g, function () { return spread; });
3662 return RegExp(source, flags);3982 return RegExp(source, flags);
3663}3983 }
3664 3984
3665spread = re(spread).source;3985 spread = re(spread).source;
3666 3986
3667 3987
3668Prism.languages.jsx = Prism.languages.extend('markup', javascript);3988 Prism.languages.jsx = Prism.languages.extend('markup', javascript);
3669Prism.languages.jsx.tag.pattern = re(3989 Prism.languages.jsx.tag.pattern = re(
3670 /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source3990 /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
3671);3991 );
3672 3992
3673Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;3993 Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
3674Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;3994 Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
3675Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;3995 Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
3676Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];3996 Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
3677 3997
3678Prism.languages.insertBefore('inside', 'attr-name', {3998 Prism.languages.insertBefore('inside', 'attr-name', {
3679 'spread': {3999 'spread': {
3680 pattern: re(/<SPREAD>/.source),4000 pattern: re(/<SPREAD>/.source),
3681 inside: Prism.languages.jsx4001 inside: Prism.languages.jsx
3682 }4002 }
3683}, Prism.languages.jsx.tag);4003 }, Prism.languages.jsx.tag);
3684 4004
3685Prism.languages.insertBefore('inside', 'attr-value',{4005 Prism.languages.insertBefore('inside', 'special-attr', {
3686 'script': {4006 'script': {
3687 // Allow for two levels of nesting4007 // Allow for two levels of nesting
3688 pattern: re(/=<BRACES>/.source),4008 pattern: re(/=<BRACES>/.source),
3689 inside: {4009 inside: {
3690 'script-punctuation': {4010 'script-punctuation': {
3691 pattern: /^=(?={)/,4011 pattern: /^=(?={)/,
3692 alias: 'punctuation'4012 alias: 'punctuation'
4013 },
4014 rest: Prism.languages.jsx
3693 },4015 },
3694 rest: Prism.languages.jsx4016 'alias': 'language-javascript'
3695 },4017 }
3696 'alias': 'language-javascript'4018 }, Prism.languages.jsx.tag);
3697 }
3698}, Prism.languages.jsx.tag);
3699 4019
3700// The following will handle plain text inside tags4020 // The following will handle plain text inside tags
3701var stringifyToken = function (token) {4021 var stringifyToken = function (token) {
3702 if (!token) {4022 if (!token) {
3703 return '';4023 return '';
3704 }4024 }
3705 if (typeof token === 'string') {4025 if (typeof token === 'string') {
3706 return token;4026 return token;
3707 }4027 }
3708 if (typeof token.content === 'string') {4028 if (typeof token.content === 'string') {
3709 return token.content;4029 return token.content;
3710 }4030 }
3711 return token.content.map(stringifyToken).join('');4031 return token.content.map(stringifyToken).join('');
3712};4032 };
3713 4033
3714var walkTokens = function (tokens) {4034 var walkTokens = function (tokens) {
3715 var openedTags = [];4035 var openedTags = [];
3716 for (var i = 0; i < tokens.length; i++) {4036 for (var i = 0; i < tokens.length; i++) {
3717 var token = tokens[i];4037 var token = tokens[i];
3718 var notTagNorBrace = false;4038 var notTagNorBrace = false;
3719 4039
3720 if (typeof token !== 'string') {4040 if (typeof token !== 'string') {
3721 if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {4041 if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
3722 // We found a tag, now find its kind4042 // We found a tag, now find its kind
3723 4043
3724 if (token.content[0].content[0].content === '</') {4044 if (token.content[0].content[0].content === '</') {
3725 // Closing tag4045 // Closing tag
3726 if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {4046 if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
3727 // Pop matching opening tag4047 // Pop matching opening tag
3728 openedTags.pop();4048 openedTags.pop();
3729 }4049 }
3730 } else {
3731 if (token.content[token.content.length - 1].content === '/>') {
3732 // Autoclosed tag, ignore
3733 } else {4050 } else {
3734 // Opening tag4051 if (token.content[token.content.length - 1].content === '/>') {
3735 openedTags.push({4052 // Autoclosed tag, ignore
3736 tagName: stringifyToken(token.content[0].content[1]),4053 } else {
3737 openedBraces: 04054 // Opening tag
3738 });4055 openedTags.push({
4056 tagName: stringifyToken(token.content[0].content[1]),
4057 openedBraces: 0
4058 });
4059 }
3739 }4060 }
3740 }4061 } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
3741 } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
3742 4062
3743 // Here we might have entered a JSX context inside a tag4063 // Here we might have entered a JSX context inside a tag
3744 openedTags[openedTags.length - 1].openedBraces++;4064 openedTags[openedTags.length - 1].openedBraces++;
3745 4065
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 === '}') {
3747 4067
3748 // Here we might have left a JSX context inside a tag4068 // Here we might have left a JSX context inside a tag
3749 openedTags[openedTags.length - 1].openedBraces--;4069 openedTags[openedTags.length - 1].openedBraces--;
3750 4070
3751 } else {4071 } else {
3752 notTagNorBrace = true4072 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);
3765 }4073 }
3766 if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {4074 }
3767 plainText = stringifyToken(tokens[i - 1]) + plainText;4075 if (notTagNorBrace || typeof token === 'string') {
3768 tokens.splice(i - 1, 1);4076 if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
3769 i--;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);
3770 }4093 }
4094 }
3771 4095
3772 tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);4096 if (token.content && typeof token.content !== 'string') {
4097 walkTokens(token.content);
3773 }4098 }
3774 }4099 }
4100 };
3775 4101
3776 if (token.content && typeof token.content !== 'string') {4102 Prism.hooks.add('after-tokenize', function (env) {
3777 walkTokens(token.content);4103 if (env.language !== 'jsx' && env.language !== 'tsx') {
4104 return;
3778 }4105 }
3779 }4106 walkTokens(env.tokens);
3780};4107 });
3781
3782Prism.hooks.add('after-tokenize', function (env) {
3783 if (env.language !== 'jsx' && env.language !== 'tsx') {
3784 return;
3785 }
3786 walkTokens(env.tokens);
3787});
3788 4108
3789}(Prism));4109}(Prism));
3790 4110
@@ -4007,17 +4327,26 @@ Prism.languages.scss['atrule'].inside.rest = Prism.languages.scss; · 216 unmodified lines
4007 4327
4008 var strings = [4328 var strings = [
4009 // normal string4329 // normal string
4010 // 1 capturing group4330 /"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source,
4011 /(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\1)[^\\`$])*\1/.source,4331 /'[^']*'/.source,
4332 /\$'(?:[^'\\]|\\[\s\S])*'/.source,
4012 4333
4013 // here doc4334 // here doc
4014 // 2 capturing groups4335 // 2 capturing groups
4015 /<<-?\s*(["']?)(\w+)\2\s[\s\S]*?[\r\n]\3/.source4336 /<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source
4016 ].join('|');4337 ].join('|');
4017 4338
4018 Prism.languages['shell-session'] = {4339 Prism.languages['shell-session'] = {
4019 'command': {4340 '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 ),
4021 greedy: true,4350 greedy: true,
4022 inside: {4351 inside: {
4023 'info': {4352 'info': {
@@ -4085,11 +4414,16 @@ Prism.languages.sql = { · 61 unmodified lines
4085 greedy: true,4414 greedy: true,
4086 inside: null // see below4415 inside: null // see below
4087 },4416 },
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/,
4090 'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,4417 'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,
4091 });4418 });
4092 4419
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
4093 // doesn't work with TS because TS is too complex4427 // doesn't work with TS because TS is too complex
4094 delete Prism.languages.typescript['parameter'];4428 delete Prism.languages.typescript['parameter'];
4095 4429
@@ -4100,6 +4434,16 @@ Prism.languages.sql = { · 4 unmodified lines
4100 Prism.languages.typescript['class-name'].inside = typeInside;4434 Prism.languages.typescript['class-name'].inside = typeInside;
4101 4435
4102 Prism.languages.insertBefore('typescript', 'function', {4436 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 },
4103 'generic-function': {4447 'generic-function': {
4104 // e.g. foo<T extends "bar" | "baz">( ...4448 // e.g. foo<T extends "bar" | "baz">( ...
4105 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,4449 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
@@ -4146,7 +4490,7 @@ Prism.languages.sql = { · 40 unmodified lines
4146 flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag4490 flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag
4147 var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|]|}|(?:[\r\n]\s*)?#))/.source4491 var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|]|}|(?:[\r\n]\s*)?#))/.source
4148 .replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g, function () { return value; });4492 .replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g, function () { return value; });
4149 return RegExp(pattern, flags)4493 return RegExp(pattern, flags);
4150 }4494 }
4151 4495
4152 Prism.languages.yaml = {4496 Prism.languages.yaml = {
@@ -4202,4 +4546,3 @@ Prism.languages.sql = { · 49 unmodified lines
4202 Prism.languages.yml = Prism.languages.yaml;4546 Prism.languages.yml = Prism.languages.yaml;
4203 4547
4204}(Prism));4548}(Prism));
4205
lib/docs/filters/latex/clean_html.rb+5−0
@@ -13,6 +13,11 @@ module Docs · 12 unmodified lines
13 13
14 css('h1, h2, h3, h4').each { |node| node.content = node.content.sub /^[0-9A-Z]+(\.[0-9]+)* /, '' }14 css('h1, h2, h3, h4').each { |node| node.content = node.content.sub /^[0-9A-Z]+(\.[0-9]+)* /, '' }
15 15
16 css('pre').each do |node|
17 node.delete 'class'
18 node['data-language'] = 'latex'
19 end
20
16 doc21 doc
17 end22 end
18 end23 end