prism.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+c+cpp+coffeescript+php+python+ruby+rust */
  2. self = (typeof window !== 'undefined')
  3. ? window // if in browser
  4. : (
  5. (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
  6. ? self // if in worker
  7. : {} // if in node js
  8. );
  9. /**
  10. * Prism: Lightweight, robust, elegant syntax highlighting
  11. * MIT license http://www.opensource.org/licenses/mit-license.php/
  12. * @author Lea Verou http://lea.verou.me
  13. */
  14. var Prism = (function(){
  15. // Private helper vars
  16. var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
  17. var _ = self.Prism = {
  18. util: {
  19. encode: function (tokens) {
  20. if (tokens instanceof Token) {
  21. return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
  22. } else if (_.util.type(tokens) === 'Array') {
  23. return tokens.map(_.util.encode);
  24. } else {
  25. return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
  26. }
  27. },
  28. type: function (o) {
  29. return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
  30. },
  31. // Deep clone a language definition (e.g. to extend it)
  32. clone: function (o) {
  33. var type = _.util.type(o);
  34. switch (type) {
  35. case 'Object':
  36. var clone = {};
  37. for (var key in o) {
  38. if (o.hasOwnProperty(key)) {
  39. clone[key] = _.util.clone(o[key]);
  40. }
  41. }
  42. return clone;
  43. case 'Array':
  44. return o.map(function(v) { return _.util.clone(v); });
  45. }
  46. return o;
  47. }
  48. },
  49. languages: {
  50. extend: function (id, redef) {
  51. var lang = _.util.clone(_.languages[id]);
  52. for (var key in redef) {
  53. lang[key] = redef[key];
  54. }
  55. return lang;
  56. },
  57. /**
  58. * Insert a token before another token in a language literal
  59. * As this needs to recreate the object (we cannot actually insert before keys in object literals),
  60. * we cannot just provide an object, we need anobject and a key.
  61. * @param inside The key (or language id) of the parent
  62. * @param before The key to insert before. If not provided, the function appends instead.
  63. * @param insert Object with the key/value pairs to insert
  64. * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted.
  65. */
  66. insertBefore: function (inside, before, insert, root) {
  67. root = root || _.languages;
  68. var grammar = root[inside];
  69. if (arguments.length == 2) {
  70. insert = arguments[1];
  71. for (var newToken in insert) {
  72. if (insert.hasOwnProperty(newToken)) {
  73. grammar[newToken] = insert[newToken];
  74. }
  75. }
  76. return grammar;
  77. }
  78. var ret = {};
  79. for (var token in grammar) {
  80. if (grammar.hasOwnProperty(token)) {
  81. if (token == before) {
  82. for (var newToken in insert) {
  83. if (insert.hasOwnProperty(newToken)) {
  84. ret[newToken] = insert[newToken];
  85. }
  86. }
  87. }
  88. ret[token] = grammar[token];
  89. }
  90. }
  91. // Update references in other language definitions
  92. _.languages.DFS(_.languages, function(key, value) {
  93. if (value === root[inside] && key != inside) {
  94. this[key] = ret;
  95. }
  96. });
  97. return root[inside] = ret;
  98. },
  99. // Traverse a language definition with Depth First Search
  100. DFS: function(o, callback, type) {
  101. for (var i in o) {
  102. if (o.hasOwnProperty(i)) {
  103. callback.call(o, i, o[i], type || i);
  104. if (_.util.type(o[i]) === 'Object') {
  105. _.languages.DFS(o[i], callback);
  106. }
  107. else if (_.util.type(o[i]) === 'Array') {
  108. _.languages.DFS(o[i], callback, i);
  109. }
  110. }
  111. }
  112. }
  113. },
  114. highlightAll: function(async, callback) {
  115. var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');
  116. for (var i=0, element; element = elements[i++];) {
  117. _.highlightElement(element, async === true, callback);
  118. }
  119. },
  120. highlightElement: function(element, async, callback) {
  121. // Find language
  122. var language, grammar, parent = element;
  123. while (parent && !lang.test(parent.className)) {
  124. parent = parent.parentNode;
  125. }
  126. if (parent) {
  127. language = (parent.className.match(lang) || [,''])[1];
  128. grammar = _.languages[language];
  129. }
  130. if (!grammar) {
  131. return;
  132. }
  133. // Set language on the element, if not present
  134. element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
  135. // Set language on the parent, for styling
  136. parent = element.parentNode;
  137. if (/pre/i.test(parent.nodeName)) {
  138. parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
  139. }
  140. var code = element.textContent;
  141. if(!code) {
  142. return;
  143. }
  144. code = code.replace(/^(?:\r?\n|\r)/,'');
  145. var env = {
  146. element: element,
  147. language: language,
  148. grammar: grammar,
  149. code: code
  150. };
  151. _.hooks.run('before-highlight', env);
  152. // if (async && self.Worker) {
  153. // var worker = new Worker(_.filename);
  154. // worker.onmessage = function(evt) {
  155. // env.highlightedCode = Token.stringify(JSON.parse(evt.data), language);
  156. // _.hooks.run('before-insert', env);
  157. // env.element.innerHTML = env.highlightedCode;
  158. // callback && callback.call(env.element);
  159. // _.hooks.run('after-highlight', env);
  160. // };
  161. // worker.postMessage(JSON.stringify({
  162. // language: env.language,
  163. // code: env.code
  164. // }));
  165. // }
  166. // else {
  167. env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
  168. _.hooks.run('before-insert', env);
  169. env.element.innerHTML = env.highlightedCode;
  170. callback && callback.call(element);
  171. _.hooks.run('after-highlight', env);
  172. // }
  173. },
  174. highlight: function (text, grammar, language) {
  175. var tokens = _.tokenize(text, grammar);
  176. return Token.stringify(_.util.encode(tokens), language);
  177. },
  178. tokenize: function(text, grammar, language) {
  179. var Token = _.Token;
  180. var strarr = [text];
  181. var rest = grammar.rest;
  182. if (rest) {
  183. for (var token in rest) {
  184. grammar[token] = rest[token];
  185. }
  186. delete grammar.rest;
  187. }
  188. tokenloop: for (var token in grammar) {
  189. if(!grammar.hasOwnProperty(token) || !grammar[token]) {
  190. continue;
  191. }
  192. var patterns = grammar[token];
  193. patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns];
  194. for (var j = 0; j < patterns.length; ++j) {
  195. var pattern = patterns[j],
  196. inside = pattern.inside,
  197. lookbehind = !!pattern.lookbehind,
  198. lookbehindLength = 0,
  199. alias = pattern.alias;
  200. pattern = pattern.pattern || pattern;
  201. for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop
  202. var str = strarr[i];
  203. if (strarr.length > text.length) {
  204. // Something went terribly wrong, ABORT, ABORT!
  205. break tokenloop;
  206. }
  207. if (str instanceof Token) {
  208. continue;
  209. }
  210. pattern.lastIndex = 0;
  211. var match = pattern.exec(str);
  212. if (match) {
  213. if(lookbehind) {
  214. lookbehindLength = match[1].length;
  215. }
  216. var from = match.index - 1 + lookbehindLength,
  217. match = match[0].slice(lookbehindLength),
  218. len = match.length,
  219. to = from + len,
  220. before = str.slice(0, from + 1),
  221. after = str.slice(to + 1);
  222. var args = [i, 1];
  223. if (before) {
  224. args.push(before);
  225. }
  226. var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias);
  227. args.push(wrapped);
  228. if (after) {
  229. args.push(after);
  230. }
  231. Array.prototype.splice.apply(strarr, args);
  232. }
  233. }
  234. }
  235. }
  236. return strarr;
  237. },
  238. hooks: {
  239. all: {},
  240. add: function (name, callback) {
  241. var hooks = _.hooks.all;
  242. hooks[name] = hooks[name] || [];
  243. hooks[name].push(callback);
  244. },
  245. run: function (name, env) {
  246. var callbacks = _.hooks.all[name];
  247. if (!callbacks || !callbacks.length) {
  248. return;
  249. }
  250. for (var i=0, callback; callback = callbacks[i++];) {
  251. callback(env);
  252. }
  253. }
  254. }
  255. };
  256. var Token = _.Token = function(type, content, alias) {
  257. this.type = type;
  258. this.content = content;
  259. this.alias = alias;
  260. };
  261. Token.stringify = function(o, language, parent) {
  262. if (typeof o == 'string') {
  263. return o;
  264. }
  265. if (_.util.type(o) === 'Array') {
  266. return o.map(function(element) {
  267. return Token.stringify(element, language, o);
  268. }).join('');
  269. }
  270. var env = {
  271. type: o.type,
  272. content: Token.stringify(o.content, language, parent),
  273. tag: 'span',
  274. classes: ['token', o.type],
  275. attributes: {},
  276. language: language,
  277. parent: parent
  278. };
  279. if (env.type == 'comment') {
  280. env.attributes['spellcheck'] = 'true';
  281. }
  282. if (o.alias) {
  283. var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
  284. Array.prototype.push.apply(env.classes, aliases);
  285. }
  286. _.hooks.run('wrap', env);
  287. var attributes = '';
  288. for (var name in env.attributes) {
  289. attributes += name + '="' + (env.attributes[name] || '') + '"';
  290. }
  291. return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>';
  292. };
  293. // if (!self.document) {
  294. // if (!self.addEventListener) {
  295. // // in Node.js
  296. // return self.Prism;
  297. // }
  298. // // In worker
  299. // self.addEventListener('message', function(evt) {
  300. // var message = JSON.parse(evt.data),
  301. // lang = message.language,
  302. // code = message.code;
  303. // self.postMessage(JSON.stringify(_.util.encode(_.tokenize(code, _.languages[lang]))));
  304. // self.close();
  305. // }, false);
  306. // return self.Prism;
  307. // }
  308. // // Get current script and highlight
  309. // var script = document.getElementsByTagName('script');
  310. // script = script[script.length - 1];
  311. // if (script) {
  312. // _.filename = script.src;
  313. // if (document.addEventListener && !script.hasAttribute('data-manual')) {
  314. // document.addEventListener('DOMContentLoaded', _.highlightAll);
  315. // }
  316. // }
  317. return self.Prism;
  318. })();
  319. if (typeof module !== 'undefined' && module.exports) {
  320. module.exports = Prism;
  321. }
  322. ;
  323. Prism.languages.markup = {
  324. 'comment': /<!--[\w\W]*?-->/,
  325. 'prolog': /<\?.+?\?>/,
  326. 'doctype': /<!DOCTYPE.+?>/,
  327. 'cdata': /<!\[CDATA\[[\w\W]*?]]>/i,
  328. 'tag': {
  329. pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/i,
  330. inside: {
  331. 'tag': {
  332. pattern: /^<\/?[\w:-]+/i,
  333. inside: {
  334. 'punctuation': /^<\/?/,
  335. 'namespace': /^[\w-]+?:/
  336. }
  337. },
  338. 'attr-value': {
  339. pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,
  340. inside: {
  341. 'punctuation': /=|>|"/
  342. }
  343. },
  344. 'punctuation': /\/?>/,
  345. 'attr-name': {
  346. pattern: /[\w:-]+/,
  347. inside: {
  348. 'namespace': /^[\w-]+?:/
  349. }
  350. }
  351. }
  352. },
  353. 'entity': /&#?[\da-z]{1,8};/i
  354. };
  355. // Plugin to make entity title show the real entity, idea by Roman Komarov
  356. Prism.hooks.add('wrap', function(env) {
  357. if (env.type === 'entity') {
  358. env.attributes['title'] = env.content.replace(/&amp;/, '&');
  359. }
  360. });
  361. ;
  362. Prism.languages.css = {
  363. 'comment': /\/\*[\w\W]*?\*\//,
  364. 'atrule': {
  365. pattern: /@[\w-]+?.*?(;|(?=\s*\{))/i,
  366. inside: {
  367. 'punctuation': /[;:]/
  368. }
  369. },
  370. 'url': /url\((?:(["'])(\\\n|\\?.)*?\1|.*?)\)/i,
  371. 'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/,
  372. 'string': /("|')(\\\n|\\?.)*?\1/,
  373. 'property': /(\b|\B)[\w-]+(?=\s*:)/i,
  374. 'important': /\B!important\b/i,
  375. 'punctuation': /[\{\};:]/,
  376. 'function': /[-a-z0-9]+(?=\()/i
  377. };
  378. if (Prism.languages.markup) {
  379. Prism.languages.insertBefore('markup', 'tag', {
  380. 'style': {
  381. pattern: /<style[\w\W]*?>[\w\W]*?<\/style>/i,
  382. inside: {
  383. 'tag': {
  384. pattern: /<style[\w\W]*?>|<\/style>/i,
  385. inside: Prism.languages.markup.tag.inside
  386. },
  387. rest: Prism.languages.css
  388. },
  389. alias: 'language-css'
  390. }
  391. });
  392. Prism.languages.insertBefore('inside', 'attr-value', {
  393. 'style-attr': {
  394. pattern: /\s*style=("|').*?\1/i,
  395. inside: {
  396. 'attr-name': {
  397. pattern: /^\s*style/i,
  398. inside: Prism.languages.markup.tag.inside
  399. },
  400. 'punctuation': /^\s*=\s*['"]|['"]\s*$/,
  401. 'attr-value': {
  402. pattern: /.+/i,
  403. inside: Prism.languages.css
  404. }
  405. },
  406. alias: 'language-css'
  407. }
  408. }, Prism.languages.markup.tag);
  409. };
  410. Prism.languages.clike = {
  411. 'comment': [
  412. {
  413. pattern: /(^|[^\\])\/\*[\w\W]*?\*\//,
  414. lookbehind: true
  415. },
  416. {
  417. pattern: /(^|[^\\:])\/\/.*/,
  418. lookbehind: true
  419. }
  420. ],
  421. 'string': /("|')(\\\n|\\?.)*?\1/,
  422. 'class-name': {
  423. pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,
  424. lookbehind: true,
  425. inside: {
  426. punctuation: /(\.|\\)/
  427. }
  428. },
  429. 'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
  430. 'boolean': /\b(true|false)\b/,
  431. 'function': {
  432. pattern: /[a-z0-9_]+\(/i,
  433. inside: {
  434. punctuation: /\(/
  435. }
  436. },
  437. 'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,
  438. 'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,
  439. 'ignore': /&(lt|gt|amp);/i,
  440. 'punctuation': /[{}[\];(),.:]/
  441. };
  442. ;
  443. Prism.languages.javascript = Prism.languages.extend('clike', {
  444. 'keyword': /\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,
  445. 'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/,
  446. 'function': /(?!\d)[a-z0-9_$]+(?=\()/i
  447. });
  448. Prism.languages.insertBefore('javascript', 'keyword', {
  449. 'regex': {
  450. pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,
  451. lookbehind: true
  452. }
  453. });
  454. if (Prism.languages.markup) {
  455. Prism.languages.insertBefore('markup', 'tag', {
  456. 'script': {
  457. pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/i,
  458. inside: {
  459. 'tag': {
  460. pattern: /<script[\w\W]*?>|<\/script>/i,
  461. inside: Prism.languages.markup.tag.inside
  462. },
  463. rest: Prism.languages.javascript
  464. },
  465. alias: 'language-javascript'
  466. }
  467. });
  468. }
  469. ;
  470. Prism.languages.c = Prism.languages.extend('clike', {
  471. // allow for c multiline strings
  472. 'string': /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/,
  473. 'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,
  474. 'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//
  475. });
  476. Prism.languages.insertBefore('c', 'string', {
  477. // property class reused for macro statements
  478. 'property': {
  479. // allow for multiline macro definitions
  480. // spaces after the # character compile fine with gcc
  481. pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/i,
  482. lookbehind: true,
  483. inside: {
  484. // highlight the path of the include statement as a string
  485. 'string': {
  486. pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,
  487. lookbehind: true
  488. }
  489. }
  490. }
  491. });
  492. delete Prism.languages.c['class-name'];
  493. delete Prism.languages.c['boolean'];;
  494. Prism.languages.cpp = Prism.languages.extend('c', {
  495. 'keyword': /\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|delete\[\]|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|new\[\]|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|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/,
  496. 'boolean': /\b(true|false)\b/,
  497. 'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/
  498. });
  499. Prism.languages.insertBefore('cpp', 'keyword', {
  500. 'class-name': {
  501. pattern: /(class\s+)[a-z0-9_]+/i,
  502. lookbehind: true
  503. }
  504. });;
  505. (function(Prism) {
  506. // Ignore comments starting with { to privilege string interpolation highlighting
  507. var comment = /#(?!\{).+/,
  508. interpolation = {
  509. pattern: /#\{[^}]+\}/,
  510. alias: 'variable'
  511. };
  512. Prism.languages.coffeescript = Prism.languages.extend('javascript', {
  513. 'comment': comment,
  514. 'string': [
  515. // Strings are multiline
  516. /'(?:\\?[\s\S])*?'/,
  517. {
  518. // Strings are multiline
  519. pattern: /"(?:\\?[\s\S])*?"/,
  520. inside: {
  521. 'interpolation': interpolation
  522. }
  523. }
  524. ],
  525. '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/,
  526. 'class-member': {
  527. pattern: /@(?!\d)\w+/,
  528. alias: 'variable'
  529. }
  530. });
  531. Prism.languages.insertBefore('coffeescript', 'comment', {
  532. 'multiline-comment': {
  533. pattern: /###[\s\S]+?###/,
  534. alias: 'comment'
  535. },
  536. // Block regexp can contain comments and interpolation
  537. 'block-regex': {
  538. pattern: /\/{3}[\s\S]*?\/{3}/,
  539. alias: 'regex',
  540. inside: {
  541. 'comment': comment,
  542. 'interpolation': interpolation
  543. }
  544. }
  545. });
  546. Prism.languages.insertBefore('coffeescript', 'string', {
  547. 'inline-javascript': {
  548. pattern: /`(?:\\?[\s\S])*?`/,
  549. inside: {
  550. 'delimiter': {
  551. pattern: /^`|`$/,
  552. alias: 'punctuation'
  553. },
  554. rest: Prism.languages.javascript
  555. }
  556. },
  557. // Block strings
  558. 'multiline-string': [
  559. {
  560. pattern: /'''[\s\S]*?'''/,
  561. alias: 'string'
  562. },
  563. {
  564. pattern: /"""[\s\S]*?"""/,
  565. alias: 'string',
  566. inside: {
  567. interpolation: interpolation
  568. }
  569. }
  570. ]
  571. });
  572. Prism.languages.insertBefore('coffeescript', 'keyword', {
  573. // Object property
  574. 'property': /(?!\d)\w+(?=\s*:(?!:))/
  575. });
  576. }(Prism));;
  577. /**
  578. * Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/
  579. * Modified by Miles Johnson: http://milesj.me
  580. *
  581. * Supports the following:
  582. * - Extends clike syntax
  583. * - Support for PHP 5.3+ (namespaces, traits, generators, etc)
  584. * - Smarter constant and function matching
  585. *
  586. * Adds the following new token classes:
  587. * constant, delimiter, variable, function, package
  588. */
  589. Prism.languages.php = Prism.languages.extend('clike', {
  590. 'keyword': /\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,
  591. 'constant': /\b[A-Z0-9_]{2,}\b/,
  592. 'comment': {
  593. pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])(\/\/).*?(\r?\n|$))/,
  594. lookbehind: true
  595. }
  596. });
  597. // Shell-like comments are matched after strings, because they are less
  598. // common than strings containing hashes...
  599. Prism.languages.insertBefore('php', 'class-name', {
  600. 'shell-comment': {
  601. pattern: /(^|[^\\])#.*?(\r?\n|$)/,
  602. lookbehind: true,
  603. alias: 'comment'
  604. }
  605. });
  606. Prism.languages.insertBefore('php', 'keyword', {
  607. 'delimiter': /(\?>|<\?php|<\?)/i,
  608. 'variable': /(\$\w+)\b/i,
  609. 'package': {
  610. pattern: /(\\|namespace\s+|use\s+)[\w\\]+/,
  611. lookbehind: true,
  612. inside: {
  613. punctuation: /\\/
  614. }
  615. }
  616. });
  617. // Must be defined after the function pattern
  618. Prism.languages.insertBefore('php', 'operator', {
  619. 'property': {
  620. pattern: /(->)[\w]+/,
  621. lookbehind: true
  622. }
  623. });
  624. // Add HTML support of the markup language exists
  625. if (Prism.languages.markup) {
  626. // Tokenize all inline PHP blocks that are wrapped in <?php ?>
  627. // This allows for easy PHP + markup highlighting
  628. Prism.hooks.add('before-highlight', function(env) {
  629. if (env.language !== 'php') {
  630. return;
  631. }
  632. env.tokenStack = [];
  633. env.backupCode = env.code;
  634. env.code = env.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/ig, function(match) {
  635. env.tokenStack.push(match);
  636. return '{{{PHP' + env.tokenStack.length + '}}}';
  637. });
  638. });
  639. // Restore env.code for other plugins (e.g. line-numbers)
  640. Prism.hooks.add('before-insert', function(env) {
  641. if (env.language === 'php') {
  642. env.code = env.backupCode;
  643. delete env.backupCode;
  644. }
  645. });
  646. // Re-insert the tokens after highlighting
  647. Prism.hooks.add('after-highlight', function(env) {
  648. if (env.language !== 'php') {
  649. return;
  650. }
  651. for (var i = 0, t; t = env.tokenStack[i]; i++) {
  652. env.highlightedCode = env.highlightedCode.replace('{{{PHP' + (i + 1) + '}}}', Prism.highlight(t, env.grammar, 'php'));
  653. }
  654. env.element.innerHTML = env.highlightedCode;
  655. });
  656. // Wrap tokens in classes that are missing them
  657. Prism.hooks.add('wrap', function(env) {
  658. if (env.language === 'php' && env.type === 'markup') {
  659. env.content = env.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g, "<span class=\"token php\">$1</span>");
  660. }
  661. });
  662. // Add the rules before all others
  663. Prism.languages.insertBefore('php', 'comment', {
  664. 'markup': {
  665. pattern: /<[^?]\/?(.*?)>/,
  666. inside: Prism.languages.markup
  667. },
  668. 'php': /\{\{\{PHP[0-9]+\}\}\}/
  669. });
  670. }
  671. ;
  672. Prism.languages.python= {
  673. 'comment': {
  674. pattern: /(^|[^\\])#.*?(\r?\n|$)/,
  675. lookbehind: true
  676. },
  677. 'string': /"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(\\?.)*?\1/,
  678. 'keyword' : /\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,
  679. 'boolean' : /\b(True|False)\b/,
  680. 'number' : /\b-?(0[box])?(?:[\da-f]+\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,
  681. 'operator' : /[-+]|<=?|>=?|!|={1,2}|&{1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/,
  682. 'punctuation' : /[{}[\];(),.:]/
  683. };
  684. ;
  685. /**
  686. * Original by Samuel Flores
  687. *
  688. * Adds the following new token classes:
  689. * constant, builtin, variable, symbol, regex
  690. */
  691. Prism.languages.ruby = Prism.languages.extend('clike', {
  692. 'comment': /#[^\r\n]*(\r?\n|$)/,
  693. 'keyword': /\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/,
  694. 'builtin': /\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,
  695. 'constant': /\b[A-Z][a-zA-Z_0-9]*[?!]?\b/
  696. });
  697. Prism.languages.insertBefore('ruby', 'keyword', {
  698. 'regex': {
  699. pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,
  700. lookbehind: true
  701. },
  702. 'variable': /[@$]+\b[a-zA-Z_][a-zA-Z_0-9]*[?!]?\b/,
  703. 'symbol': /:\b[a-zA-Z_][a-zA-Z_0-9]*[?!]?\b/
  704. });
  705. ;
  706. /* TODO
  707. Add support for Markdown notation inside doc comments
  708. Add support for nested block comments...
  709. Match closure params even when not followed by dash or brace
  710. Add better support for macro definition
  711. */
  712. Prism.languages.rust = {
  713. 'comment': [
  714. {
  715. pattern: /(^|[^\\])\/\*[\w\W]*?\*\//,
  716. lookbehind: true
  717. },
  718. {
  719. pattern: /(^|[^\\:])\/\/.*?(\r?\n|$)/,
  720. lookbehind: true
  721. }
  722. ],
  723. 'string': [
  724. /b?r(#*)"(?:\\?.)*?"\1/,
  725. /b?("|')(?:\\?.)*?\1/
  726. ],
  727. 'keyword': /\b(?:abstract|alignof|as|be|box|break|const|continue|crate|do|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|match|mod|move|mut|offsetof|once|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\b/,
  728. 'attribute': {
  729. pattern: /#!?\[.+?\]/,
  730. alias: 'attr-name'
  731. },
  732. 'function': [
  733. /[a-z0-9_]+(?=\s*\()/i,
  734. // Macros can use parens or brackets
  735. /[a-z0-9_]+!(?=\s*\(|\[)/i
  736. ],
  737. 'macro-rules': {
  738. pattern: /[a-z0-9_]+!/i,
  739. alias: 'function'
  740. },
  741. // Hex, oct, bin, dec numbers with visual separators and type suffix
  742. 'number': /\b-?(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(\d(_?\d)*)?\.?\d(_?\d)*([Ee][+-]?\d+)?)(?:_?(?:[iu](?:8|16|32)?|f32|f64))?\b/,
  743. // Closure params should not be confused with bitwise OR |
  744. 'closure-params': {
  745. pattern: /\|[^|]*\|(?=\s*[{-])/,
  746. inside: {
  747. 'punctuation': /[\|:,]/,
  748. 'operator': /[&*]/
  749. }
  750. },
  751. 'punctuation': /[{}[\];(),.:]|->/,
  752. 'operator': /[-+]{1,2}|!=?|<=?|>=?|={1,3}|&&?|\|\|?|\*|\/|\^|%|<<|>>@/
  753. };;