| @@ -1,13 +1,13 @@ |
| 1 | 1 | /* PrismJS 1.23.0 |
| 2 | | −https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+lua+markup-templating+matlab+nginx+nim+ocaml+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml */ |
| 2 | +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+cpp+coffeescript+crystal+d+dart+diff+django+elixir+erlang+go+groovy+java+json+julia+kotlin+latex+lua+markup-templating+matlab+nginx+nim+ocaml+perl+php+python+jsx+ruby+rust+scss+shell-session+sql+typescript+yaml */ |
| 3 | 3 | /// <reference lib="WebWorker"/> |
| 4 | 4 | |
| 5 | 5 | var _self = (typeof window !== 'undefined') |
| 6 | 6 | ? window // if in browser |
| 7 | 7 | : ( |
| 8 | 8 | (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) |
| 9 | | − ? self // if in worker |
| 10 | | − : {} // if in node js |
| 9 | + ? self // if in worker |
| 10 | + : {} // if in node js |
| 11 | 11 | ); |
| 12 | 12 | |
| 13 | 13 | /** |
| @@ -18,1133 +18,1151 @@ var _self = (typeof window !== 'undefined') · 4 unmodified lines |
| 18 | 18 | * @namespace |
| 19 | 19 | * @public |
| 20 | 20 | */ |
| 21 | | −var Prism = (function (_self){ |
| 21 | +var Prism = (function (_self) { |
| 22 | 22 | |
| 23 | | −// Private helper vars |
| 24 | | −var lang = /\blang(?:uage)?-([\w-]+)\b/i; |
| 25 | | −var uniqueId = 0; |
| 23 | + // Private helper vars |
| 24 | + var lang = /\blang(?:uage)?-([\w-]+)\b/i; |
| 25 | + var uniqueId = 0; |
| 26 | 26 | |
| 27 | + // The grammar object for plaintext |
| 28 | + var plainTextGrammar = {}; |
| 27 | 29 | |
| 28 | | −var _ = { |
| 29 | | − /** |
| 30 | | − * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the |
| 31 | | − * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load |
| 32 | | − * additional languages or plugins yourself. |
| 33 | | − * |
| 34 | | − * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. |
| 35 | | − * |
| 36 | | − * You obviously have to change this value before the automatic highlighting started. To do this, you can add an |
| 37 | | − * empty Prism object into the global scope before loading the Prism script like this: |
| 38 | | − * |
| 39 | | − * ```js |
| 40 | | − * window.Prism = window.Prism || {}; |
| 41 | | − * Prism.manual = true; |
| 42 | | − * // add a new <script> to load Prism's script |
| 43 | | − * ``` |
| 44 | | − * |
| 45 | | − * @default false |
| 46 | | − * @type {boolean} |
| 47 | | − * @memberof Prism |
| 48 | | − * @public |
| 49 | | − */ |
| 50 | | − manual: _self.Prism && _self.Prism.manual, |
| 51 | | − disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, |
| 52 | | − |
| 53 | | − /** |
| 54 | | − * A namespace for utility methods. |
| 55 | | − * |
| 56 | | − * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may |
| 57 | | − * change or disappear at any time. |
| 58 | | − * |
| 59 | | − * @namespace |
| 60 | | − * @memberof Prism |
| 61 | | − */ |
| 62 | | − util: { |
| 63 | | − encode: function encode(tokens) { |
| 64 | | − if (tokens instanceof Token) { |
| 65 | | − return new Token(tokens.type, encode(tokens.content), tokens.alias); |
| 66 | | − } else if (Array.isArray(tokens)) { |
| 67 | | − return tokens.map(encode); |
| 68 | | − } else { |
| 69 | | − return tokens.replace(/&/g, '&').replace(/</g, '<').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} o |
| 77 | | − * @returns {string} |
| 78 | | − * @example |
| 79 | | − * type(null) === 'Null' |
| 80 | | − * type(undefined) === 'Undefined' |
| 81 | | − * type(123) === 'Number' |
| 82 | | − * type('foo') === 'String' |
| 83 | | − * type(true) === 'Boolean' |
| 84 | | − * type([1, 2]) === 'Array' |
| 85 | | − * type({}) === 'Object' |
| 86 | | − * type(String) === 'Function' |
| 87 | | − * type(/abc+/) === 'RegExp' |
| 88 | | − */ |
| 89 | | − type: function (o) { |
| 90 | | − return Object.prototype.toString.call(o).slice(8, -1); |
| 91 | | − }, |
| 92 | | − |
| 93 | | − /** |
| 94 | | − * Returns a unique number for the given object. Later calls will still return the same number. |
| 37 | + * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. |
| 38 | + * |
| 39 | + * You obviously have to change this value before the automatic highlighting started. To do this, you can add an |
| 40 | + * empty Prism object into the global scope before loading the Prism script like this: |
| 95 | 41 | * |
| 96 | | − * @param {Object} obj |
| 97 | | − * @returns {number} |
| 42 | + * ```js |
| 43 | + * window.Prism = window.Prism || {}; |
| 44 | + * Prism.manual = true; |
| 45 | + * // add a new <script> to load Prism's script |
| 46 | + * ``` |
| 47 | + * |
| 48 | + * @default false |
| 49 | + * @type {boolean} |
| 50 | + * @memberof Prism |
| 51 | + * @public |
| 98 | 52 | */ |
| 99 | | − objId: function (obj) { |
| 100 | | − if (!obj['__id']) { |
| 101 | | − Object.defineProperty(obj, '__id', { value: ++uniqueId }); |
| 102 | | − } |
| 103 | | − return obj['__id']; |
| 104 | | − }, |
| 53 | + manual: _self.Prism && _self.Prism.manual, |
| 54 | + disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, |
| 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} o |
| 112 | | − * @param {Record<number, any>} [visited] |
| 113 | | − * @returns {T} |
| 114 | | − * @template T |
| 62 | + * @namespace |
| 63 | + * @memberof Prism |
| 115 | 64 | */ |
| 116 | | − clone: function deepClone(o, visited) { |
| 117 | | − visited = visited || {}; |
| 118 | | − |
| 119 | | − var clone, id; |
| 120 | | − switch (_.util.type(o)) { |
| 121 | | − case 'Object': |
| 122 | | − id = _.util.objId(o); |
| 123 | | − if (visited[id]) { |
| 124 | | − return visited[id]; |
| 125 | | − } |
| 126 | | − clone = /** @type {Record<string, any>} */ ({}); |
| 127 | | − visited[id] = clone; |
| 65 | + util: { |
| 66 | + encode: function encode(tokens) { |
| 67 | + if (tokens instanceof Token) { |
| 68 | + return new Token(tokens.type, encode(tokens.content), tokens.alias); |
| 69 | + } else if (Array.isArray(tokens)) { |
| 70 | + return tokens.map(encode); |
| 71 | + } else { |
| 72 | + return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); |
| 73 | + } |
| 74 | + }, |
| 75 | + |
| 76 | + /** |
| 77 | + * Returns the name of the type of the given value. |
| 78 | + * |
| 79 | + * @param {any} o |
| 80 | + * @returns {string} |
| 81 | + * @example |
| 82 | + * type(null) === 'Null' |
| 83 | + * type(undefined) === 'Undefined' |
| 84 | + * type(123) === 'Number' |
| 85 | + * type('foo') === 'String' |
| 86 | + * type(true) === 'Boolean' |
| 87 | + * type([1, 2]) === 'Array' |
| 88 | + * type({}) === 'Object' |
| 89 | + * type(String) === 'Function' |
| 90 | + * type(/abc+/) === 'RegExp' |
| 91 | + */ |
| 92 | + type: function (o) { |
| 93 | + return Object.prototype.toString.call(o).slice(8, -1); |
| 94 | + }, |
| 95 | + |
| 96 | + /** |
| 97 | + * Returns a unique number for the given object. Later calls will still return the same number. |
| 98 | + * |
| 99 | + * @param {Object} obj |
| 100 | + * @returns {number} |
| 101 | + */ |
| 102 | + objId: function (obj) { |
| 103 | + if (!obj['__id']) { |
| 104 | + Object.defineProperty(obj, '__id', { value: ++uniqueId }); |
| 105 | + } |
| 106 | + return obj['__id']; |
| 107 | + }, |
| 128 | 108 | |
| 129 | | − for (var key in o) { |
| 130 | | − if (o.hasOwnProperty(key)) { |
| 131 | | − clone[key] = deepClone(o[key], visited); |
| 109 | + /** |
| 110 | + * Creates a deep clone of the given object. |
| 111 | + * |
| 112 | + * The main intended use of this function is to clone language definitions. |
| 113 | + * |
| 114 | + * @param {T} o |
| 115 | + * @param {Record<number, any>} [visited] |
| 116 | + * @returns {T} |
| 117 | + * @template T |
| 118 | + */ |
| 119 | + clone: function deepClone(o, visited) { |
| 120 | + visited = visited || {}; |
| 121 | + |
| 122 | + var clone; var id; |
| 123 | + switch (_.util.type(o)) { |
| 124 | + case 'Object': |
| 125 | + id = _.util.objId(o); |
| 126 | + if (visited[id]) { |
| 127 | + return visited[id]; |
| 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 | | − id = _.util.objId(o); |
| 139 | | − if (visited[id]) { |
| 140 | | − return visited[id]; |
| 141 | | − } |
| 142 | | − clone = []; |
| 143 | | − visited[id] = clone; |
| 138 | + return /** @type {any} */ (clone); |
| 144 | 139 | |
| 145 | | − (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) { |
| 146 | | − clone[i] = deepClone(v, visited); |
| 147 | | − }); |
| 140 | + case 'Array': |
| 141 | + id = _.util.objId(o); |
| 142 | + if (visited[id]) { |
| 143 | + return visited[id]; |
| 144 | + } |
| 145 | + clone = []; |
| 146 | + visited[id] = clone; |
| 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 o; |
| 153 | | − } |
| 154 | | − }, |
| 152 | + return /** @type {any} */ (clone); |
| 155 | 153 | |
| 156 | | − /** |
| 157 | | − * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. |
| 158 | | − * |
| 159 | | − * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. |
| 160 | | − * |
| 161 | | − * @param {Element} element |
| 162 | | − * @returns {string} |
| 163 | | − */ |
| 164 | | − getLanguage: function (element) { |
| 165 | | − while (element && !lang.test(element.className)) { |
| 166 | | − element = element.parentElement; |
| 167 | | − } |
| 168 | | − if (element) { |
| 169 | | − return (element.className.match(lang) || [, 'none'])[1].toLowerCase(); |
| 170 | | − } |
| 171 | | − return 'none'; |
| 172 | | − }, |
| 154 | + default: |
| 155 | + return o; |
| 156 | + } |
| 157 | + }, |
| 173 | 158 | |
| 174 | | − /** |
| 175 | | − * Returns the script element that is currently executing. |
| 176 | | − * |
| 177 | | − * This does __not__ work for line script element. |
| 178 | | − * |
| 179 | | − * @returns {HTMLScriptElement | null} |
| 180 | | − */ |
| 181 | | − currentScript: function () { |
| 182 | | − if (typeof document === 'undefined') { |
| 183 | | − return null; |
| 184 | | − } |
| 185 | | − if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) { |
| 186 | | − return /** @type {any} */ (document.currentScript); |
| 187 | | − } |
| 159 | + /** |
| 160 | + * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. |
| 161 | + * |
| 162 | + * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. |
| 163 | + * |
| 164 | + * @param {Element} element |
| 165 | + * @returns {string} |
| 166 | + */ |
| 167 | + getLanguage: function (element) { |
| 168 | + while (element && !lang.test(element.className)) { |
| 169 | + element = element.parentElement; |
| 170 | + } |
| 171 | + if (element) { |
| 172 | + return (element.className.match(lang) || [, 'none'])[1].toLowerCase(); |
| 173 | + } |
| 174 | + return 'none'; |
| 175 | + }, |
| 188 | 176 | |
| 189 | | − // IE11 workaround |
| 190 | | − // we'll get the src of the current script by parsing IE11's error stack trace |
| 191 | | − // this will not work for inline scripts |
| 177 | + /** |
| 178 | + * Returns the script element that is currently executing. |
| 179 | + * |
| 180 | + * This does __not__ work for line script element. |
| 181 | + * |
| 182 | + * @returns {HTMLScriptElement | null} |
| 183 | + */ |
| 184 | + currentScript: function () { |
| 185 | + if (typeof document === 'undefined') { |
| 186 | + return null; |
| 187 | + } |
| 188 | + if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) { |
| 189 | + return /** @type {any} */ (document.currentScript); |
| 190 | + } |
| 192 | 191 | |
| 193 | | − try { |
| 194 | | − throw new Error(); |
| 195 | | − } catch (err) { |
| 196 | | − // Get file src url from stack. Specifically works with the format of stack traces in IE. |
| 197 | | − // A stack will look like this: |
| 198 | | − // |
| 199 | | − // Error |
| 200 | | − // at _.util.currentScript (http://localhost/components/prism-core.js:119:5) |
| 201 | | − // at Global code (http://localhost/components/prism-core.js:606:1) |
| 202 | | − |
| 203 | | − var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1]; |
| 204 | | − if (src) { |
| 205 | | − var scripts = document.getElementsByTagName('script'); |
| 206 | | − for (var i in scripts) { |
| 207 | | − if (scripts[i].src == src) { |
| 208 | | − return scripts[i]; |
| 192 | + // IE11 workaround |
| 193 | + // we'll get the src of the current script by parsing IE11's error stack trace |
| 194 | + // this will not work for inline scripts |
| 195 | + |
| 196 | + try { |
| 197 | + throw new Error(); |
| 198 | + } catch (err) { |
| 199 | + // Get file src url from stack. Specifically works with the format of stack traces in IE. |
| 200 | + // A stack will look like this: |
| 201 | + // |
| 202 | + // Error |
| 203 | + // at _.util.currentScript (http://localhost/components/prism-core.js:119:5) |
| 204 | + // at Global code (http://localhost/components/prism-core.js:606:1) |
| 205 | + |
| 206 | + var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1]; |
| 207 | + if (src) { |
| 208 | + var scripts = document.getElementsByTagName('script'); |
| 209 | + for (var i in scripts) { |
| 210 | + if (scripts[i].src == src) { |
| 211 | + return scripts[i]; |
| 212 | + } |
| 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 deactivated |
| 220 | | − * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the |
| 221 | | − * given class is just the given class with a `no-` prefix. |
| 222 | | − * |
| 223 | | − * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is |
| 224 | | − * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its |
| 225 | | − * ancestors have the given class or the negated version of it, then the default activation will be returned. |
| 226 | | − * |
| 227 | | − * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated |
| 228 | | − * version of it, the class is considered active. |
| 229 | | − * |
| 230 | | − * @param {Element} element |
| 231 | | − * @param {string} className |
| 232 | | − * @param {boolean} [defaultActivation=false] |
| 233 | | − * @returns {boolean} |
| 258 | + * @namespace |
| 259 | + * @memberof Prism |
| 260 | + * @public |
| 234 | 261 | */ |
| 235 | | − isActive: function (element, className, defaultActivation) { |
| 236 | | − var no = 'no-' + className; |
| 262 | + languages: { |
| 263 | + /** |
| 264 | + * The grammar for plain, unformatted text. |
| 265 | + */ |
| 266 | + plain: plainTextGrammar, |
| 267 | + plaintext: plainTextGrammar, |
| 268 | + text: plainTextGrammar, |
| 269 | + txt: plainTextGrammar, |
| 237 | 270 | |
| 238 | | − while (element) { |
| 239 | | − var classList = element.classList; |
| 240 | | − if (classList.contains(className)) { |
| 241 | | − return true; |
| 271 | + /** |
| 272 | + * Creates a deep copy of the language with the given id and appends the given tokens. |
| 273 | + * |
| 274 | + * If a token in `redef` also appears in the copied language, then the existing token in the copied language |
| 275 | + * will be overwritten at its original position. |
| 276 | + * |
| 277 | + * ## Best practices |
| 278 | + * |
| 279 | + * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) |
| 280 | + * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to |
| 281 | + * understand the language definition because, normally, the order of tokens matters in Prism grammars. |
| 282 | + * |
| 283 | + * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. |
| 284 | + * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. |
| 285 | + * |
| 286 | + * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. |
| 287 | + * @param {Grammar} redef The new tokens to append. |
| 288 | + * @returns {Grammar} The new language created. |
| 289 | + * @public |
| 290 | + * @example |
| 291 | + * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { |
| 292 | + * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token |
| 293 | + * // at its original position |
| 294 | + * 'comment': { ... }, |
| 295 | + * // CSS doesn't have a 'color' token, so this token will be appended |
| 296 | + * 'color': /\b(?:red|green|blue)\b/ |
| 297 | + * }); |
| 298 | + */ |
| 299 | + extend: function (id, redef) { |
| 300 | + var lang = _.util.clone(_.languages[id]); |
| 301 | + |
| 302 | + for (var key in redef) { |
| 303 | + lang[key] = redef[key]; |
| 304 | + } |
| 305 | + |
| 306 | + return lang; |
| 307 | + }, |
| 308 | + |
| 309 | + /** |
| 310 | + * Inserts tokens _before_ another token in a language definition or any other grammar. |
| 311 | + * |
| 312 | + * ## Usage |
| 313 | + * |
| 314 | + * This helper method makes it easy to modify existing languages. For example, the CSS language definition |
| 315 | + * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded |
| 316 | + * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the |
| 317 | + * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do |
| 318 | + * this: |
| 319 | + * |
| 320 | + * ```js |
| 321 | + * Prism.languages.markup.style = { |
| 322 | + * // token |
| 323 | + * }; |
| 324 | + * ``` |
| 325 | + * |
| 326 | + * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens |
| 327 | + * before existing tokens. For the CSS example above, you would use it like this: |
| 328 | + * |
| 329 | + * ```js |
| 330 | + * Prism.languages.insertBefore('markup', 'cdata', { |
| 331 | + * 'style': { |
| 332 | + * // token |
| 333 | + * } |
| 334 | + * }); |
| 335 | + * ``` |
| 336 | + * |
| 337 | + * ## Special cases |
| 338 | + * |
| 339 | + * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar |
| 340 | + * will be ignored. |
| 341 | + * |
| 342 | + * This behavior can be used to insert tokens after `before`: |
| 343 | + * |
| 344 | + * ```js |
| 345 | + * Prism.languages.insertBefore('markup', 'comment', { |
| 346 | + * 'comment': Prism.languages.markup.comment, |
| 347 | + * // tokens after 'comment' |
| 348 | + * }); |
| 349 | + * ``` |
| 350 | + * |
| 351 | + * ## Limitations |
| 352 | + * |
| 353 | + * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object |
| 354 | + * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave |
| 355 | + * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily |
| 356 | + * deleting properties which is necessary to insert at arbitrary positions. |
| 357 | + * |
| 358 | + * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. |
| 359 | + * Instead, it will create a new object and replace all references to the target object with the new one. This |
| 360 | + * can be done without temporarily deleting properties, so the iteration order is well-defined. |
| 361 | + * |
| 362 | + * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if |
| 363 | + * you hold the target object in a variable, then the value of the variable will not change. |
| 364 | + * |
| 365 | + * ```js |
| 366 | + * var oldMarkup = Prism.languages.markup; |
| 367 | + * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); |
| 368 | + * |
| 369 | + * assert(oldMarkup !== Prism.languages.markup); |
| 370 | + * assert(newMarkup === Prism.languages.markup); |
| 371 | + * ``` |
| 372 | + * |
| 373 | + * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the |
| 374 | + * object to be modified. |
| 375 | + * @param {string} before The key to insert before. |
| 376 | + * @param {Grammar} insert An object containing the key-value pairs to be inserted. |
| 377 | + * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the |
| 378 | + * object to be modified. |
| 379 | + * |
| 380 | + * Defaults to `Prism.languages`. |
| 381 | + * @returns {Grammar} The new grammar object. |
| 382 | + * @public |
| 383 | + */ |
| 384 | + insertBefore: function (inside, before, insert, root) { |
| 385 | + root = root || /** @type {any} */ (_.languages); |
| 386 | + var grammar = root[inside]; |
| 387 | + /** @type {Grammar} */ |
| 388 | + var ret = {}; |
| 389 | + |
| 390 | + for (var token in grammar) { |
| 391 | + if (grammar.hasOwnProperty(token)) { |
| 392 | + |
| 393 | + if (token == before) { |
| 394 | + for (var newToken in insert) { |
| 395 | + if (insert.hasOwnProperty(newToken)) { |
| 396 | + ret[newToken] = insert[newToken]; |
| 397 | + } |
| 398 | + } |
| 399 | + } |
| 400 | + |
| 401 | + // Do not insert token which also occur in insert. See #1525 |
| 402 | + if (!insert.hasOwnProperty(token)) { |
| 403 | + ret[token] = grammar[token]; |
| 404 | + } |
| 405 | + } |
| 242 | 406 | } |
| 243 | | − if (classList.contains(no)) { |
| 244 | | − return false; |
| 407 | + |
| 408 | + var old = root[inside]; |
| 409 | + root[inside] = ret; |
| 410 | + |
| 411 | + // Update references in other language definitions |
| 412 | + _.languages.DFS(_.languages, function (key, value) { |
| 413 | + if (value === old && key != inside) { |
| 414 | + this[key] = ret; |
| 415 | + } |
| 416 | + }); |
| 417 | + |
| 418 | + return ret; |
| 419 | + }, |
| 420 | + |
| 421 | + // Traverse a language definition with Depth First Search |
| 422 | + DFS: function DFS(o, callback, type, visited) { |
| 423 | + visited = visited || {}; |
| 424 | + |
| 425 | + var objId = _.util.objId; |
| 426 | + |
| 427 | + for (var i in o) { |
| 428 | + if (o.hasOwnProperty(i)) { |
| 429 | + callback.call(o, i, o[i], type || i); |
| 430 | + |
| 431 | + var property = o[i]; |
| 432 | + var propertyType = _.util.type(property); |
| 433 | + |
| 434 | + if (propertyType === 'Object' && !visited[objId(property)]) { |
| 435 | + visited[objId(property)] = true; |
| 436 | + DFS(property, callback, null, visited); |
| 437 | + } else if (propertyType === 'Array' && !visited[objId(property)]) { |
| 438 | + visited[objId(property)] = true; |
| 439 | + DFS(property, callback, i, visited); |
| 440 | + } |
| 441 | + } |
| 245 | 442 | } |
| 246 | | − element = element.parentElement; |
| 247 | 443 | } |
| 248 | | − return !!defaultActivation; |
| 249 | | − } |
| 250 | | − }, |
| 444 | + }, |
| 445 | + |
| 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 language |
| 264 | | − * will be overwritten at its original position. |
| 453 | + * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. |
| 265 | 454 | * |
| 266 | | − * ## Best practices |
| 267 | | − * |
| 268 | | − * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) |
| 269 | | − * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to |
| 270 | | − * understand the language definition because, normally, the order of tokens matters in Prism grammars. |
| 455 | + * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. |
| 456 | + * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. |
| 457 | + * @memberof Prism |
| 458 | + * @public |
| 459 | + */ |
| 460 | + highlightAll: function (async, callback) { |
| 461 | + _.highlightAllUnder(document, async, callback); |
| 462 | + }, |
| 463 | + |
| 464 | + /** |
| 465 | + * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls |
| 466 | + * {@link Prism.highlightElement} on each one of them. |
| 271 | 467 | * |
| 272 | | − * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. |
| 273 | | − * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. |
| 468 | + * The following hooks will be run: |
| 469 | + * 1. `before-highlightall` |
| 470 | + * 2. `before-all-elements-highlight` |
| 471 | + * 3. All hooks of {@link Prism.highlightElement} for each element. |
| 274 | 472 | * |
| 275 | | − * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. |
| 276 | | − * @param {Grammar} redef The new tokens to append. |
| 277 | | − * @returns {Grammar} The new language created. |
| 473 | + * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. |
| 474 | + * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. |
| 475 | + * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. |
| 476 | + * @memberof Prism |
| 278 | 477 | * @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) { |
| 289 | | − var lang = _.util.clone(_.languages[id]); |
| 479 | + highlightAllUnder: function (container, async, callback) { |
| 480 | + var env = { |
| 481 | + callback: callback, |
| 482 | + container: container, |
| 483 | + selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' |
| 484 | + }; |
| 290 | 485 | |
| 291 | | − for (var key in redef) { |
| 292 | | − lang[key] = redef[key]; |
| 293 | | − } |
| 486 | + _.hooks.run('before-highlightall', env); |
| 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. |
| 300 | | − * |
| 301 | | − * ## Usage |
| 302 | | − * |
| 303 | | − * This helper method makes it easy to modify existing languages. For example, the CSS language definition |
| 304 | | − * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded |
| 305 | | − * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the |
| 306 | | − * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do |
| 307 | | − * this: |
| 308 | | − * |
| 309 | | − * ```js |
| 310 | | − * Prism.languages.markup.style = { |
| 311 | | − * // token |
| 312 | | − * }; |
| 313 | | − * ``` |
| 314 | | − * |
| 315 | | − * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens |
| 316 | | − * before existing tokens. For the CSS example above, you would use it like this: |
| 317 | | − * |
| 318 | | − * ```js |
| 319 | | − * Prism.languages.insertBefore('markup', 'cdata', { |
| 320 | | − * 'style': { |
| 321 | | − * // token |
| 322 | | − * } |
| 323 | | − * }); |
| 324 | | − * ``` |
| 325 | | − * |
| 326 | | − * ## Special cases |
| 327 | | − * |
| 328 | | − * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar |
| 329 | | − * will be ignored. |
| 330 | | − * |
| 331 | | − * This behavior can be used to insert tokens after `before`: |
| 332 | | − * |
| 333 | | − * ```js |
| 334 | | − * Prism.languages.insertBefore('markup', 'comment', { |
| 335 | | − * 'comment': Prism.languages.markup.comment, |
| 336 | | − * // tokens after 'comment' |
| 337 | | − * }); |
| 338 | | − * ``` |
| 339 | | − * |
| 340 | | − * ## Limitations |
| 341 | | − * |
| 342 | | − * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object |
| 343 | | − * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave |
| 344 | | − * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily |
| 345 | | − * deleting properties which is necessary to insert at arbitrary positions. |
| 346 | | − * |
| 347 | | − * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. |
| 348 | | − * Instead, it will create a new object and replace all references to the target object with the new one. This |
| 349 | | − * can be done without temporarily deleting properties, so the iteration order is well-defined. |
| 498 | + * Highlights the code inside a single element. |
| 350 | 499 | * |
| 351 | | − * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if |
| 352 | | − * you hold the target object in a variable, then the value of the variable will not change. |
| 500 | + * The following hooks will be run: |
| 501 | + * 1. `before-sanity-check` |
| 502 | + * 2. `before-highlight` |
| 503 | + * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. |
| 504 | + * 4. `before-insert` |
| 505 | + * 5. `after-highlight` |
| 506 | + * 6. `complete` |
| 353 | 507 | * |
| 354 | | − * ```js |
| 355 | | − * var oldMarkup = Prism.languages.markup; |
| 356 | | − * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); |
| 357 | | − * |
| 358 | | − * assert(oldMarkup !== Prism.languages.markup); |
| 359 | | − * assert(newMarkup === Prism.languages.markup); |
| 360 | | − * ``` |
| 508 | + * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for |
| 509 | + * the element's language. |
| 361 | 510 | * |
| 362 | | − * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the |
| 363 | | − * object to be modified. |
| 364 | | − * @param {string} before The key to insert before. |
| 365 | | − * @param {Grammar} insert An object containing the key-value pairs to be inserted. |
| 366 | | − * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the |
| 367 | | − * object to be modified. |
| 511 | + * @param {Element} element The element containing the code. |
| 512 | + * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. |
| 513 | + * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers |
| 514 | + * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is |
| 515 | + * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). |
| 368 | 516 | * |
| 369 | | − * Defaults to `Prism.languages`. |
| 370 | | − * @returns {Grammar} The new grammar object. |
| 517 | + * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for |
| 518 | + * asynchronous highlighting to work. You can build your own bundle on the |
| 519 | + * [Download page](https://prismjs.com/download.html). |
| 520 | + * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. |
| 521 | + * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. |
| 522 | + * @memberof Prism |
| 371 | 523 | * @public |
| 372 | 524 | */ |
| 373 | | − insertBefore: function (inside, before, insert, root) { |
| 374 | | − root = root || /** @type {any} */ (_.languages); |
| 375 | | − var grammar = root[inside]; |
| 376 | | − /** @type {Grammar} */ |
| 377 | | − var ret = {}; |
| 378 | | − |
| 379 | | − for (var token in grammar) { |
| 380 | | − if (grammar.hasOwnProperty(token)) { |
| 381 | | − |
| 382 | | − if (token == before) { |
| 383 | | − for (var newToken in insert) { |
| 384 | | − if (insert.hasOwnProperty(newToken)) { |
| 385 | | − ret[newToken] = insert[newToken]; |
| 386 | | − } |
| 387 | | − } |
| 388 | | − } |
| 389 | | − |
| 390 | | − // Do not insert token which also occur in insert. See #1525 |
| 391 | | − if (!insert.hasOwnProperty(token)) { |
| 392 | | − ret[token] = grammar[token]; |
| 393 | | − } |
| 394 | | − } |
| 525 | + highlightElement: function (element, async, callback) { |
| 526 | + // Find language |
| 527 | + var language = _.util.getLanguage(element); |
| 528 | + var grammar = _.languages[language]; |
| 529 | + |
| 530 | + // Set language on the element, if not present |
| 531 | + element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
| 532 | + |
| 533 | + // Set language on the parent, for styling |
| 534 | + var parent = element.parentElement; |
| 535 | + if (parent && parent.nodeName.toLowerCase() === 'pre') { |
| 536 | + parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
| 395 | 537 | } |
| 396 | 538 | |
| 397 | | − var old = root[inside]; |
| 398 | | − root[inside] = ret; |
| 539 | + var code = element.textContent; |
| 399 | 540 | |
| 400 | | − // Update references in other language definitions |
| 401 | | − _.languages.DFS(_.languages, function(key, value) { |
| 402 | | − if (value === old && key != inside) { |
| 403 | | − this[key] = ret; |
| 404 | | − } |
| 405 | | − }); |
| 406 | | − |
| 407 | | − return ret; |
| 408 | | − }, |
| 409 | | − |
| 410 | | − // Traverse a language definition with Depth First Search |
| 411 | | − DFS: function DFS(o, callback, type, visited) { |
| 412 | | − visited = visited || {}; |
| 541 | + var env = { |
| 542 | + element: element, |
| 543 | + language: language, |
| 544 | + grammar: grammar, |
| 545 | + code: code |
| 546 | + }; |
| 413 | 547 | |
| 414 | | − var objId = _.util.objId; |
| 548 | + function insertHighlightedCode(highlightedCode) { |
| 549 | + env.highlightedCode = highlightedCode; |
| 415 | 550 | |
| 416 | | − for (var i in o) { |
| 417 | | − if (o.hasOwnProperty(i)) { |
| 418 | | − callback.call(o, i, o[i], type || i); |
| 551 | + _.hooks.run('before-insert', env); |
| 419 | 552 | |
| 420 | | − var property = o[i], |
| 421 | | − propertyType = _.util.type(property); |
| 553 | + env.element.innerHTML = env.highlightedCode; |
| 422 | 554 | |
| 423 | | − if (propertyType === 'Object' && !visited[objId(property)]) { |
| 424 | | − visited[objId(property)] = true; |
| 425 | | − DFS(property, callback, null, visited); |
| 426 | | − } |
| 427 | | − else if (propertyType === 'Array' && !visited[objId(property)]) { |
| 428 | | − visited[objId(property)] = true; |
| 429 | | − DFS(property, callback, i, visited); |
| 430 | | − } |
| 431 | | − } |
| 555 | + _.hooks.run('after-highlight', env); |
| 556 | + _.hooks.run('complete', env); |
| 557 | + callback && callback.call(env.element); |
| 432 | 558 | } |
| 433 | | − } |
| 434 | | − }, |
| 435 | 559 | |
| 436 | | − plugins: {}, |
| 560 | + _.hooks.run('before-sanity-check', env); |
| 437 | 561 | |
| 438 | | − /** |
| 439 | | − * This is the most high-level function in Prism’s API. |
| 440 | | − * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on |
| 441 | | − * each one of them. |
| 442 | | − * |
| 443 | | − * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. |
| 444 | | − * |
| 445 | | − * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. |
| 446 | | − * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. |
| 447 | | − * @memberof Prism |
| 448 | | − * @public |
| 449 | | − */ |
| 450 | | − highlightAll: function(async, callback) { |
| 451 | | − _.highlightAllUnder(document, async, callback); |
| 452 | | − }, |
| 453 | | − |
| 454 | | − /** |
| 455 | | − * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls |
| 456 | | − * {@link Prism.highlightElement} on each one of them. |
| 457 | | − * |
| 458 | | − * The following hooks will be run: |
| 459 | | − * 1. `before-highlightall` |
| 460 | | − * 2. `before-all-elements-highlight` |
| 461 | | − * 3. All hooks of {@link Prism.highlightElement} for each element. |
| 462 | | − * |
| 463 | | − * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. |
| 464 | | − * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. |
| 465 | | − * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. |
| 466 | | − * @memberof Prism |
| 467 | | − * @public |
| 468 | | − */ |
| 469 | | − highlightAllUnder: function(container, async, callback) { |
| 470 | | − var env = { |
| 471 | | − callback: callback, |
| 472 | | − container: container, |
| 473 | | − selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' |
| 474 | | − }; |
| 475 | | − |
| 476 | | − _.hooks.run('before-highlightall', env); |
| 562 | + // plugins may change/add the parent/element |
| 563 | + parent = env.element.parentElement; |
| 564 | + if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) { |
| 565 | + parent.setAttribute('tabindex', '0'); |
| 566 | + } |
| 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++];) { |
| 483 | | − _.highlightElement(element, async === true, env.callback); |
| 484 | | − } |
| 485 | | − }, |
| 576 | + if (!env.grammar) { |
| 577 | + insertHighlightedCode(_.util.encode(env.code)); |
| 578 | + return; |
| 579 | + } |
| 486 | 580 | |
| 487 | | − /** |
| 488 | | − * Highlights the code inside a single element. |
| 489 | | − * |
| 490 | | − * The following hooks will be run: |
| 491 | | − * 1. `before-sanity-check` |
| 492 | | − * 2. `before-highlight` |
| 493 | | − * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. |
| 494 | | − * 4. `before-insert` |
| 495 | | − * 5. `after-highlight` |
| 496 | | − * 6. `complete` |
| 497 | | − * |
| 498 | | − * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for |
| 499 | | − * the element's language. |
| 500 | | − * |
| 501 | | − * @param {Element} element The element containing the code. |
| 502 | | − * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. |
| 503 | | − * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers |
| 504 | | − * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is |
| 505 | | − * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). |
| 506 | | − * |
| 507 | | − * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for |
| 508 | | − * asynchronous highlighting to work. You can build your own bundle on the |
| 509 | | − * [Download page](https://prismjs.com/download.html). |
| 510 | | − * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. |
| 511 | | − * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. |
| 512 | | − * @memberof Prism |
| 513 | | − * @public |
| 514 | | − */ |
| 515 | | − highlightElement: function(element, async, callback) { |
| 516 | | − // Find language |
| 517 | | − var language = _.util.getLanguage(element); |
| 518 | | − var grammar = _.languages[language]; |
| 519 | | − |
| 520 | | − // Set language on the element, if not present |
| 521 | | − element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
| 522 | | − |
| 523 | | − // Set language on the parent, for styling |
| 524 | | − var parent = element.parentElement; |
| 525 | | − if (parent && parent.nodeName.toLowerCase() === 'pre') { |
| 526 | | − parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
| 527 | | − } |
| 581 | + if (async && _self.Worker) { |
| 582 | + var worker = new Worker(_.filename); |
| 528 | 583 | |
| 529 | | − var code = element.textContent; |
| 584 | + worker.onmessage = function (evt) { |
| 585 | + insertHighlightedCode(evt.data); |
| 586 | + }; |
| 530 | 587 | |
| 531 | | − var env = { |
| 532 | | − element: element, |
| 533 | | − language: language, |
| 534 | | − grammar: grammar, |
| 535 | | − code: code |
| 536 | | − }; |
| 588 | + worker.postMessage(JSON.stringify({ |
| 589 | + language: env.language, |
| 590 | + code: env.code, |
| 591 | + immediateClose: true |
| 592 | + })); |
| 593 | + } else { |
| 594 | + insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); |
| 595 | + } |
| 596 | + }, |
| 537 | 597 | |
| 538 | | − function insertHighlightedCode(highlightedCode) { |
| 539 | | − env.highlightedCode = highlightedCode; |
| 598 | + /** |
| 599 | + * Low-level function, only use if you know what you’re doing. It accepts a string of text as input |
| 600 | + * and the language definitions to use, and returns a string with the HTML produced. |
| 601 | + * |
| 602 | + * The following hooks will be run: |
| 603 | + * 1. `before-tokenize` |
| 604 | + * 2. `after-tokenize` |
| 605 | + * 3. `wrap`: On each {@link Token}. |
| 606 | + * |
| 607 | + * @param {string} text A string with the code to be highlighted. |
| 608 | + * @param {Grammar} grammar An object containing the tokens to use. |
| 609 | + * |
| 610 | + * Usually a language definition like `Prism.languages.markup`. |
| 611 | + * @param {string} language The name of the language definition passed to `grammar`. |
| 612 | + * @returns {string} The highlighted HTML. |
| 613 | + * @memberof Prism |
| 614 | + * @public |
| 615 | + * @example |
| 616 | + * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); |
| 617 | + */ |
| 618 | + highlight: function (text, grammar, language) { |
| 619 | + var env = { |
| 620 | + code: text, |
| 621 | + grammar: grammar, |
| 622 | + language: language |
| 623 | + }; |
| 624 | + _.hooks.run('before-tokenize', env); |
| 625 | + env.tokens = _.tokenize(env.code, env.grammar); |
| 626 | + _.hooks.run('after-tokenize', env); |
| 627 | + return Token.stringify(_.util.encode(env.tokens), env.language); |
| 628 | + }, |
| 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); |
| 546 | | − _.hooks.run('complete', env); |
| 547 | | − callback && callback.call(env.element); |
| 548 | | − } |
| 664 | + var tokenList = new LinkedList(); |
| 665 | + addAfter(tokenList, tokenList.head, text); |
| 549 | 666 | |
| 550 | | − _.hooks.run('before-sanity-check', env); |
| 667 | + matchGrammar(text, tokenList, grammar, tokenList.head, 0); |
| 551 | 668 | |
| 552 | | − if (!env.code) { |
| 553 | | − _.hooks.run('complete', env); |
| 554 | | − callback && callback.call(env.element); |
| 555 | | − return; |
| 556 | | − } |
| 669 | + return toArray(tokenList); |
| 670 | + }, |
| 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) { |
| 561 | | − insertHighlightedCode(_.util.encode(env.code)); |
| 562 | | − return; |
| 563 | | − } |
| 680 | + /** |
| 681 | + * Adds the given callback to the list of callbacks for the given hook. |
| 682 | + * |
| 683 | + * The callback will be invoked when the hook it is registered for is run. |
| 684 | + * Hooks are usually directly run by a highlight function but you can also run hooks yourself. |
| 685 | + * |
| 686 | + * One callback function can be registered to multiple hooks and the same hook multiple times. |
| 687 | + * |
| 688 | + * @param {string} name The name of the hook. |
| 689 | + * @param {HookCallback} callback The callback function which is given environment variables. |
| 690 | + * @public |
| 691 | + */ |
| 692 | + add: function (name, callback) { |
| 693 | + var hooks = _.hooks.all; |
| 564 | 694 | |
| 565 | | − if (async && _self.Worker) { |
| 566 | | − var worker = new Worker(_.filename); |
| 695 | + hooks[name] = hooks[name] || []; |
| 567 | 696 | |
| 568 | | − worker.onmessage = function(evt) { |
| 569 | | − insertHighlightedCode(evt.data); |
| 570 | | − }; |
| 697 | + hooks[name].push(callback); |
| 698 | + }, |
| 571 | 699 | |
| 572 | | − worker.postMessage(JSON.stringify({ |
| 573 | | − language: env.language, |
| 574 | | − code: env.code, |
| 575 | | − immediateClose: true |
| 576 | | − })); |
| 577 | | − } |
| 578 | | − else { |
| 579 | | − insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); |
| 580 | | − } |
| 581 | | − }, |
| 700 | + /** |
| 701 | + * Runs a hook invoking all registered callbacks with the given environment variables. |
| 702 | + * |
| 703 | + * Callbacks will be invoked synchronously and in the order in which they were registered. |
| 704 | + * |
| 705 | + * @param {string} name The name of the hook. |
| 706 | + * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. |
| 707 | + * @public |
| 708 | + */ |
| 709 | + run: function (name, env) { |
| 710 | + var callbacks = _.hooks.all[name]; |
| 582 | 711 | |
| 583 | | − /** |
| 584 | | − * Low-level function, only use if you know what you’re doing. It accepts a string of text as input |
| 585 | | − * and the language definitions to use, and returns a string with the HTML produced. |
| 586 | | − * |
| 587 | | − * The following hooks will be run: |
| 588 | | − * 1. `before-tokenize` |
| 589 | | − * 2. `after-tokenize` |
| 590 | | − * 3. `wrap`: On each {@link Token}. |
| 591 | | − * |
| 592 | | − * @param {string} text A string with the code to be highlighted. |
| 593 | | − * @param {Grammar} grammar An object containing the tokens to use. |
| 594 | | − * |
| 595 | | − * Usually a language definition like `Prism.languages.markup`. |
| 596 | | − * @param {string} language The name of the language definition passed to `grammar`. |
| 597 | | − * @returns {string} The highlighted HTML. |
| 598 | | − * @memberof Prism |
| 599 | | − * @public |
| 600 | | − * @example |
| 601 | | − * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); |
| 602 | | − */ |
| 603 | | − highlight: function (text, grammar, language) { |
| 604 | | − var env = { |
| 605 | | − code: text, |
| 606 | | − grammar: grammar, |
| 607 | | − language: language |
| 608 | | − }; |
| 609 | | − _.hooks.run('before-tokenize', env); |
| 610 | | − env.tokens = _.tokenize(env.code, env.grammar); |
| 611 | | − _.hooks.run('after-tokenize', env); |
| 612 | | − return Token.stringify(_.util.encode(env.tokens), env.language); |
| 613 | | − }, |
| 712 | + if (!callbacks || !callbacks.length) { |
| 713 | + return; |
| 714 | + } |
| 614 | 715 | |
| 615 | | − /** |
| 616 | | − * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input |
| 617 | | − * and the language definitions to use, and returns an array with the tokenized code. |
| 618 | | − * |
| 619 | | − * When the language definition includes nested tokens, the function is called recursively on each of these tokens. |
| 620 | | − * |
| 621 | | − * This method could be useful in other contexts as well, as a very crude parser. |
| 622 | | − * |
| 623 | | − * @param {string} text A string with the code to be highlighted. |
| 624 | | − * @param {Grammar} grammar An object containing the tokens to use. |
| 625 | | − * |
| 626 | | − * Usually a language definition like `Prism.languages.markup`. |
| 627 | | − * @returns {TokenStream} An array of strings and tokens, a token stream. |
| 628 | | − * @memberof Prism |
| 629 | | − * @public |
| 630 | | − * @example |
| 631 | | − * let code = `var foo = 0;`; |
| 632 | | − * let tokens = Prism.tokenize(code, Prism.languages.javascript); |
| 633 | | − * tokens.forEach(token => { |
| 634 | | − * if (token instanceof Prism.Token && token.type === 'number') { |
| 635 | | − * console.log(`Found numeric literal: ${token.content}`); |
| 636 | | − * } |
| 637 | | − * }); |
| 638 | | − */ |
| 639 | | − tokenize: function(text, grammar) { |
| 640 | | − var rest = grammar.rest; |
| 641 | | − if (rest) { |
| 642 | | − for (var token in rest) { |
| 643 | | − grammar[token] = rest[token]; |
| 716 | + for (var i = 0, callback; (callback = callbacks[i++]);) { |
| 717 | + callback(env); |
| 718 | + } |
| 644 | 719 | } |
| 720 | + }, |
| 645 | 721 | |
| 646 | | − delete grammar.rest; |
| 647 | | − } |
| 648 | | − |
| 649 | | − var tokenList = new LinkedList(); |
| 650 | | − addAfter(tokenList, tokenList.head, text); |
| 722 | + Token: Token |
| 723 | + }; |
| 724 | + _self.Prism = _; |
| 651 | 725 | |
| 652 | | − matchGrammar(text, tokenList, grammar, tokenList.head, 0); |
| 653 | 726 | |
| 654 | | − return toArray(tokenList); |
| 655 | | − }, |
| 727 | + // Typescript note: |
| 728 | + // The following can be used to import the Token type in JSDoc: |
| 729 | + // |
| 730 | + // @typedef {InstanceType<import("./prism-core")["Token"]>} Token |
| 656 | 731 | |
| 657 | 732 | /** |
| 658 | | − * @namespace |
| 659 | | − * @memberof Prism |
| 733 | + * Creates a new token. |
| 734 | + * |
| 735 | + * @param {string} type See {@link Token#type type} |
| 736 | + * @param {string | TokenStream} content See {@link Token#content content} |
| 737 | + * @param {string|string[]} [alias] The alias(es) of the token. |
| 738 | + * @param {string} [matchedStr=""] A copy of the full string this token was created from. |
| 739 | + * @class |
| 740 | + * @global |
| 660 | 741 | * @public |
| 661 | 742 | */ |
| 662 | | − hooks: { |
| 663 | | − all: {}, |
| 664 | | − |
| 743 | + function Token(type, content, alias, matchedStr) { |
| 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. |
| 669 | | − * Hooks are usually directly run by a highlight function but you can also run hooks yourself. |
| 747 | + * This is usually the key of a pattern in a {@link Grammar}. |
| 670 | 748 | * |
| 671 | | − * One callback function can be registered to multiple hooks and the same hook multiple times. |
| 672 | | − * |
| 673 | | − * @param {string} name The name of the hook. |
| 674 | | − * @param {HookCallback} callback The callback function which is given environment variables. |
| 749 | + * @type {string} |
| 750 | + * @see GrammarToken |
| 675 | 751 | * @public |
| 676 | 752 | */ |
| 677 | | − add: function (name, callback) { |
| 678 | | − var hooks = _.hooks.all; |
| 679 | | − |
| 680 | | − hooks[name] = hooks[name] || []; |
| 681 | | − |
| 682 | | − hooks[name].push(callback); |
| 683 | | − }, |
| 684 | | − |
| 753 | + this.type = type; |
| 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. |
| 691 | | − * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. |
| 759 | + * @type {string | TokenStream} |
| 692 | 760 | * @public |
| 693 | 761 | */ |
| 694 | | − run: function (name, env) { |
| 695 | | − var callbacks = _.hooks.all[name]; |
| 696 | | − |
| 697 | | − if (!callbacks || !callbacks.length) { |
| 698 | | − return; |
| 699 | | − } |
| 700 | | − |
| 701 | | − for (var i=0, callback; callback = callbacks[i++];) { |
| 702 | | − callback(env); |
| 703 | | − } |
| 704 | | − } |
| 705 | | − }, |
| 706 | | − |
| 707 | | − Token: Token |
| 708 | | −}; |
| 709 | | −_self.Prism = _; |
| 710 | | − |
| 711 | | − |
| 712 | | −// Typescript note: |
| 713 | | −// The following can be used to import the Token type in JSDoc: |
| 714 | | −// |
| 715 | | −// @typedef {InstanceType<import("./prism-core")["Token"]>} Token |
| 762 | + this.content = content; |
| 763 | + /** |
| 764 | + * The alias(es) of the token. |
| 765 | + * |
| 766 | + * @type {string|string[]} |
| 767 | + * @see GrammarToken |
| 768 | + * @public |
| 769 | + */ |
| 770 | + this.alias = alias; |
| 771 | + // Copy of the full string this token was created from |
| 772 | + this.length = (matchedStr || '').length | 0; |
| 773 | + } |
| 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 | | − */ |
| 728 | | −function 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} |
| 735 | | − * @see GrammarToken |
| 736 | | − * @public |
| 737 | | − */ |
| 738 | | − this.type = type; |
| 739 | | − /** |
| 740 | | − * The strings or tokens contained by this token. |
| 781 | + * 1. No adjacent strings. |
| 782 | + * 2. No empty strings. |
| 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 | 788 | * @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[]} |
| 752 | | − * @see GrammarToken |
| 753 | | − * @public |
| 794 | + * The following hooks will be run: |
| 795 | + * 1. `wrap`: On each {@link Token}. |
| 796 | + * |
| 797 | + * @param {string | Token | TokenStream} o The token or token stream to be converted. |
| 798 | + * @param {string} language The name of current language. |
| 799 | + * @returns {string} The HTML representation of the token or token stream. |
| 800 | + * @memberof Token |
| 801 | + * @static |
| 754 | 802 | */ |
| 755 | | − this.alias = alias; |
| 756 | | − // Copy of the full string this token was created from |
| 757 | | − this.length = (matchedStr || '').length | 0; |
| 758 | | −} |
| 759 | | − |
| 760 | | −/** |
| 761 | | − * A token stream is an array of strings and {@link Token Token} objects. |
| 762 | | − * |
| 763 | | − * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process |
| 764 | | − * them. |
| 765 | | − * |
| 766 | | − * 1. No adjacent strings. |
| 767 | | − * 2. No empty strings. |
| 768 | | − * |
| 769 | | − * The only exception here is the token stream that only contains the empty string and nothing else. |
| 770 | | − * |
| 771 | | − * @typedef {Array<string | Token>} TokenStream |
| 772 | | − * @global |
| 773 | | − * @public |
| 774 | | − */ |
| 775 | | − |
| 776 | | −/** |
| 777 | | − * Converts the given token or token stream to an HTML representation. |
| 778 | | − * |
| 779 | | − * The following hooks will be run: |
| 780 | | − * 1. `wrap`: On each {@link Token}. |
| 781 | | − * |
| 782 | | − * @param {string | Token | TokenStream} o The token or token stream to be converted. |
| 783 | | − * @param {string} language The name of current language. |
| 784 | | − * @returns {string} The HTML representation of the token or token stream. |
| 785 | | − * @memberof Token |
| 786 | | − * @static |
| 787 | | − */ |
| 788 | | −Token.stringify = function stringify(o, language) { |
| 789 | | − if (typeof o == 'string') { |
| 790 | | − return o; |
| 791 | | − } |
| 792 | | − if (Array.isArray(o)) { |
| 793 | | − var s = ''; |
| 794 | | − o.forEach(function (e) { |
| 795 | | − s += stringify(e, language); |
| 796 | | − }); |
| 797 | | − return s; |
| 798 | | − } |
| 799 | | − |
| 800 | | − var env = { |
| 801 | | − type: o.type, |
| 802 | | − content: stringify(o.content, language), |
| 803 | | − tag: 'span', |
| 804 | | − classes: ['token', o.type], |
| 805 | | − attributes: {}, |
| 806 | | − language: language |
| 807 | | − }; |
| 808 | | − |
| 809 | | − var aliases = o.alias; |
| 810 | | − if (aliases) { |
| 811 | | − if (Array.isArray(aliases)) { |
| 812 | | − Array.prototype.push.apply(env.classes, aliases); |
| 813 | | − } else { |
| 814 | | − env.classes.push(aliases); |
| 803 | + Token.stringify = function stringify(o, language) { |
| 804 | + if (typeof o == 'string') { |
| 805 | + return o; |
| 806 | + } |
| 807 | + if (Array.isArray(o)) { |
| 808 | + var s = ''; |
| 809 | + o.forEach(function (e) { |
| 810 | + s += stringify(e, language); |
| 811 | + }); |
| 812 | + return s; |
| 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 = ''; |
| 821 | | − for (var name in env.attributes) { |
| 822 | | − attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; |
| 823 | | − } |
| 824 | + var aliases = o.alias; |
| 825 | + if (aliases) { |
| 826 | + if (Array.isArray(aliases)) { |
| 827 | + Array.prototype.push.apply(env.classes, aliases); |
| 828 | + } else { |
| 829 | + env.classes.push(aliases); |
| 830 | + } |
| 831 | + } |
| 824 | 832 | |
| 825 | | − return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>'; |
| 826 | | −}; |
| 833 | + _.hooks.run('wrap', env); |
| 827 | 834 | |
| 828 | | −/** |
| 829 | | − * @param {RegExp} pattern |
| 830 | | − * @param {number} pos |
| 831 | | − * @param {string} text |
| 832 | | − * @param {boolean} lookbehind |
| 833 | | − * @returns {RegExpExecArray | null} |
| 834 | | − */ |
| 835 | | −function matchPattern(pattern, pos, text, lookbehind) { |
| 836 | | − pattern.lastIndex = pos; |
| 837 | | − var match = pattern.exec(text); |
| 838 | | − if (match && lookbehind && match[1]) { |
| 839 | | − // change the match to remove the text matched by the Prism lookbehind group |
| 840 | | − var lookbehindLength = match[1].length; |
| 841 | | − match.index += lookbehindLength; |
| 842 | | − match[0] = match[0].slice(lookbehindLength); |
| 843 | | − } |
| 844 | | − return match; |
| 845 | | −} |
| 846 | | − |
| 847 | | −/** |
| 848 | | − * @param {string} text |
| 849 | | − * @param {LinkedList<string | Token>} tokenList |
| 850 | | − * @param {any} grammar |
| 851 | | − * @param {LinkedListNode<string | Token>} startNode |
| 852 | | − * @param {number} startPos |
| 853 | | − * @param {RematchOptions} [rematch] |
| 854 | | − * @returns {void} |
| 855 | | − * @private |
| 856 | | − * |
| 857 | | − * @typedef RematchOptions |
| 858 | | − * @property {string} cause |
| 859 | | − * @property {number} reach |
| 860 | | − */ |
| 861 | | −function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) { |
| 862 | | − for (var token in grammar) { |
| 863 | | − if (!grammar.hasOwnProperty(token) || !grammar[token]) { |
| 864 | | − continue; |
| 835 | + var attributes = ''; |
| 836 | + for (var name in env.attributes) { |
| 837 | + attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; |
| 865 | 838 | } |
| 866 | 839 | |
| 867 | | − var patterns = grammar[token]; |
| 868 | | − patterns = Array.isArray(patterns) ? patterns : [patterns]; |
| 869 | | − |
| 870 | | − for (var j = 0; j < patterns.length; ++j) { |
| 871 | | − if (rematch && rematch.cause == token + ',' + j) { |
| 872 | | − return; |
| 873 | | − } |
| 840 | + return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>'; |
| 841 | + }; |
| 874 | 842 | |
| 875 | | − var patternObj = patterns[j], |
| 876 | | − inside = patternObj.inside, |
| 877 | | − lookbehind = !!patternObj.lookbehind, |
| 878 | | − greedy = !!patternObj.greedy, |
| 879 | | − alias = patternObj.alias; |
| 843 | + /** |
| 844 | + * @param {RegExp} pattern |
| 845 | + * @param {number} pos |
| 846 | + * @param {string} text |
| 847 | + * @param {boolean} lookbehind |
| 848 | + * @returns {RegExpExecArray | null} |
| 849 | + */ |
| 850 | + function matchPattern(pattern, pos, text, lookbehind) { |
| 851 | + pattern.lastIndex = pos; |
| 852 | + var match = pattern.exec(text); |
| 853 | + if (match && lookbehind && match[1]) { |
| 854 | + // change the match to remove the text matched by the Prism lookbehind group |
| 855 | + var lookbehindLength = match[1].length; |
| 856 | + match.index += lookbehindLength; |
| 857 | + match[0] = match[0].slice(lookbehindLength); |
| 858 | + } |
| 859 | + return match; |
| 860 | + } |
| 880 | 861 | |
| 881 | | − if (greedy && !patternObj.pattern.global) { |
| 882 | | − // Without the global flag, lastIndex won't work |
| 883 | | − var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; |
| 884 | | − patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g'); |
| 862 | + /** |
| 863 | + * @param {string} text |
| 864 | + * @param {LinkedList<string | Token>} tokenList |
| 865 | + * @param {any} grammar |
| 866 | + * @param {LinkedListNode<string | Token>} startNode |
| 867 | + * @param {number} startPos |
| 868 | + * @param {RematchOptions} [rematch] |
| 869 | + * @returns {void} |
| 870 | + * @private |
| 871 | + * |
| 872 | + * @typedef RematchOptions |
| 873 | + * @property {string} cause |
| 874 | + * @property {number} reach |
| 875 | + */ |
| 876 | + function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) { |
| 877 | + for (var token in grammar) { |
| 878 | + if (!grammar.hasOwnProperty(token) || !grammar[token]) { |
| 879 | + continue; |
| 885 | 880 | } |
| 886 | 881 | |
| 887 | | − /** @type {RegExp} */ |
| 888 | | − var pattern = patternObj.pattern || patternObj; |
| 889 | | − |
| 890 | | − for ( // iterate the token list and keep track of the current token/string position |
| 891 | | − var currentNode = startNode.next, pos = startPos; |
| 892 | | − currentNode !== tokenList.tail; |
| 893 | | − pos += currentNode.value.length, currentNode = currentNode.next |
| 894 | | − ) { |
| 882 | + var patterns = grammar[token]; |
| 883 | + patterns = Array.isArray(patterns) ? patterns : [patterns]; |
| 895 | 884 | |
| 896 | | − if (rematch && pos >= rematch.reach) { |
| 897 | | − break; |
| 885 | + for (var j = 0; j < patterns.length; ++j) { |
| 886 | + if (rematch && rematch.cause == token + ',' + j) { |
| 887 | + return; |
| 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) { |
| 903 | | − // Something went terribly wrong, ABORT, ABORT! |
| 904 | | − return; |
| 896 | + if (greedy && !patternObj.pattern.global) { |
| 897 | + // Without the global flag, lastIndex won't work |
| 898 | + var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; |
| 899 | + patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g'); |
| 905 | 900 | } |
| 906 | 901 | |
| 907 | | − if (str instanceof Token) { |
| 908 | | − continue; |
| 909 | | − } |
| 902 | + /** @type {RegExp} */ |
| 903 | + var pattern = patternObj.pattern || patternObj; |
| 910 | 904 | |
| 911 | | − var removeCount = 1; // this is the to parameter of removeBetween |
| 912 | | − var match; |
| 905 | + for ( // iterate the token list and keep track of the current token/string position |
| 906 | + var currentNode = startNode.next, pos = startPos; |
| 907 | + currentNode !== tokenList.tail; |
| 908 | + pos += currentNode.value.length, currentNode = currentNode.next |
| 909 | + ) { |
| 913 | 910 | |
| 914 | | − if (greedy) { |
| 915 | | − match = matchPattern(pattern, pos, text, lookbehind); |
| 916 | | − if (!match) { |
| 911 | + if (rematch && pos >= rematch.reach) { |
| 917 | 912 | break; |
| 918 | 913 | } |
| 919 | 914 | |
| 920 | | − var from = match.index; |
| 921 | | − var to = match.index + match[0].length; |
| 922 | | − var p = pos; |
| 915 | + var str = currentNode.value; |
| 923 | 916 | |
| 924 | | − // find the node that contains the match |
| 925 | | − p += currentNode.value.length; |
| 926 | | − while (from >= p) { |
| 927 | | − currentNode = currentNode.next; |
| 928 | | − p += currentNode.value.length; |
| 917 | + if (tokenList.length > text.length) { |
| 918 | + // Something went terribly wrong, ABORT, ABORT! |
| 919 | + return; |
| 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 invalid |
| 935 | | − if (currentNode.value instanceof Token) { |
| 922 | + if (str instanceof Token) { |
| 936 | 923 | continue; |
| 937 | 924 | } |
| 938 | 925 | |
| 939 | | − // find the last node which is affected by this match |
| 940 | | − for ( |
| 941 | | − var k = currentNode; |
| 942 | | − k !== tokenList.tail && (p < to || typeof k.value === 'string'); |
| 943 | | − k = k.next |
| 944 | | − ) { |
| 945 | | − removeCount++; |
| 946 | | − p += k.value.length; |
| 947 | | − } |
| 948 | | − removeCount--; |
| 926 | + var removeCount = 1; // this is the to parameter of removeBetween |
| 927 | + var match; |
| 949 | 928 | |
| 950 | | − // replace with the new match |
| 951 | | − str = text.slice(pos, p); |
| 952 | | − match.index -= pos; |
| 953 | | − } else { |
| 954 | | − match = matchPattern(pattern, 0, str, lookbehind); |
| 955 | | − if (!match) { |
| 956 | | − continue; |
| 929 | + if (greedy) { |
| 930 | + match = matchPattern(pattern, pos, text, lookbehind); |
| 931 | + if (!match) { |
| 932 | + break; |
| 933 | + } |
| 934 | + |
| 935 | + var from = match.index; |
| 936 | + var to = match.index + match[0].length; |
| 937 | + var p = pos; |
| 938 | + |
| 939 | + // find the node that contains the match |
| 940 | + p += currentNode.value.length; |
| 941 | + while (from >= p) { |
| 942 | + currentNode = currentNode.next; |
| 943 | + p += currentNode.value.length; |
| 944 | + } |
| 945 | + // adjust pos (and p) |
| 946 | + p -= currentNode.value.length; |
| 947 | + pos = p; |
| 948 | + |
| 949 | + // the current node is a Token, then the match starts inside another Token, which is invalid |
| 950 | + if (currentNode.value instanceof Token) { |
| 951 | + continue; |
| 952 | + } |
| 953 | + |
| 954 | + // find the last node which is affected by this match |
| 955 | + for ( |
| 956 | + var k = currentNode; |
| 957 | + k !== tokenList.tail && (p < to || typeof k.value === 'string'); |
| 958 | + k = k.next |
| 959 | + ) { |
| 960 | + removeCount++; |
| 961 | + p += k.value.length; |
| 962 | + } |
| 963 | + removeCount--; |
| 964 | + |
| 965 | + // replace with the new match |
| 966 | + str = text.slice(pos, p); |
| 967 | + match.index -= pos; |
| 968 | + } else { |
| 969 | + match = matchPattern(pattern, 0, str, lookbehind); |
| 970 | + if (!match) { |
| 971 | + continue; |
| 972 | + } |
| 957 | 973 | } |
| 958 | | − } |
| 959 | 974 | |
| 960 | | − var from = match.index, |
| 961 | | − matchStr = match[0], |
| 962 | | − before = str.slice(0, from), |
| 963 | | − after = str.slice(from + matchStr.length); |
| 975 | + // eslint-disable-next-line no-redeclare |
| 976 | + var from = match.index; |
| 977 | + var matchStr = match[0]; |
| 978 | + var before = str.slice(0, from); |
| 979 | + var after = str.slice(from + matchStr.length); |
| 964 | 980 | |
| 965 | | − var reach = pos + str.length; |
| 966 | | − if (rematch && reach > rematch.reach) { |
| 967 | | − rematch.reach = reach; |
| 968 | | − } |
| 981 | + var reach = pos + str.length; |
| 982 | + if (rematch && reach > rematch.reach) { |
| 983 | + rematch.reach = reach; |
| 984 | + } |
| 969 | 985 | |
| 970 | | − var removeFrom = currentNode.prev; |
| 986 | + var removeFrom = currentNode.prev; |
| 971 | 987 | |
| 972 | | − if (before) { |
| 973 | | − removeFrom = addAfter(tokenList, removeFrom, before); |
| 974 | | − pos += before.length; |
| 975 | | − } |
| 988 | + if (before) { |
| 989 | + removeFrom = addAfter(tokenList, removeFrom, before); |
| 990 | + pos += before.length; |
| 991 | + } |
| 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); |
| 980 | | − currentNode = addAfter(tokenList, removeFrom, wrapped); |
| 995 | + var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr); |
| 996 | + currentNode = addAfter(tokenList, removeFrom, wrapped); |
| 981 | 997 | |
| 982 | | − if (after) { |
| 983 | | − addAfter(tokenList, currentNode, after); |
| 984 | | − } |
| 998 | + if (after) { |
| 999 | + addAfter(tokenList, currentNode, after); |
| 1000 | + } |
| 985 | 1001 | |
| 986 | | − if (removeCount > 1) { |
| 987 | | − // at least one Token object was removed, so we have to do some rematching |
| 988 | | − // this can only happen if the current pattern is greedy |
| 1002 | + if (removeCount > 1) { |
| 1003 | + // at least one Token object was removed, so we have to do some rematching |
| 1004 | + // this can only happen if the current pattern is greedy |
| 989 | 1005 | |
| 990 | | − /** @type {RematchOptions} */ |
| 991 | | − var nestedRematch = { |
| 992 | | − cause: token + ',' + j, |
| 993 | | − reach: reach |
| 994 | | − }; |
| 995 | | − matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch); |
| 1006 | + /** @type {RematchOptions} */ |
| 1007 | + var nestedRematch = { |
| 1008 | + cause: token + ',' + j, |
| 1009 | + reach: reach |
| 1010 | + }; |
| 1011 | + matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch); |
| 996 | 1012 | |
| 997 | | − // the reach might have been extended because of the rematching |
| 998 | | − if (rematch && nestedRematch.reach > rematch.reach) { |
| 999 | | − rematch.reach = nestedRematch.reach; |
| 1013 | + // the reach might have been extended because of the rematching |
| 1014 | + if (rematch && nestedRematch.reach > rematch.reach) { |
| 1015 | + rematch.reach = nestedRematch.reach; |
| 1016 | + } |
| 1000 | 1017 | } |
| 1001 | 1018 | } |
| 1002 | 1019 | } |
| 1003 | 1020 | } |
| 1004 | 1021 | } |
| 1005 | | −} |
| 1006 | 1022 | |
| 1007 | | −/** |
| 1008 | | − * @typedef LinkedListNode |
| 1009 | | − * @property {T} value |
| 1010 | | − * @property {LinkedListNode<T> | null} prev The previous node. |
| 1011 | | − * @property {LinkedListNode<T> | null} next The next node. |
| 1012 | | − * @template T |
| 1013 | | − * @private |
| 1014 | | − */ |
| 1023 | + /** |
| 1024 | + * @typedef LinkedListNode |
| 1025 | + * @property {T} value |
| 1026 | + * @property {LinkedListNode<T> | null} prev The previous node. |
| 1027 | + * @property {LinkedListNode<T> | null} next The next node. |
| 1028 | + * @template T |
| 1029 | + * @private |
| 1030 | + */ |
| 1015 | 1031 | |
| 1016 | | −/** |
| 1017 | | − * @template T |
| 1018 | | − * @private |
| 1019 | | − */ |
| 1020 | | −function LinkedList() { |
| 1021 | | − /** @type {LinkedListNode<T>} */ |
| 1022 | | − var head = { value: null, prev: null, next: null }; |
| 1023 | | − /** @type {LinkedListNode<T>} */ |
| 1024 | | − var tail = { value: null, prev: head, next: null }; |
| 1025 | | − head.next = tail; |
| 1026 | | − |
| 1027 | | − /** @type {LinkedListNode<T>} */ |
| 1028 | | − this.head = head; |
| 1029 | | − /** @type {LinkedListNode<T>} */ |
| 1030 | | − this.tail = tail; |
| 1031 | | − this.length = 0; |
| 1032 | | −} |
| 1032 | + /** |
| 1033 | + * @template T |
| 1034 | + * @private |
| 1035 | + */ |
| 1036 | + function LinkedList() { |
| 1037 | + /** @type {LinkedListNode<T>} */ |
| 1038 | + var head = { value: null, prev: null, next: null }; |
| 1039 | + /** @type {LinkedListNode<T>} */ |
| 1040 | + var tail = { value: null, prev: head, next: null }; |
| 1041 | + head.next = tail; |
| 1042 | + |
| 1043 | + /** @type {LinkedListNode<T>} */ |
| 1044 | + this.head = head; |
| 1045 | + /** @type {LinkedListNode<T>} */ |
| 1046 | + this.tail = tail; |
| 1047 | + this.length = 0; |
| 1048 | + } |
| 1033 | 1049 | |
| 1034 | | −/** |
| 1035 | | − * Adds a new node with the given value to the list. |
| 1036 | | − * @param {LinkedList<T>} list |
| 1037 | | − * @param {LinkedListNode<T>} node |
| 1038 | | − * @param {T} value |
| 1039 | | − * @returns {LinkedListNode<T>} The added node. |
| 1040 | | − * @template T |
| 1041 | | − */ |
| 1042 | | −function addAfter(list, node, value) { |
| 1043 | | − // assumes that node != list.tail && values.length >= 0 |
| 1044 | | − var next = node.next; |
| 1050 | + /** |
| 1051 | + * Adds a new node with the given value to the list. |
| 1052 | + * |
| 1053 | + * @param {LinkedList<T>} list |
| 1054 | + * @param {LinkedListNode<T>} node |
| 1055 | + * @param {T} value |
| 1056 | + * @returns {LinkedListNode<T>} The added node. |
| 1057 | + * @template T |
| 1058 | + */ |
| 1059 | + function addAfter(list, node, value) { |
| 1060 | + // assumes that node != list.tail && values.length >= 0 |
| 1061 | + var next = node.next; |
| 1045 | 1062 | |
| 1046 | | − var newNode = { value: value, prev: node, next: next }; |
| 1047 | | − node.next = newNode; |
| 1048 | | − next.prev = newNode; |
| 1049 | | − list.length++; |
| 1063 | + var newNode = { value: value, prev: node, next: next }; |
| 1064 | + node.next = newNode; |
| 1065 | + next.prev = newNode; |
| 1066 | + list.length++; |
| 1050 | 1067 | |
| 1051 | | − return newNode; |
| 1052 | | −} |
| 1053 | | −/** |
| 1054 | | − * Removes `count` nodes after the given node. The given node will not be removed. |
| 1055 | | − * @param {LinkedList<T>} list |
| 1056 | | − * @param {LinkedListNode<T>} node |
| 1057 | | − * @param {number} count |
| 1058 | | − * @template T |
| 1059 | | − */ |
| 1060 | | −function removeRange(list, node, count) { |
| 1061 | | − var next = node.next; |
| 1062 | | − for (var i = 0; i < count && next !== list.tail; i++) { |
| 1063 | | − next = next.next; |
| 1068 | + return newNode; |
| 1064 | 1069 | } |
| 1065 | | − node.next = next; |
| 1066 | | − next.prev = node; |
| 1067 | | − list.length -= i; |
| 1068 | | −} |
| 1069 | | −/** |
| 1070 | | − * @param {LinkedList<T>} list |
| 1071 | | − * @returns {T[]} |
| 1072 | | − * @template T |
| 1073 | | − */ |
| 1074 | | −function toArray(list) { |
| 1075 | | − var array = []; |
| 1076 | | − var node = list.head.next; |
| 1077 | | − while (node !== list.tail) { |
| 1078 | | − array.push(node.value); |
| 1079 | | − node = node.next; |
| 1070 | + /** |
| 1071 | + * Removes `count` nodes after the given node. The given node will not be removed. |
| 1072 | + * |
| 1073 | + * @param {LinkedList<T>} list |
| 1074 | + * @param {LinkedListNode<T>} node |
| 1075 | + * @param {number} count |
| 1076 | + * @template T |
| 1077 | + */ |
| 1078 | + function removeRange(list, node, count) { |
| 1079 | + var next = node.next; |
| 1080 | + for (var i = 0; i < count && next !== list.tail; i++) { |
| 1081 | + next = next.next; |
| 1082 | + } |
| 1083 | + node.next = next; |
| 1084 | + next.prev = node; |
| 1085 | + list.length -= i; |
| 1086 | + } |
| 1087 | + /** |
| 1088 | + * @param {LinkedList<T>} list |
| 1089 | + * @returns {T[]} |
| 1090 | + * @template T |
| 1091 | + */ |
| 1092 | + function toArray(list) { |
| 1093 | + var array = []; |
| 1094 | + var node = list.head.next; |
| 1095 | + while (node !== list.tail) { |
| 1096 | + array.push(node.value); |
| 1097 | + node = node.next; |
| 1098 | + } |
| 1099 | + return array; |
| 1080 | 1100 | } |
| 1081 | | − return array; |
| 1082 | | −} |
| 1083 | 1101 | |
| 1084 | 1102 | |
| 1085 | | −if (!_self.document) { |
| 1086 | | − if (!_self.addEventListener) { |
| 1087 | | − // in Node.js |
| 1088 | | − return _; |
| 1089 | | − } |
| 1103 | + if (!_self.document) { |
| 1104 | + if (!_self.addEventListener) { |
| 1105 | + // in Node.js |
| 1106 | + return _; |
| 1107 | + } |
| 1090 | 1108 | |
| 1091 | | − if (!_.disableWorkerMessageHandler) { |
| 1092 | | − // In worker |
| 1093 | | − _self.addEventListener('message', function (evt) { |
| 1094 | | − var message = JSON.parse(evt.data), |
| 1095 | | − lang = message.language, |
| 1096 | | − code = message.code, |
| 1097 | | − immediateClose = message.immediateClose; |
| 1098 | | − |
| 1099 | | − _self.postMessage(_.highlight(code, _.languages[lang], lang)); |
| 1100 | | − if (immediateClose) { |
| 1101 | | − _self.close(); |
| 1102 | | − } |
| 1103 | | − }, false); |
| 1104 | | − } |
| 1109 | + if (!_.disableWorkerMessageHandler) { |
| 1110 | + // In worker |
| 1111 | + _self.addEventListener('message', function (evt) { |
| 1112 | + var message = JSON.parse(evt.data); |
| 1113 | + var lang = message.language; |
| 1114 | + var code = message.code; |
| 1115 | + var immediateClose = message.immediateClose; |
| 1116 | + |
| 1117 | + _self.postMessage(_.highlight(code, _.languages[lang], lang)); |
| 1118 | + if (immediateClose) { |
| 1119 | + _self.close(); |
| 1120 | + } |
| 1121 | + }, false); |
| 1122 | + } |
| 1105 | 1123 | |
| 1106 | | − return _; |
| 1107 | | −} |
| 1124 | + return _; |
| 1125 | + } |
| 1108 | 1126 | |
| 1109 | | −// Get current script and highlight |
| 1110 | | −var script = _.util.currentScript(); |
| 1127 | + // Get current script and highlight |
| 1128 | + var script = _.util.currentScript(); |
| 1111 | 1129 | |
| 1112 | | −if (script) { |
| 1113 | | − _.filename = script.src; |
| 1130 | + if (script) { |
| 1131 | + _.filename = script.src; |
| 1114 | 1132 | |
| 1115 | | − if (script.hasAttribute('data-manual')) { |
| 1116 | | − _.manual = true; |
| 1133 | + if (script.hasAttribute('data-manual')) { |
| 1134 | + _.manual = true; |
| 1135 | + } |
| 1117 | 1136 | } |
| 1118 | | −} |
| 1119 | 1137 | |
| 1120 | | −function highlightAutomaticallyCallback() { |
| 1121 | | − if (!_.manual) { |
| 1122 | | − _.highlightAll(); |
| 1138 | + function highlightAutomaticallyCallback() { |
| 1139 | + if (!_.manual) { |
| 1140 | + _.highlightAll(); |
| 1141 | + } |
| 1123 | 1142 | } |
| 1124 | | −} |
| 1125 | 1143 | |
| 1126 | | −if (!_.manual) { |
| 1127 | | − // If the document state is "loading", then we'll use DOMContentLoaded. |
| 1128 | | − // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the |
| 1129 | | − // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they |
| 1130 | | − // might take longer one animation frame to execute which can create a race condition where only some plugins have |
| 1131 | | − // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. |
| 1132 | | − // See https://github.com/PrismJS/prism/issues/2102 |
| 1133 | | − var readyState = document.readyState; |
| 1134 | | − if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { |
| 1135 | | − document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); |
| 1136 | | − } else { |
| 1137 | | − if (window.requestAnimationFrame) { |
| 1138 | | − window.requestAnimationFrame(highlightAutomaticallyCallback); |
| 1144 | + if (!_.manual) { |
| 1145 | + // If the document state is "loading", then we'll use DOMContentLoaded. |
| 1146 | + // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the |
| 1147 | + // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they |
| 1148 | + // might take longer one animation frame to execute which can create a race condition where only some plugins have |
| 1149 | + // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded. |
| 1150 | + // See https://github.com/PrismJS/prism/issues/2102 |
| 1151 | + var readyState = document.readyState; |
| 1152 | + if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { |
| 1153 | + document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); |
| 1139 | 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 | |
| 1145 | | −return _; |
| 1163 | + return _; |
| 1146 | 1164 | |
| 1147 | | −})(_self); |
| 1165 | +}(_self)); |
| 1148 | 1166 | |
| 1149 | 1167 | if (typeof module !== 'undefined' && module.exports) { |
| 1150 | 1168 | module.exports = Prism; |
| @@ -1176,7 +1194,7 @@ if (typeof global !== 'undefined') { · 25 unmodified lines |
| 1176 | 1194 | * each another. |
| 1177 | 1195 | * @global |
| 1178 | 1196 | * @public |
| 1179 | | −*/ |
| 1197 | + */ |
| 1180 | 1198 | |
| 1181 | 1199 | /** |
| 1182 | 1200 | * @typedef Grammar |
| @@ -1194,7 +1212,7 @@ if (typeof global !== 'undefined') { · 11 unmodified lines |
| 1194 | 1212 | * @returns {void} |
| 1195 | 1213 | * @global |
| 1196 | 1214 | * @public |
| 1197 | | −*/ |
| 1215 | + */ |
| 1198 | 1216 | |
| 1199 | 1217 | /** |
| 1200 | 1218 | * @callback HookCallback |
| @@ -1239,6 +1257,7 @@ Prism.languages.markup = { · 38 unmodified lines |
| 1239 | 1257 | 'namespace': /^[^\s>\/:]+:/ |
| 1240 | 1258 | } |
| 1241 | 1259 | }, |
| 1260 | + 'special-attr': [], |
| 1242 | 1261 | 'attr-value': { |
| 1243 | 1262 | pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, |
| 1244 | 1263 | inside: { |
| @@ -1325,6 +1344,49 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { · 80 unmodified lines |
| 1325 | 1344 | Prism.languages.insertBefore('markup', 'cdata', def); |
| 1326 | 1345 | } |
| 1327 | 1346 | }); |
| 1347 | +Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', { |
| 1348 | + /** |
| 1349 | + * Adds an pattern to highlight languages embedded in HTML attributes. |
| 1350 | + * |
| 1351 | + * An example of an inlined language is CSS with `style` attributes. |
| 1352 | + * |
| 1353 | + * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as |
| 1354 | + * case insensitive. |
| 1355 | + * @param {string} lang The language key. |
| 1356 | + * @example |
| 1357 | + * addAttribute('style', 'css'); |
| 1358 | + */ |
| 1359 | + value: function (attrName, lang) { |
| 1360 | + Prism.languages.markup.tag.inside['special-attr'].push({ |
| 1361 | + pattern: RegExp( |
| 1362 | + /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, |
| 1363 | + 'i' |
| 1364 | + ), |
| 1365 | + lookbehind: true, |
| 1366 | + inside: { |
| 1367 | + 'attr-name': /^[^\s=]+/, |
| 1368 | + 'attr-value': { |
| 1369 | + pattern: /=[\s\S]+/, |
| 1370 | + inside: { |
| 1371 | + 'value': { |
| 1372 | + pattern: /(=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, |
| 1373 | + lookbehind: true, |
| 1374 | + alias: [lang, 'language-' + lang], |
| 1375 | + inside: Prism.languages[lang] |
| 1376 | + }, |
| 1377 | + 'punctuation': [ |
| 1378 | + { |
| 1379 | + pattern: /^=/, |
| 1380 | + alias: 'attr-equals' |
| 1381 | + }, |
| 1382 | + /"|'/ |
| 1383 | + ] |
| 1384 | + } |
| 1385 | + } |
| 1386 | + } |
| 1387 | + }); |
| 1388 | + } |
| 1389 | +}); |
| 1328 | 1390 | |
| 1329 | 1391 | Prism.languages.html = Prism.languages.markup; |
| 1330 | 1392 | Prism.languages.mathml = Prism.languages.markup; |
| @@ -1386,34 +1448,7 @@ Prism.languages.rss = Prism.languages.xml; · 55 unmodified lines |
| 1386 | 1448 | var markup = Prism.languages.markup; |
| 1387 | 1449 | if (markup) { |
| 1388 | 1450 | markup.tag.addInlined('style', 'css'); |
| 1389 | | − |
| 1390 | | − Prism.languages.insertBefore('inside', 'attr-value', { |
| 1391 | | − 'style-attr': { |
| 1392 | | − pattern: /(^|["'\s])style\s*=\s*(?:"[^"]*"|'[^']*')/i, |
| 1393 | | − lookbehind: true, |
| 1394 | | − inside: { |
| 1395 | | − 'attr-value': { |
| 1396 | | − pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, |
| 1397 | | − inside: { |
| 1398 | | − 'style': { |
| 1399 | | − pattern: /(["'])[\s\S]+(?=["']$)/, |
| 1400 | | − lookbehind: true, |
| 1401 | | − alias: 'language-css', |
| 1402 | | − inside: Prism.languages.css |
| 1403 | | − }, |
| 1404 | | − 'punctuation': [ |
| 1405 | | − { |
| 1406 | | − pattern: /^=/, |
| 1407 | | − alias: 'attr-equals' |
| 1408 | | − }, |
| 1409 | | − /"|'/ |
| 1410 | | − ] |
| 1411 | | − } |
| 1412 | | − }, |
| 1413 | | − 'attr-name': /^style/i |
| 1414 | | − } |
| 1415 | | − } |
| 1416 | | − }, markup.tag); |
| 1451 | + markup.tag.addAttribute('style', 'css'); |
| 1417 | 1452 | } |
| 1418 | 1453 | |
| 1419 | 1454 | }(Prism)); |
| @@ -1464,7 +1499,7 @@ Prism.languages.javascript = Prism.languages.extend('clike', { · 44 unmodified lines |
| 1464 | 1499 | 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 | 1503 | 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 | |
| 1479 | 1514 | Prism.languages.insertBefore('javascript', 'keyword', { |
| 1480 | 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 | 1517 | lookbehind: true, |
| 1483 | 1518 | greedy: true, |
| 1484 | 1519 | inside: { |
| @@ -1522,6 +1557,11 @@ Prism.languages.insertBefore('javascript', 'keyword', { · 37 unmodified lines |
| 1522 | 1557 | }); |
| 1523 | 1558 | |
| 1524 | 1559 | Prism.languages.insertBefore('javascript', 'string', { |
| 1560 | + 'hashbang': { |
| 1561 | + pattern: /^#!.*/, |
| 1562 | + greedy: true, |
| 1563 | + alias: 'comment' |
| 1564 | + }, |
| 1525 | 1565 | 'template-string': { |
| 1526 | 1566 | pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/, |
| 1527 | 1567 | greedy: true, |
| @@ -1548,11 +1588,18 @@ Prism.languages.insertBefore('javascript', 'string', { · 20 unmodified lines |
| 1548 | 1588 | |
| 1549 | 1589 | if (Prism.languages.markup) { |
| 1550 | 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 | |
| 1553 | 1600 | Prism.languages.js = Prism.languages.javascript; |
| 1554 | 1601 | |
| 1555 | | −(function(Prism) { |
| 1602 | +(function (Prism) { |
| 1556 | 1603 | // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|' |
| 1557 | 1604 | // + LC_ALL, RANDOM, REPLY, SECONDS. |
| 1558 | 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 | 1616 | var insideString = { |
| 1570 | 1617 | 'bash': commandAfterHeredoc, |
| 1571 | 1618 | 'environment': { |
| 1572 | | − pattern: RegExp("\\$" + envVars), |
| 1619 | + pattern: RegExp('\\$' + envVars), |
| 1573 | 1620 | alias: 'constant' |
| 1574 | 1621 | }, |
| 1575 | 1622 | 'variable': [ |
| @@ -1609,7 +1656,7 @@ Prism.languages.js = Prism.languages.javascript; · 33 unmodified lines |
| 1609 | 1656 | 'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, |
| 1610 | 1657 | 'punctuation': /[\[\]]/, |
| 1611 | 1658 | 'environment': { |
| 1612 | | − pattern: RegExp("(\\{)" + envVars), |
| 1659 | + pattern: RegExp('(\\{)' + envVars), |
| 1613 | 1660 | lookbehind: true, |
| 1614 | 1661 | alias: 'constant' |
| 1615 | 1662 | } |
| @@ -1637,13 +1684,13 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines |
| 1637 | 1684 | // but not “foo {” |
| 1638 | 1685 | { |
| 1639 | 1686 | // a) and c) |
| 1640 | | − pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/, |
| 1687 | + pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/, |
| 1641 | 1688 | lookbehind: true, |
| 1642 | 1689 | alias: 'function' |
| 1643 | 1690 | }, |
| 1644 | 1691 | { |
| 1645 | 1692 | // b) |
| 1646 | | − pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/, |
| 1693 | + pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/, |
| 1647 | 1694 | alias: 'function' |
| 1648 | 1695 | } |
| 1649 | 1696 | ], |
| @@ -1659,7 +1706,7 @@ Prism.languages.js = Prism.languages.javascript; · 9 unmodified lines |
| 1659 | 1706 | pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/, |
| 1660 | 1707 | inside: { |
| 1661 | 1708 | 'environment': { |
| 1662 | | − pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars), |
| 1709 | + pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars), |
| 1663 | 1710 | lookbehind: true, |
| 1664 | 1711 | alias: 'constant' |
| 1665 | 1712 | } |
| @@ -1687,14 +1734,29 @@ Prism.languages.js = Prism.languages.javascript; · 21 unmodified lines |
| 1687 | 1734 | }, |
| 1688 | 1735 | // “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 | 1739 | lookbehind: true, |
| 1692 | 1740 | greedy: true, |
| 1693 | 1741 | 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 | 1758 | 'environment': { |
| 1697 | | − pattern: RegExp("\\$?" + envVars), |
| 1759 | + pattern: RegExp('\\$?' + envVars), |
| 1698 | 1760 | alias: 'constant' |
| 1699 | 1761 | }, |
| 1700 | 1762 | 'variable': insideString.variable, |
| @@ -1758,12 +1820,12 @@ Prism.languages.js = Prism.languages.javascript; · 57 unmodified lines |
| 1758 | 1820 | 'number' |
| 1759 | 1821 | ]; |
| 1760 | 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 | 1824 | inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]]; |
| 1763 | 1825 | } |
| 1764 | 1826 | |
| 1765 | 1827 | Prism.languages.shell = Prism.languages.bash; |
| 1766 | | −})(Prism); |
| 1828 | +}(Prism)); |
| 1767 | 1829 | |
| 1768 | 1830 | Prism.languages.c = Prism.languages.extend('clike', { |
| 1769 | 1831 | 'comment': { |
| @@ -1831,7 +1893,8 @@ delete Prism.languages.c['boolean']; · 61 unmodified lines |
| 1831 | 1893 | |
| 1832 | 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 | 1899 | Prism.languages.cpp = Prism.languages.extend('c', { |
| 1837 | 1900 | 'class-name': [ |
| @@ -1857,11 +1920,31 @@ delete Prism.languages.c['boolean']; · 19 unmodified lines |
| 1857 | 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 | 1921 | 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 | 1924 | 'boolean': /\b(?:true|false)\b/ |
| 1862 | 1925 | }); |
| 1863 | 1926 | |
| 1864 | 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 | 1948 | 'raw-string': { |
| 1866 | 1949 | pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, |
| 1867 | 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 | 1976 | Prism.languages.insertBefore('cpp', 'class-name', { |
| 1873 | 1977 | // the base clause is an optional list of parent classes |
| 1874 | 1978 | // https://en.cppreference.com/w/cpp/language/class |
| @@ -1879,108 +1983,109 @@ delete Prism.languages.c['boolean']; · 4 unmodified lines |
| 1879 | 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 | 1988 | // All untokenized words that are not namespaces should be class names |
| 1884 | 1989 | 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i |
| 1885 | 1990 | }, Prism.languages.cpp['base-clause']); |
| 1886 | 1991 | |
| 1887 | 1992 | }(Prism)); |
| 1888 | 1993 | |
| 1889 | | −(function(Prism) { |
| 1890 | | − |
| 1891 | | −// Ignore comments starting with { to privilege string interpolation highlighting |
| 1892 | | −var comment = /#(?!\{).+/, |
| 1893 | | − interpolation = { |
| 1894 | | − pattern: /#\{[^}]+\}/, |
| 1895 | | − alias: 'variable' |
| 1896 | | − }; |
| 1994 | +(function (Prism) { |
| 1897 | 1995 | |
| 1898 | | −Prism.languages.coffeescript = Prism.languages.extend('javascript', { |
| 1899 | | − 'comment': comment, |
| 1900 | | − 'string': [ |
| 1996 | + // Ignore comments starting with { to privilege string interpolation highlighting |
| 1997 | + var comment = /#(?!\{).+/; |
| 1998 | + var interpolation = { |
| 1999 | + pattern: /#\{[^}]+\}/, |
| 2000 | + alias: 'variable' |
| 2001 | + }; |
| 1901 | 2002 | |
| 1902 | | − // Strings are multiline |
| 1903 | | − { |
| 1904 | | − pattern: /'(?:\\[\s\S]|[^\\'])*'/, |
| 1905 | | − greedy: true |
| 1906 | | − }, |
| 2003 | + Prism.languages.coffeescript = Prism.languages.extend('javascript', { |
| 2004 | + 'comment': comment, |
| 2005 | + 'string': [ |
| 1907 | 2006 | |
| 1908 | | − { |
| 1909 | 2007 | // Strings are multiline |
| 1910 | | − pattern: /"(?:\\[\s\S]|[^\\"])*"/, |
| 1911 | | − greedy: true, |
| 1912 | | − inside: { |
| 1913 | | − 'interpolation': interpolation |
| 2008 | + { |
| 2009 | + pattern: /'(?:\\[\s\S]|[^\\'])*'/, |
| 2010 | + greedy: true |
| 2011 | + }, |
| 2012 | + |
| 2013 | + { |
| 2014 | + // Strings are multiline |
| 2015 | + pattern: /"(?:\\[\s\S]|[^\\"])*"/, |
| 2016 | + greedy: true, |
| 2017 | + inside: { |
| 2018 | + 'interpolation': interpolation |
| 2019 | + } |
| 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 | | − ], |
| 1917 | | − 'keyword': /\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/, |
| 1918 | | − 'class-member': { |
| 1919 | | − pattern: /@(?!\d)\w+/, |
| 1920 | | − alias: 'variable' |
| 1921 | | − } |
| 1922 | | −}); |
| 1923 | | − |
| 1924 | | −Prism.languages.insertBefore('coffeescript', 'comment', { |
| 1925 | | − 'multiline-comment': { |
| 1926 | | − pattern: /###[\s\S]+?###/, |
| 1927 | | − alias: 'comment' |
| 1928 | | − }, |
| 2027 | + }); |
| 1929 | 2028 | |
| 1930 | | − // Block regexp can contain comments and interpolation |
| 1931 | | − 'block-regex': { |
| 1932 | | − pattern: /\/{3}[\s\S]*?\/{3}/, |
| 1933 | | − alias: 'regex', |
| 1934 | | − inside: { |
| 1935 | | − 'comment': comment, |
| 1936 | | − 'interpolation': interpolation |
| 1937 | | − } |
| 1938 | | − } |
| 1939 | | −}); |
| 2029 | + Prism.languages.insertBefore('coffeescript', 'comment', { |
| 2030 | + 'multiline-comment': { |
| 2031 | + pattern: /###[\s\S]+?###/, |
| 2032 | + alias: 'comment' |
| 2033 | + }, |
| 1940 | 2034 | |
| 1941 | | −Prism.languages.insertBefore('coffeescript', 'string', { |
| 1942 | | − 'inline-javascript': { |
| 1943 | | − pattern: /`(?:\\[\s\S]|[^\\`])*`/, |
| 1944 | | − inside: { |
| 1945 | | − 'delimiter': { |
| 1946 | | − pattern: /^`|`$/, |
| 1947 | | − alias: 'punctuation' |
| 1948 | | − }, |
| 1949 | | − 'script': { |
| 1950 | | − pattern: /[\s\S]+/, |
| 1951 | | − alias: 'language-javascript', |
| 1952 | | − inside: Prism.languages.javascript |
| 2035 | + // Block regexp can contain comments and interpolation |
| 2036 | + 'block-regex': { |
| 2037 | + pattern: /\/{3}[\s\S]*?\/{3}/, |
| 2038 | + alias: 'regex', |
| 2039 | + inside: { |
| 2040 | + 'comment': comment, |
| 2041 | + 'interpolation': interpolation |
| 1953 | 2042 | } |
| 1954 | 2043 | } |
| 1955 | | − }, |
| 2044 | + }); |
| 1956 | 2045 | |
| 1957 | | − // Block strings |
| 1958 | | − 'multiline-string': [ |
| 1959 | | − { |
| 1960 | | − pattern: /'''[\s\S]*?'''/, |
| 1961 | | − greedy: true, |
| 1962 | | − alias: 'string' |
| 1963 | | − }, |
| 1964 | | − { |
| 1965 | | − pattern: /"""[\s\S]*?"""/, |
| 1966 | | − greedy: true, |
| 1967 | | − alias: 'string', |
| 2046 | + Prism.languages.insertBefore('coffeescript', 'string', { |
| 2047 | + 'inline-javascript': { |
| 2048 | + pattern: /`(?:\\[\s\S]|[^\\`])*`/, |
| 1968 | 2049 | inside: { |
| 1969 | | − interpolation: interpolation |
| 2050 | + 'delimiter': { |
| 2051 | + pattern: /^`|`$/, |
| 2052 | + alias: 'punctuation' |
| 2053 | + }, |
| 2054 | + 'script': { |
| 2055 | + pattern: /[\s\S]+/, |
| 2056 | + alias: 'language-javascript', |
| 2057 | + inside: Prism.languages.javascript |
| 2058 | + } |
| 1970 | 2059 | } |
| 1971 | | − } |
| 1972 | | − ] |
| 2060 | + }, |
| 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 | |
| 1976 | | −Prism.languages.insertBefore('coffeescript', 'keyword', { |
| 1977 | | − // Object property |
| 1978 | | − 'property': /(?!\d)\w+(?=\s*:(?!:))/ |
| 1979 | | −}); |
| 2079 | + }); |
| 2080 | + |
| 2081 | + Prism.languages.insertBefore('coffeescript', 'keyword', { |
| 2082 | + // Object property |
| 2083 | + 'property': /(?!\d)\w+(?=\s*:(?!:))/ |
| 2084 | + }); |
| 1980 | 2085 | |
| 1981 | | −delete Prism.languages.coffeescript['template-string']; |
| 2086 | + delete Prism.languages.coffeescript['template-string']; |
| 1982 | 2087 | |
| 1983 | | −Prism.languages.coffee = Prism.languages.coffeescript; |
| 2088 | + Prism.languages.coffee = Prism.languages.coffeescript; |
| 1984 | 2089 | }(Prism)); |
| 1985 | 2090 | |
| 1986 | 2091 | /** |
| @@ -2025,22 +2130,25 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 38 unmodified lines |
| 2025 | 2130 | 'regex': [ |
| 2026 | 2131 | { |
| 2027 | 2132 | pattern: RegExp(/%r/.source + '(?:' + [ |
| 2028 | | − /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[gim]{0,3}/.source, |
| 2029 | | − /\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/.source, |
| 2133 | + /([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, |
| 2134 | + /\((?:[^()\\]|\\[\s\S])*\)/.source, |
| 2030 | 2135 | // Here we need to specifically allow interpolation |
| 2031 | | − /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/.source, |
| 2032 | | − /\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/.source, |
| 2033 | | − /<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/.source |
| 2034 | | − ].join('|') + ')'), |
| 2136 | + /\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/.source, |
| 2137 | + /\[(?:[^\[\]\\]|\\[\s\S])*\]/.source, |
| 2138 | + /<(?:[^<>\\]|\\[\s\S])*>/.source |
| 2139 | + ].join('|') + ')' + /[egimnosux]{0,6}/.source), |
| 2035 | 2140 | greedy: true, |
| 2036 | 2141 | inside: { |
| 2037 | 2142 | '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 | 2147 | lookbehind: true, |
| 2043 | | − greedy: true |
| 2148 | + greedy: true, |
| 2149 | + inside: { |
| 2150 | + 'interpolation': interpolation |
| 2151 | + } |
| 2044 | 2152 | } |
| 2045 | 2153 | ], |
| 2046 | 2154 | 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, |
| @@ -2084,13 +2192,42 @@ Prism.languages.coffee = Prism.languages.coffeescript; · 37 unmodified lines |
| 2084 | 2192 | inside: { |
| 2085 | 2193 | '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 | 2227 | Prism.languages.rb = Prism.languages.ruby; |
| 2091 | 2228 | }(Prism)); |
| 2092 | 2229 | |
| 2093 | | −(function(Prism) { |
| 2230 | +(function (Prism) { |
| 2094 | 2231 | Prism.languages.crystal = Prism.languages.extend('ruby', { |
| 2095 | 2232 | keyword: [ |
| 2096 | 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 | 2256 | expansion: [ |
| 2120 | | − { |
| 2121 | | − pattern: /\{\{.+?\}\}/, |
| 2122 | | − inside: { |
| 2123 | | − delimiter: { |
| 2124 | | − pattern: /^\{\{|\}\}$/, |
| 2125 | | − alias: 'tag' |
| 2126 | | − }, |
| 2127 | | − rest: Prism.languages.crystal |
| 2128 | | − } |
| 2129 | | − }, |
| 2130 | | − { |
| 2131 | | − pattern: /\{%.+?%\}/, |
| 2132 | | − inside: { |
| 2133 | | − delimiter: { |
| 2134 | | − pattern: /^\{%|%\}$/, |
| 2135 | | − alias: 'tag' |
| 2136 | | − }, |
| 2137 | | − rest: Prism.languages.crystal |
| 2257 | + { |
| 2258 | + pattern: /\{\{.+?\}\}/, |
| 2259 | + inside: { |
| 2260 | + delimiter: { |
| 2261 | + pattern: /^\{\{|\}\}$/, |
| 2262 | + alias: 'tag' |
| 2263 | + }, |
| 2264 | + rest: Prism.languages.crystal |
| 2265 | + } |
| 2266 | + }, |
| 2267 | + { |
| 2268 | + pattern: /\{%.+?%\}/, |
| 2269 | + inside: { |
| 2270 | + delimiter: { |
| 2271 | + pattern: /^\{%|%\}$/, |
| 2272 | + alias: 'tag' |
| 2273 | + }, |
| 2274 | + rest: Prism.languages.crystal |
| 2275 | + } |
| 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 | |
| 2226 | | −Prism.languages.dart = Prism.languages.extend('clike', { |
| 2227 | | − 'string': [ |
| 2228 | | − { |
| 2229 | | − pattern: /r?("""|''')[\s\S]*?\1/, |
| 2230 | | − greedy: true |
| 2231 | | − }, |
| 2232 | | − { |
| 2233 | | − pattern: /r?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/, |
| 2234 | | − greedy: true |
| 2235 | | − } |
| 2236 | | − ], |
| 2237 | | − 'keyword': [ |
| 2363 | +(function (Prism) { |
| 2364 | + var keywords = [ |
| 2238 | 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/ |
| 2240 | | − ], |
| 2241 | | − 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/ |
| 2242 | | −}); |
| 2366 | + /\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|covariant|default|deferred|do|dynamic|else|enum|export|extension|external|extends|factory|final|finally|for|get|hide|if|implements|interface|import|in|library|mixin|new|null|on|operator|part|rethrow|return|set|show|static|super|switch|sync|this|throw|try|typedef|var|void|while|with|yield)\b/ |
| 2367 | + ]; |
| 2243 | 2368 | |
| 2244 | | −Prism.languages.insertBefore('dart','function',{ |
| 2245 | | − 'metadata': { |
| 2246 | | − pattern: /@\w+/, |
| 2247 | | − alias: 'symbol' |
| 2248 | | − } |
| 2249 | | −}); |
| 2369 | + // Handles named imports, such as http.Client |
| 2370 | + var packagePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source; |
| 2371 | + |
| 2372 | + // based on the dart naming conventions |
| 2373 | + var className = { |
| 2374 | + pattern: RegExp(packagePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source), |
| 2375 | + lookbehind: true, |
| 2376 | + inside: { |
| 2377 | + 'namespace': { |
| 2378 | + pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/, |
| 2379 | + inside: { |
| 2380 | + 'punctuation': /\./ |
| 2381 | + } |
| 2382 | + }, |
| 2383 | + } |
| 2384 | + }; |
| 2385 | + |
| 2386 | + Prism.languages.dart = Prism.languages.extend('clike', { |
| 2387 | + 'string': [ |
| 2388 | + { |
| 2389 | + pattern: /r?("""|''')[\s\S]*?\1/, |
| 2390 | + greedy: true |
| 2391 | + }, |
| 2392 | + { |
| 2393 | + pattern: /r?(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/, |
| 2394 | + greedy: true |
| 2395 | + } |
| 2396 | + ], |
| 2397 | + 'class-name': [ |
| 2398 | + className, |
| 2399 | + { |
| 2400 | + // variables and parameters |
| 2401 | + // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) |
| 2402 | + pattern: RegExp(packagePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()])/.source), |
| 2403 | + lookbehind: true, |
| 2404 | + inside: className.inside |
| 2405 | + } |
| 2406 | + ], |
| 2407 | + 'keyword': keywords, |
| 2408 | + 'operator': /\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/ |
| 2409 | + }); |
| 2410 | + |
| 2411 | + Prism.languages.insertBefore('dart', 'function', { |
| 2412 | + 'metadata': { |
| 2413 | + pattern: /@\w+/, |
| 2414 | + alias: 'symbol' |
| 2415 | + } |
| 2416 | + }); |
| 2417 | + |
| 2418 | + Prism.languages.insertBefore('dart', 'class-name', { |
| 2419 | + 'generics': { |
| 2420 | + pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/, |
| 2421 | + inside: { |
| 2422 | + 'class-name': className, |
| 2423 | + 'keyword': keywords, |
| 2424 | + 'punctuation': /[<>(),.:]/, |
| 2425 | + 'operator': /[?&|]/ |
| 2426 | + } |
| 2427 | + }, |
| 2428 | + }); |
| 2429 | +}(Prism)); |
| 2250 | 2430 | |
| 2251 | 2431 | (function (Prism) { |
| 2252 | 2432 | |
| @@ -2285,8 +2465,8 @@ Prism.languages.insertBefore('dart','function',{ · 32 unmodified lines |
| 2285 | 2465 | if (!/^\w+$/.test(name)) { // "deleted-sign" -> "deleted" |
| 2286 | 2466 | alias.push(/\w+/.exec(name)[0]); |
| 2287 | 2467 | } |
| 2288 | | − if (name === "diff") { |
| 2289 | | − alias.push("bold"); |
| 2468 | + if (name === 'diff') { |
| 2469 | + alias.push('bold'); |
| 2290 | 2470 | } |
| 2291 | 2471 | |
| 2292 | 2472 | Prism.languages.diff[name] = { |
| @@ -2354,8 +2534,9 @@ Prism.languages.insertBefore('dart','function',{ · 61 unmodified lines |
| 2354 | 2534 | var placeholder; |
| 2355 | 2535 | |
| 2356 | 2536 | // 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 | 2538 | ++i; |
| 2539 | + } |
| 2359 | 2540 | |
| 2360 | 2541 | // Create a sparse array |
| 2361 | 2542 | tokenStack[i] = match; |
| @@ -2496,10 +2677,20 @@ Prism.languages.insertBefore('dart','function',{ · 134 unmodified lines |
| 2496 | 2677 | markupTemplating.tokenizePlaceholders(env, 'jinja2'); |
| 2497 | 2678 | }); |
| 2498 | 2679 | |
| 2499 | | −})(Prism); |
| 2680 | +}(Prism)); |
| 2500 | 2681 | |
| 2501 | 2682 | Prism.languages.elixir = { |
| 2502 | | − 'comment': /#.*/m, |
| 2683 | + 'doc': { |
| 2684 | + pattern: /@(?:doc|moduledoc)\s+(?:("""|''')[\s\S]*?\1|("|')(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2)/, |
| 2685 | + inside: { |
| 2686 | + 'attribute': /^@\w+/, |
| 2687 | + 'string': /['"][\s\S]+/ |
| 2688 | + } |
| 2689 | + }, |
| 2690 | + 'comment': { |
| 2691 | + pattern: /#.*/m, |
| 2692 | + greedy: true |
| 2693 | + }, |
| 2503 | 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 | 2695 | 'regex': { |
| 2505 | 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 | 2727 | lookbehind: true, |
| 2537 | 2728 | alias: 'symbol' |
| 2538 | 2729 | }, |
| 2730 | + 'module': { |
| 2731 | + pattern: /\b[A-Z]\w*\b/, |
| 2732 | + alias: 'class-name' |
| 2733 | + }, |
| 2539 | 2734 | // Look-ahead prevents bad highlighting of the :: operator |
| 2540 | 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 | 2736 | 'argument': { |
| 2548 | 2737 | // Look-behind prevents bad highlighting of the && operator |
| 2549 | 2738 | pattern: /(^|[^&])&\d+/, |
| @@ -2554,8 +2743,9 @@ Prism.languages.elixir = { · 4 unmodified lines |
| 2554 | 2743 | pattern: /@\w+/, |
| 2555 | 2744 | alias: 'variable' |
| 2556 | 2745 | }, |
| 2746 | + 'function': /\b[_a-zA-Z]\w*[?!]?(?:(?=\s*(?:\.\s*)?\()|(?=\/\d+))/, |
| 2557 | 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 | 2749 | 'boolean': /\b(?:true|false|nil)\b/, |
| 2560 | 2750 | 'operator': [ |
| 2561 | 2751 | /\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/, |
| @@ -2573,19 +2763,7 @@ Prism.languages.elixir = { · 11 unmodified lines |
| 2573 | 2763 | 'punctuation': /<<|>>|[.,%\[\]{}()]/ |
| 2574 | 2764 | }; |
| 2575 | 2765 | |
| 2576 | | −Prism.languages.insertBefore('elixir', 'keyword', { |
| 2577 | | − 'module': { |
| 2578 | | − pattern: /\b(defmodule\s)[A-Z][\w.\\]+/, |
| 2579 | | − lookbehind: true, |
| 2580 | | − alias: 'class-name' |
| 2581 | | − }, |
| 2582 | | − 'function': { |
| 2583 | | − pattern: /\b(defp?\s)[\w.\\]+/, |
| 2584 | | − lookbehind: true |
| 2585 | | − } |
| 2586 | | −}); |
| 2587 | | − |
| 2588 | | −Prism.languages.elixir.string.forEach(function(o) { |
| 2766 | +Prism.languages.elixir.string.forEach(function (o) { |
| 2589 | 2767 | o.inside = { |
| 2590 | 2768 | 'interpolation': { |
| 2591 | 2769 | pattern: /#\{[^}]+\}/, |
| @@ -2701,7 +2879,7 @@ Prism.languages.insertBefore('groovy', 'function', { · 109 unmodified lines |
| 2701 | 2879 | }); |
| 2702 | 2880 | |
| 2703 | 2881 | // Handle string interpolation |
| 2704 | | −Prism.hooks.add('wrap', function(env) { |
| 2882 | +Prism.hooks.add('wrap', function (env) { |
| 2705 | 2883 | if (env.language === 'groovy' && env.type === 'string') { |
| 2706 | 2884 | var delimiter = env.content[0]; |
| 2707 | 2885 | |
| @@ -2791,7 +2969,7 @@ Prism.hooks.add('wrap', function(env) { · 83 unmodified lines |
| 2791 | 2969 | alias: 'punctuation' |
| 2792 | 2970 | }, |
| 2793 | 2971 | 'generics': { |
| 2794 | | − pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/, |
| 2972 | + pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/, |
| 2795 | 2973 | inside: { |
| 2796 | 2974 | 'class-name': className, |
| 2797 | 2975 | 'keyword': keywords, |
| @@ -2893,7 +3071,7 @@ Prism.languages.julia = { · 95 unmodified lines |
| 2893 | 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 | 3076 | Prism.languages.insertBefore('kotlin', 'string', { |
| 2899 | 3077 | 'raw-string': { |
| @@ -2940,6 +3118,71 @@ Prism.languages.julia = { · 40 unmodified lines |
| 2940 | 3118 | Prism.languages.kts = Prism.languages.kotlin; |
| 2941 | 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 | + |
| 2943 | 3186 | Prism.languages.lua = { |
| 2944 | 3187 | 'comment': /^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m, |
| 2945 | 3188 | // \z may be used to skip the following space |
| @@ -2978,17 +3221,58 @@ Prism.languages.matlab = { · 32 unmodified lines |
| 2978 | 3221 | 'punctuation': /\.{3}|[.,;\[\](){}!]/ |
| 2979 | 3222 | }; |
| 2980 | 3223 | |
| 2981 | | −Prism.languages.nginx = Prism.languages.extend('clike', { |
| 2982 | | − 'comment': { |
| 2983 | | − pattern: /(^|[^"{\\])#.*/, |
| 2984 | | − lookbehind: true |
| 2985 | | − }, |
| 2986 | | − 'keyword': /\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|events|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stub_status|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timeout|timer_resolution|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|use|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_rlimit_sigpending|working_directory|xclient|xml_entities|xslt_entities|xslt_stylesheet|xslt_types|ssl_session_tickets|ssl_stapling|ssl_stapling_verify|ssl_ecdh_curve|ssl_trusted_certificate|more_set_headers|ssl_early_data)\b/i |
| 2987 | | −}); |
| 3224 | +(function (Prism) { |
| 2988 | 3225 | |
| 2989 | | −Prism.languages.insertBefore('nginx', 'keyword', { |
| 2990 | | − 'variable': /\$[a-z_]+/i |
| 2991 | | −}); |
| 3226 | + var variable = /\$(?:\w[a-z\d]*(?:_[^\x00-\x1F\s"'\\()$]*)?|\{[^}\s"'\\]+\})/i; |
| 3227 | + |
| 3228 | + Prism.languages.nginx = { |
| 3229 | + 'comment': { |
| 3230 | + pattern: /(^|[\s{};])#.*/, |
| 3231 | + lookbehind: true |
| 3232 | + }, |
| 3233 | + 'directive': { |
| 3234 | + pattern: /(^|\s)\w(?:[^;{}"'\\\s]|\\.|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\s+(?:#.*(?!.)|(?![#\s])))*?(?=\s*[;{])/, |
| 3235 | + lookbehind: true, |
| 3236 | + greedy: true, |
| 3237 | + inside: { |
| 3238 | + 'string': { |
| 3239 | + pattern: /((?:^|[^\\])(?:\\\\)*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/, |
| 3240 | + lookbehind: true, |
| 3241 | + inside: { |
| 3242 | + 'escape': { |
| 3243 | + pattern: /\\["'\\nrt]/, |
| 3244 | + alias: 'entity' |
| 3245 | + }, |
| 3246 | + 'variable': variable |
| 3247 | + } |
| 3248 | + }, |
| 3249 | + 'comment': { |
| 3250 | + pattern: /(\s)#.*/, |
| 3251 | + lookbehind: true, |
| 3252 | + greedy: true |
| 3253 | + }, |
| 3254 | + 'keyword': { |
| 3255 | + pattern: /^\S+/, |
| 3256 | + greedy: true |
| 3257 | + }, |
| 3258 | + |
| 3259 | + // other patterns |
| 3260 | + |
| 3261 | + 'boolean': { |
| 3262 | + pattern: /(\s)(?:off|on)(?!\S)/, |
| 3263 | + lookbehind: true |
| 3264 | + }, |
| 3265 | + 'number': { |
| 3266 | + pattern: /(\s)\d+[a-z]*(?!\S)/i, |
| 3267 | + lookbehind: true |
| 3268 | + }, |
| 3269 | + 'variable': variable |
| 3270 | + } |
| 3271 | + }, |
| 3272 | + 'punctuation': /[{};]/ |
| 3273 | + }; |
| 3274 | + |
| 3275 | +}(Prism)); |
| 2992 | 3276 | |
| 2993 | 3277 | Prism.languages.nim = { |
| 2994 | 3278 | 'comment': /#.*/, |
| @@ -3023,6 +3307,7 @@ Prism.languages.nim = { · 28 unmodified lines |
| 3023 | 3307 | }, |
| 3024 | 3308 | 'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/ |
| 3025 | 3309 | }; |
| 3310 | + |
| 3026 | 3311 | Prism.languages.ocaml = { |
| 3027 | 3312 | 'comment': /\(\*[\s\S]*?\*\)/, |
| 3028 | 3313 | 'string': [ |
| @@ -3228,7 +3513,7 @@ Prism.languages.perl = { · 199 unmodified lines |
| 3228 | 3513 | // ${...} |
| 3229 | 3514 | /[&*$@%]#?(?=\{)/, |
| 3230 | 3515 | // $foo |
| 3231 | | − /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i, |
| 3516 | + /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+(?![\w$]))+(?:::)*/i, |
| 3232 | 3517 | // $1 |
| 3233 | 3518 | /[&*$@%]\d+/, |
| 3234 | 3519 | // $_, @_, %! |
| @@ -3271,8 +3556,18 @@ Prism.languages.perl = { · 36 unmodified lines |
| 3271 | 3556 | pattern: /\b(?:false|true)\b/i, |
| 3272 | 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 | 3569 | /\b(?:null)\b/i, |
| 3570 | + /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/, |
| 3276 | 3571 | ]; |
| 3277 | 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 | 3573 | var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/; |
| @@ -3297,6 +3592,11 @@ Prism.languages.perl = { · 18 unmodified lines |
| 3297 | 3592 | lookbehind: true, |
| 3298 | 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 | 3600 | 'keyword': [ |
| 3301 | 3601 | { |
| 3302 | 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 | 3644 | alias: 'static-context', |
| 3345 | 3645 | 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/i |
| 3647 | + { |
| 3648 | + // yield from |
| 3649 | + pattern: /(\byield\s+)from\b/i, |
| 3650 | + lookbehind: true |
| 3651 | + }, |
| 3652 | + // `class` is always a keyword unlike other keywords |
| 3653 | + /\bclass\b/i, |
| 3654 | + { |
| 3655 | + // https://www.php.net/manual/en/reserved.keywords.php |
| 3656 | + // |
| 3657 | + // keywords cannot be preceded by "->" |
| 3658 | + // the complex lookbehind means `(?<!(?:->|::)\s*)` |
| 3659 | + pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i, |
| 3660 | + lookbehind: true |
| 3661 | + } |
| 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 | 3667 | 'class-name': [ |
| 3351 | 3668 | { |
| 3352 | 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 | 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 | 3773 | 'property': { |
| 3451 | | − pattern: /(->)[\w]+/, |
| 3774 | + pattern: /(->\s*)\w+/, |
| 3452 | 3775 | lookbehind: true |
| 3453 | 3776 | }, |
| 3454 | 3777 | 'number': number, |
| @@ -3457,7 +3780,7 @@ Prism.languages.perl = { · 2 unmodified lines |
| 3457 | 3780 | }; |
| 3458 | 3781 | |
| 3459 | 3782 | var string_interpolation = { |
| 3460 | | − pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)*)/, |
| 3783 | + pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/, |
| 3461 | 3784 | lookbehind: true, |
| 3462 | 3785 | inside: Prism.languages.php |
| 3463 | 3786 | }; |
| @@ -3489,7 +3812,7 @@ Prism.languages.perl = { · 25 unmodified lines |
| 3489 | 3812 | 'punctuation': /^<<<"?|[";]$/ |
| 3490 | 3813 | } |
| 3491 | 3814 | }, |
| 3492 | | − 'interpolation': string_interpolation // See below |
| 3815 | + 'interpolation': string_interpolation |
| 3493 | 3816 | } |
| 3494 | 3817 | }, |
| 3495 | 3818 | { |
| @@ -3507,16 +3830,13 @@ Prism.languages.perl = { · 11 unmodified lines |
| 3507 | 3830 | alias: 'double-quoted-string', |
| 3508 | 3831 | greedy: true, |
| 3509 | 3832 | inside: { |
| 3510 | | − 'interpolation': string_interpolation // See below |
| 3833 | + 'interpolation': string_interpolation |
| 3511 | 3834 | } |
| 3512 | 3835 | } |
| 3513 | 3836 | ]; |
| 3514 | 3837 | |
| 3515 | 3838 | Prism.languages.insertBefore('php', 'variable', { |
| 3516 | 3839 | 'string': string, |
| 3517 | | − }); |
| 3518 | | − |
| 3519 | | − Prism.languages.insertBefore('php', 'variable', { |
| 3520 | 3840 | 'attribute': { |
| 3521 | 3841 | pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/mi, |
| 3522 | 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 | 3886 | if (!/<\?/.test(env.code)) { |
| 3567 | 3887 | return; |
| 3568 | 3888 | } |
| @@ -3571,7 +3891,7 @@ Prism.languages.perl = { · 2 unmodified lines |
| 3571 | 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 | 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 | |
| 3643 | 3963 | Prism.languages.py = Prism.languages.python; |
| 3644 | 3964 | |
| 3645 | | −(function(Prism) { |
| 3965 | +(function (Prism) { |
| 3646 | 3966 | |
| 3647 | | −var javascript = Prism.util.clone(Prism.languages.javascript); |
| 3967 | + var javascript = Prism.util.clone(Prism.languages.javascript); |
| 3648 | 3968 | |
| 3649 | | −var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source; |
| 3650 | | −var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source; |
| 3651 | | −var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source; |
| 3969 | + var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source; |
| 3970 | + var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source; |
| 3971 | + var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source; |
| 3652 | 3972 | |
| 3653 | | −/** |
| 3654 | | − * @param {string} source |
| 3655 | | − * @param {string} [flags] |
| 3656 | | − */ |
| 3657 | | −function re(source, flags) { |
| 3658 | | − source = source |
| 3659 | | − .replace(/<S>/g, function () { return space; }) |
| 3660 | | − .replace(/<BRACES>/g, function () { return braces; }) |
| 3661 | | − .replace(/<SPREAD>/g, function () { return spread; }); |
| 3662 | | − return RegExp(source, flags); |
| 3663 | | −} |
| 3973 | + /** |
| 3974 | + * @param {string} source |
| 3975 | + * @param {string} [flags] |
| 3976 | + */ |
| 3977 | + function re(source, flags) { |
| 3978 | + source = source |
| 3979 | + .replace(/<S>/g, function () { return space; }) |
| 3980 | + .replace(/<BRACES>/g, function () { return braces; }) |
| 3981 | + .replace(/<SPREAD>/g, function () { return spread; }); |
| 3982 | + return RegExp(source, flags); |
| 3983 | + } |
| 3664 | 3984 | |
| 3665 | | −spread = re(spread).source; |
| 3985 | + spread = re(spread).source; |
| 3666 | 3986 | |
| 3667 | 3987 | |
| 3668 | | −Prism.languages.jsx = Prism.languages.extend('markup', javascript); |
| 3669 | | −Prism.languages.jsx.tag.pattern = re( |
| 3670 | | − /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source |
| 3671 | | −); |
| 3988 | + Prism.languages.jsx = Prism.languages.extend('markup', javascript); |
| 3989 | + Prism.languages.jsx.tag.pattern = re( |
| 3990 | + /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source |
| 3991 | + ); |
| 3672 | 3992 | |
| 3673 | | −Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i; |
| 3674 | | −Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i; |
| 3675 | | −Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/; |
| 3676 | | −Prism.languages.jsx.tag.inside['comment'] = javascript['comment']; |
| 3993 | + Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i; |
| 3994 | + Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i; |
| 3995 | + Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/; |
| 3996 | + Prism.languages.jsx.tag.inside['comment'] = javascript['comment']; |
| 3677 | 3997 | |
| 3678 | | −Prism.languages.insertBefore('inside', 'attr-name', { |
| 3679 | | − 'spread': { |
| 3680 | | − pattern: re(/<SPREAD>/.source), |
| 3681 | | − inside: Prism.languages.jsx |
| 3682 | | − } |
| 3683 | | −}, Prism.languages.jsx.tag); |
| 3998 | + Prism.languages.insertBefore('inside', 'attr-name', { |
| 3999 | + 'spread': { |
| 4000 | + pattern: re(/<SPREAD>/.source), |
| 4001 | + inside: Prism.languages.jsx |
| 4002 | + } |
| 4003 | + }, Prism.languages.jsx.tag); |
| 3684 | 4004 | |
| 3685 | | −Prism.languages.insertBefore('inside', 'attr-value',{ |
| 3686 | | − 'script': { |
| 3687 | | − // Allow for two levels of nesting |
| 3688 | | − pattern: re(/=<BRACES>/.source), |
| 3689 | | − inside: { |
| 3690 | | − 'script-punctuation': { |
| 3691 | | − pattern: /^=(?={)/, |
| 3692 | | − alias: 'punctuation' |
| 4005 | + Prism.languages.insertBefore('inside', 'special-attr', { |
| 4006 | + 'script': { |
| 4007 | + // Allow for two levels of nesting |
| 4008 | + pattern: re(/=<BRACES>/.source), |
| 4009 | + inside: { |
| 4010 | + 'script-punctuation': { |
| 4011 | + pattern: /^=(?={)/, |
| 4012 | + alias: 'punctuation' |
| 4013 | + }, |
| 4014 | + rest: Prism.languages.jsx |
| 3693 | 4015 | }, |
| 3694 | | − rest: Prism.languages.jsx |
| 3695 | | − }, |
| 3696 | | − 'alias': 'language-javascript' |
| 3697 | | − } |
| 3698 | | −}, Prism.languages.jsx.tag); |
| 4016 | + 'alias': 'language-javascript' |
| 4017 | + } |
| 4018 | + }, Prism.languages.jsx.tag); |
| 3699 | 4019 | |
| 3700 | | −// The following will handle plain text inside tags |
| 3701 | | −var stringifyToken = function (token) { |
| 3702 | | − if (!token) { |
| 3703 | | − return ''; |
| 3704 | | − } |
| 3705 | | − if (typeof token === 'string') { |
| 3706 | | − return token; |
| 3707 | | − } |
| 3708 | | − if (typeof token.content === 'string') { |
| 3709 | | − return token.content; |
| 3710 | | − } |
| 3711 | | − return token.content.map(stringifyToken).join(''); |
| 3712 | | −}; |
| 4020 | + // The following will handle plain text inside tags |
| 4021 | + var stringifyToken = function (token) { |
| 4022 | + if (!token) { |
| 4023 | + return ''; |
| 4024 | + } |
| 4025 | + if (typeof token === 'string') { |
| 4026 | + return token; |
| 4027 | + } |
| 4028 | + if (typeof token.content === 'string') { |
| 4029 | + return token.content; |
| 4030 | + } |
| 4031 | + return token.content.map(stringifyToken).join(''); |
| 4032 | + }; |
| 3713 | 4033 | |
| 3714 | | −var walkTokens = function (tokens) { |
| 3715 | | − var openedTags = []; |
| 3716 | | − for (var i = 0; i < tokens.length; i++) { |
| 3717 | | − var token = tokens[i]; |
| 3718 | | − var notTagNorBrace = false; |
| 3719 | | − |
| 3720 | | − if (typeof token !== 'string') { |
| 3721 | | − if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') { |
| 3722 | | − // We found a tag, now find its kind |
| 3723 | | − |
| 3724 | | − if (token.content[0].content[0].content === '</') { |
| 3725 | | − // Closing tag |
| 3726 | | − if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) { |
| 3727 | | − // Pop matching opening tag |
| 3728 | | − openedTags.pop(); |
| 3729 | | − } |
| 3730 | | − } else { |
| 3731 | | − if (token.content[token.content.length - 1].content === '/>') { |
| 3732 | | − // Autoclosed tag, ignore |
| 4034 | + var walkTokens = function (tokens) { |
| 4035 | + var openedTags = []; |
| 4036 | + for (var i = 0; i < tokens.length; i++) { |
| 4037 | + var token = tokens[i]; |
| 4038 | + var notTagNorBrace = false; |
| 4039 | + |
| 4040 | + if (typeof token !== 'string') { |
| 4041 | + if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') { |
| 4042 | + // We found a tag, now find its kind |
| 4043 | + |
| 4044 | + if (token.content[0].content[0].content === '</') { |
| 4045 | + // Closing tag |
| 4046 | + if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) { |
| 4047 | + // Pop matching opening tag |
| 4048 | + openedTags.pop(); |
| 4049 | + } |
| 3733 | 4050 | } else { |
| 3734 | | − // Opening tag |
| 3735 | | − openedTags.push({ |
| 3736 | | − tagName: stringifyToken(token.content[0].content[1]), |
| 3737 | | − openedBraces: 0 |
| 3738 | | − }); |
| 4051 | + if (token.content[token.content.length - 1].content === '/>') { |
| 4052 | + // Autoclosed tag, ignore |
| 4053 | + } else { |
| 4054 | + // Opening tag |
| 4055 | + openedTags.push({ |
| 4056 | + tagName: stringifyToken(token.content[0].content[1]), |
| 4057 | + openedBraces: 0 |
| 4058 | + }); |
| 4059 | + } |
| 3739 | 4060 | } |
| 3740 | | − } |
| 3741 | | − } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') { |
| 4061 | + } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') { |
| 3742 | 4062 | |
| 3743 | | − // Here we might have entered a JSX context inside a tag |
| 3744 | | − openedTags[openedTags.length - 1].openedBraces++; |
| 4063 | + // Here we might have entered a JSX context inside a tag |
| 4064 | + openedTags[openedTags.length - 1].openedBraces++; |
| 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 tag |
| 3749 | | − openedTags[openedTags.length - 1].openedBraces--; |
| 4068 | + // Here we might have left a JSX context inside a tag |
| 4069 | + openedTags[openedTags.length - 1].openedBraces--; |
| 3750 | 4070 | |
| 3751 | | − } else { |
| 3752 | | − notTagNorBrace = true |
| 3753 | | − } |
| 3754 | | − } |
| 3755 | | − if (notTagNorBrace || typeof token === 'string') { |
| 3756 | | − if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) { |
| 3757 | | − // Here we are inside a tag, and not inside a JSX context. |
| 3758 | | − // That's plain text: drop any tokens matched. |
| 3759 | | − var plainText = stringifyToken(token); |
| 3760 | | − |
| 3761 | | − // And merge text with adjacent text |
| 3762 | | − if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) { |
| 3763 | | − plainText += stringifyToken(tokens[i + 1]); |
| 3764 | | − tokens.splice(i + 1, 1); |
| 4071 | + } else { |
| 4072 | + notTagNorBrace = true; |
| 3765 | 4073 | } |
| 3766 | | − if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) { |
| 3767 | | − plainText = stringifyToken(tokens[i - 1]) + plainText; |
| 3768 | | − tokens.splice(i - 1, 1); |
| 3769 | | − i--; |
| 4074 | + } |
| 4075 | + if (notTagNorBrace || typeof token === 'string') { |
| 4076 | + if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) { |
| 4077 | + // Here we are inside a tag, and not inside a JSX context. |
| 4078 | + // That's plain text: drop any tokens matched. |
| 4079 | + var plainText = stringifyToken(token); |
| 4080 | + |
| 4081 | + // And merge text with adjacent text |
| 4082 | + if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) { |
| 4083 | + plainText += stringifyToken(tokens[i + 1]); |
| 4084 | + tokens.splice(i + 1, 1); |
| 4085 | + } |
| 4086 | + if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) { |
| 4087 | + plainText = stringifyToken(tokens[i - 1]) + plainText; |
| 4088 | + tokens.splice(i - 1, 1); |
| 4089 | + i--; |
| 4090 | + } |
| 4091 | + |
| 4092 | + tokens[i] = new Prism.Token('plain-text', plainText, null, plainText); |
| 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') { |
| 3777 | | − walkTokens(token.content); |
| 4102 | + Prism.hooks.add('after-tokenize', function (env) { |
| 4103 | + if (env.language !== 'jsx' && env.language !== 'tsx') { |
| 4104 | + return; |
| 3778 | 4105 | } |
| 3779 | | − } |
| 3780 | | −}; |
| 3781 | | − |
| 3782 | | −Prism.hooks.add('after-tokenize', function (env) { |
| 3783 | | − if (env.language !== 'jsx' && env.language !== 'tsx') { |
| 3784 | | − return; |
| 3785 | | − } |
| 3786 | | − walkTokens(env.tokens); |
| 3787 | | −}); |
| 4106 | + walkTokens(env.tokens); |
| 4107 | + }); |
| 3788 | 4108 | |
| 3789 | 4109 | }(Prism)); |
| 3790 | 4110 | |
| @@ -4007,17 +4327,26 @@ Prism.languages.scss['atrule'].inside.rest = Prism.languages.scss; · 216 unmodified lines |
| 4007 | 4327 | |
| 4008 | 4328 | var strings = [ |
| 4009 | 4329 | // normal string |
| 4010 | | − // 1 capturing group |
| 4011 | | − /(["'])(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|(?!\1)[^\\`$])*\1/.source, |
| 4330 | + /"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/.source, |
| 4331 | + /'[^']*'/.source, |
| 4332 | + /\$'(?:[^'\\]|\\[\s\S])*'/.source, |
| 4012 | 4333 | |
| 4013 | 4334 | // here doc |
| 4014 | 4335 | // 2 capturing groups |
| 4015 | | − /<<-?\s*(["']?)(\w+)\2\s[\s\S]*?[\r\n]\3/.source |
| 4336 | + /<<-?\s*(["']?)(\w+)\1\s[\s\S]*?[\r\n]\2/.source |
| 4016 | 4337 | ].join('|'); |
| 4017 | 4338 | |
| 4018 | 4339 | Prism.languages['shell-session'] = { |
| 4019 | 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 | 4350 | greedy: true, |
| 4022 | 4351 | inside: { |
| 4023 | 4352 | 'info': { |
| @@ -4085,11 +4414,16 @@ Prism.languages.sql = { · 61 unmodified lines |
| 4085 | 4414 | greedy: true, |
| 4086 | 4415 | 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 | 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 | 4427 | // doesn't work with TS because TS is too complex |
| 4094 | 4428 | delete Prism.languages.typescript['parameter']; |
| 4095 | 4429 | |
| @@ -4100,6 +4434,16 @@ Prism.languages.sql = { · 4 unmodified lines |
| 4100 | 4434 | Prism.languages.typescript['class-name'].inside = typeInside; |
| 4101 | 4435 | |
| 4102 | 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 | 4447 | 'generic-function': { |
| 4104 | 4448 | // e.g. foo<T extends "bar" | "baz">( ... |
| 4105 | 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 | 4490 | flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag |
| 4147 | 4491 | var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|]|}|(?:[\r\n]\s*)?#))/.source |
| 4148 | 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 | 4496 | Prism.languages.yaml = { |
| @@ -4202,4 +4546,3 @@ Prism.languages.sql = { · 49 unmodified lines |
| 4202 | 4546 | Prism.languages.yml = Prism.languages.yaml; |
| 4203 | 4547 | |
| 4204 | 4548 | }(Prism)); |
| 4205 | | − |