prettify.js 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526
  1. // This code comes from the December 2009 release of Google Prettify, which is Copyright © 2006 Google Inc.
  2. // Minor modifications are marked with "ND Change" comments.
  3. // As part of Natural Docs, this code is licensed under version 3 of the GNU Affero General Public License (AGPL.)
  4. // However, it may also be obtained separately under version 2.0 of the Apache License.
  5. // Refer to License.txt for the complete details
  6. // Main code
  7. // ____________________________________________________________________________
  8. // Copyright (C) 2006 Google Inc.
  9. //
  10. // Licensed under the Apache License, Version 2.0 (the "License");
  11. // you may not use this file except in compliance with the License.
  12. // You may obtain a copy of the License at
  13. //
  14. // http://www.apache.org/licenses/LICENSE-2.0
  15. //
  16. // Unless required by applicable law or agreed to in writing, software
  17. // distributed under the License is distributed on an "AS IS" BASIS,
  18. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. // See the License for the specific language governing permissions and
  20. // limitations under the License.
  21. /**
  22. * @fileoverview
  23. * some functions for browser-side pretty printing of code contained in html.
  24. * <p>
  25. *
  26. * For a fairly comprehensive set of languages see the
  27. * <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs">README</a>
  28. * file that came with this source. At a minimum, the lexer should work on a
  29. * number of languages including C and friends, Java, Python, Bash, SQL, HTML,
  30. * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk
  31. * and a subset of Perl, but, because of commenting conventions, doesn't work on
  32. * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.
  33. * <p>
  34. * Usage: <ol>
  35. * <li> include this source file in an html page via
  36. * {@code <script type="text/javascript" src="/path/to/prettify.js"></script>}
  37. * <li> define style rules. See the example page for examples.
  38. * <li> mark the {@code <pre>} and {@code <code>} tags in your source with
  39. * {@code class=prettyprint.}
  40. * You can also use the (html deprecated) {@code <xmp>} tag, but the pretty
  41. * printer needs to do more substantial DOM manipulations to support that, so
  42. * some css styles may not be preserved.
  43. * </ol>
  44. * That's it. I wanted to keep the API as simple as possible, so there's no
  45. * need to specify which language the code is in, but if you wish, you can add
  46. * another class to the {@code <pre>} or {@code <code>} element to specify the
  47. * language, as in {@code <pre class="prettyprint lang-java">}. Any class that
  48. * starts with "lang-" followed by a file extension, specifies the file type.
  49. * See the "lang-*.js" files in this directory for code that implements
  50. * per-language file handlers.
  51. * <p>
  52. * Change log:<br>
  53. * cbeust, 2006/08/22
  54. * <blockquote>
  55. * Java annotations (start with "@") are now captured as literals ("lit")
  56. * </blockquote>
  57. * @requires console
  58. * @overrides window
  59. */
  60. // JSLint declarations
  61. /*global console, document, navigator, setTimeout, window */
  62. /**
  63. * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
  64. * UI events.
  65. * If set to {@code false}, {@code prettyPrint()} is synchronous.
  66. */
  67. window['PR_SHOULD_USE_CONTINUATION'] = true;
  68. /** the number of characters between tab columns */
  69. window['PR_TAB_WIDTH'] = 8;
  70. /** Walks the DOM returning a properly escaped version of innerHTML.
  71. * @param {Node} node
  72. * @param {Array.<string>} out output buffer that receives chunks of HTML.
  73. */
  74. window['PR_normalizedHtml']
  75. /** Contains functions for creating and registering new language handlers.
  76. * @type {Object}
  77. */
  78. = window['PR']
  79. /** Pretty print a chunk of code.
  80. *
  81. * @param {string} sourceCodeHtml code as html
  82. * @return {string} code as html, but prettier
  83. */
  84. = window['prettyPrintOne']
  85. /** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
  86. * {@code class=prettyprint} and prettify them.
  87. * @param {Function?} opt_whenDone if specified, called when the last entry
  88. * has been finished.
  89. */
  90. = window['prettyPrint'] = void 0;
  91. /** browser detection. @extern @returns false if not IE, otherwise the major version. */
  92. window['_pr_isIE6'] = function () {
  93. var ieVersion = navigator && navigator.userAgent &&
  94. navigator.userAgent.match(/\bMSIE ([678])\./);
  95. ieVersion = ieVersion ? +ieVersion[1] : false;
  96. window['_pr_isIE6'] = function () { return ieVersion; };
  97. return ieVersion;
  98. };
  99. (function () {
  100. // Keyword lists for various languages.
  101. var FLOW_CONTROL_KEYWORDS =
  102. "break continue do else for if return while ";
  103. var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
  104. "double enum extern float goto int long register short signed sizeof " +
  105. "static struct switch typedef union unsigned void volatile ";
  106. var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
  107. "new operator private protected public this throw true try typeof ";
  108. var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
  109. "concept concept_map const_cast constexpr decltype " +
  110. "dynamic_cast explicit export friend inline late_check " +
  111. "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
  112. "template typeid typename using virtual wchar_t where ";
  113. var JAVA_KEYWORDS = COMMON_KEYWORDS +
  114. "abstract boolean byte extends final finally implements import " +
  115. "instanceof null native package strictfp super synchronized throws " +
  116. "transient ";
  117. var CSHARP_KEYWORDS = JAVA_KEYWORDS +
  118. "as base by checked decimal delegate descending event " +
  119. "fixed foreach from group implicit in interface internal into is lock " +
  120. "object out override orderby params partial readonly ref sbyte sealed " +
  121. "stackalloc string select uint ulong unchecked unsafe ushort var ";
  122. var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
  123. "debugger eval export function get null set undefined var with " +
  124. "Infinity NaN ";
  125. var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
  126. "goto if import last local my next no our print package redo require " +
  127. "sub undef unless until use wantarray while BEGIN END ";
  128. var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
  129. "elif except exec finally from global import in is lambda " +
  130. "nonlocal not or pass print raise try with yield " +
  131. "False True None ";
  132. var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
  133. " defined elsif end ensure false in module next nil not or redo rescue " +
  134. "retry self super then true undef unless until when yield BEGIN END ";
  135. var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
  136. "function in local set then until ";
  137. var ALL_KEYWORDS = (
  138. CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
  139. PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
  140. // token style names. correspond to css classes
  141. /** token style for a string literal */
  142. var PR_STRING = 'str';
  143. /** token style for a keyword */
  144. var PR_KEYWORD = 'kwd';
  145. /** token style for a comment */
  146. var PR_COMMENT = 'com';
  147. /** token style for a type */
  148. var PR_TYPE = 'typ';
  149. /** token style for a literal value. e.g. 1, null, true. */
  150. var PR_LITERAL = 'lit';
  151. /** token style for a punctuation string. */
  152. var PR_PUNCTUATION = 'pun';
  153. /** token style for a punctuation string. */
  154. var PR_PLAIN = 'pln';
  155. /** token style for an sgml tag. */
  156. var PR_TAG = 'tag';
  157. /** token style for a markup declaration such as a DOCTYPE. */
  158. var PR_DECLARATION = 'dec';
  159. /** token style for embedded source. */
  160. var PR_SOURCE = 'src';
  161. /** token style for an sgml attribute name. */
  162. var PR_ATTRIB_NAME = 'atn';
  163. /** token style for an sgml attribute value. */
  164. var PR_ATTRIB_VALUE = 'atv';
  165. /**
  166. * A class that indicates a section of markup that is not code, e.g. to allow
  167. * embedding of line numbers within code listings.
  168. */
  169. var PR_NOCODE = 'nocode';
  170. /** A set of tokens that can precede a regular expression literal in
  171. * javascript.
  172. * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
  173. * list, but I've removed ones that might be problematic when seen in
  174. * languages that don't support regular expression literals.
  175. *
  176. * <p>Specifically, I've removed any keywords that can't precede a regexp
  177. * literal in a syntactically legal javascript program, and I've removed the
  178. * "in" keyword since it's not a keyword in many languages, and might be used
  179. * as a count of inches.
  180. *
  181. * <p>The link a above does not accurately describe EcmaScript rules since
  182. * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
  183. * very well in practice.
  184. *
  185. * @private
  186. */
  187. var REGEXP_PRECEDER_PATTERN = function () {
  188. var preceders = [
  189. "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
  190. "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
  191. "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
  192. "<", "<<", "<<=", "<=", "=", "==", "===", ">",
  193. ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
  194. "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
  195. "||=", "~" /* handles =~ and !~ */,
  196. "break", "case", "continue", "delete",
  197. "do", "else", "finally", "instanceof",
  198. "return", "throw", "try", "typeof"
  199. ];
  200. var pattern = '(?:^^|[+-]';
  201. for (var i = 0; i < preceders.length; ++i) {
  202. pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
  203. }
  204. pattern += ')\\s*'; // matches at end, and matches empty string
  205. return pattern;
  206. // CAVEAT: this does not properly handle the case where a regular
  207. // expression immediately follows another since a regular expression may
  208. // have flags for case-sensitivity and the like. Having regexp tokens
  209. // adjacent is not valid in any language I'm aware of, so I'm punting.
  210. // TODO: maybe style special characters inside a regexp as punctuation.
  211. }();
  212. // Define regexps here so that the interpreter doesn't have to create an
  213. // object each time the function containing them is called.
  214. // The language spec requires a new object created even if you don't access
  215. // the $1 members.
  216. var pr_amp = /&/g;
  217. var pr_lt = /</g;
  218. var pr_gt = />/g;
  219. var pr_quot = /\"/g;
  220. /** like textToHtml but escapes double quotes to be attribute safe. */
  221. function attribToHtml(str) {
  222. return str.replace(pr_amp, '&amp;')
  223. .replace(pr_lt, '&lt;')
  224. .replace(pr_gt, '&gt;')
  225. .replace(pr_quot, '&quot;');
  226. }
  227. /** escapest html special characters to html. */
  228. function textToHtml(str) {
  229. return str.replace(pr_amp, '&amp;')
  230. .replace(pr_lt, '&lt;')
  231. .replace(pr_gt, '&gt;');
  232. }
  233. var pr_ltEnt = /&lt;/g;
  234. var pr_gtEnt = /&gt;/g;
  235. var pr_aposEnt = /&apos;/g;
  236. var pr_quotEnt = /&quot;/g;
  237. var pr_ampEnt = /&amp;/g;
  238. var pr_nbspEnt = /&nbsp;/g;
  239. /** unescapes html to plain text. */
  240. function htmlToText(html) {
  241. var pos = html.indexOf('&');
  242. if (pos < 0) { return html; }
  243. // Handle numeric entities specially. We can't use functional substitution
  244. // since that doesn't work in older versions of Safari.
  245. // These should be rare since most browsers convert them to normal chars.
  246. for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
  247. var end = html.indexOf(';', pos);
  248. if (end >= 0) {
  249. var num = html.substring(pos + 3, end);
  250. var radix = 10;
  251. if (num && num.charAt(0) === 'x') {
  252. num = num.substring(1);
  253. radix = 16;
  254. }
  255. var codePoint = parseInt(num, radix);
  256. if (!isNaN(codePoint)) {
  257. html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
  258. html.substring(end + 1));
  259. }
  260. }
  261. }
  262. return html.replace(pr_ltEnt, '<')
  263. .replace(pr_gtEnt, '>')
  264. .replace(pr_aposEnt, "'")
  265. .replace(pr_quotEnt, '"')
  266. .replace(pr_nbspEnt, ' ')
  267. .replace(pr_ampEnt, '&');
  268. }
  269. /** is the given node's innerHTML normally unescaped? */
  270. function isRawContent(node) {
  271. return 'XMP' === node.tagName;
  272. }
  273. var newlineRe = /[\r\n]/g;
  274. /**
  275. * Are newlines and adjacent spaces significant in the given node's innerHTML?
  276. */
  277. function isPreformatted(node, content) {
  278. // PRE means preformatted, and is a very common case, so don't create
  279. // unnecessary computed style objects.
  280. if ('PRE' === node.tagName) { return true; }
  281. if (!newlineRe.test(content)) { return true; } // Don't care
  282. var whitespace = '';
  283. // For disconnected nodes, IE has no currentStyle.
  284. if (node.currentStyle) {
  285. whitespace = node.currentStyle.whiteSpace;
  286. } else if (window.getComputedStyle) {
  287. // Firefox makes a best guess if node is disconnected whereas Safari
  288. // returns the empty string.
  289. whitespace = window.getComputedStyle(node, null).whiteSpace;
  290. }
  291. return !whitespace || whitespace === 'pre';
  292. }
  293. function normalizedHtml(node, out) {
  294. switch (node.nodeType) {
  295. case 1: // an element
  296. var name = node.tagName.toLowerCase();
  297. out.push('<', name);
  298. for (var i = 0; i < node.attributes.length; ++i) {
  299. var attr = node.attributes[i];
  300. if (!attr.specified) { continue; }
  301. out.push(' ');
  302. normalizedHtml(attr, out);
  303. }
  304. out.push('>');
  305. for (var child = node.firstChild; child; child = child.nextSibling) {
  306. normalizedHtml(child, out);
  307. }
  308. if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
  309. out.push('<\/', name, '>');
  310. }
  311. break;
  312. case 2: // an attribute
  313. out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
  314. break;
  315. case 3: case 4: // text
  316. out.push(textToHtml(node.nodeValue));
  317. break;
  318. }
  319. }
  320. /**
  321. * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
  322. * matches the union o the sets o strings matched d by the input RegExp.
  323. * Since it matches globally, if the input strings have a start-of-input
  324. * anchor (/^.../), it is ignored for the purposes of unioning.
  325. * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
  326. * @return {RegExp} a global regex.
  327. */
  328. function combinePrefixPatterns(regexs) {
  329. var capturedGroupIndex = 0;
  330. var needToFoldCase = false;
  331. var ignoreCase = false;
  332. for (var i = 0, n = regexs.length; i < n; ++i) {
  333. var regex = regexs[i];
  334. if (regex.ignoreCase) {
  335. ignoreCase = true;
  336. } else if (/[a-z]/i.test(regex.source.replace(
  337. /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
  338. needToFoldCase = true;
  339. ignoreCase = false;
  340. break;
  341. }
  342. }
  343. function decodeEscape(charsetPart) {
  344. if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
  345. switch (charsetPart.charAt(1)) {
  346. case 'b': return 8;
  347. case 't': return 9;
  348. case 'n': return 0xa;
  349. case 'v': return 0xb;
  350. case 'f': return 0xc;
  351. case 'r': return 0xd;
  352. case 'u': case 'x':
  353. return parseInt(charsetPart.substring(2), 16)
  354. || charsetPart.charCodeAt(1);
  355. case '0': case '1': case '2': case '3': case '4':
  356. case '5': case '6': case '7':
  357. return parseInt(charsetPart.substring(1), 8);
  358. default: return charsetPart.charCodeAt(1);
  359. }
  360. }
  361. function encodeEscape(charCode) {
  362. if (charCode < 0x20) {
  363. return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
  364. }
  365. var ch = String.fromCharCode(charCode);
  366. if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
  367. ch = '\\' + ch;
  368. }
  369. return ch;
  370. }
  371. function caseFoldCharset(charSet) {
  372. var charsetParts = charSet.substring(1, charSet.length - 1).match(
  373. new RegExp(
  374. '\\\\u[0-9A-Fa-f]{4}'
  375. + '|\\\\x[0-9A-Fa-f]{2}'
  376. + '|\\\\[0-3][0-7]{0,2}'
  377. + '|\\\\[0-7]{1,2}'
  378. + '|\\\\[\\s\\S]'
  379. + '|-'
  380. + '|[^-\\\\]',
  381. 'g'));
  382. var groups = [];
  383. var ranges = [];
  384. var inverse = charsetParts[0] === '^';
  385. for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
  386. var p = charsetParts[i];
  387. switch (p) {
  388. case '\\B': case '\\b':
  389. case '\\D': case '\\d':
  390. case '\\S': case '\\s':
  391. case '\\W': case '\\w':
  392. groups.push(p);
  393. continue;
  394. }
  395. var start = decodeEscape(p);
  396. var end;
  397. if (i + 2 < n && '-' === charsetParts[i + 1]) {
  398. end = decodeEscape(charsetParts[i + 2]);
  399. i += 2;
  400. } else {
  401. end = start;
  402. }
  403. ranges.push([start, end]);
  404. // If the range might intersect letters, then expand it.
  405. if (!(end < 65 || start > 122)) {
  406. if (!(end < 65 || start > 90)) {
  407. ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
  408. }
  409. if (!(end < 97 || start > 122)) {
  410. ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
  411. }
  412. }
  413. }
  414. // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
  415. // -> [[1, 12], [14, 14], [16, 17]]
  416. ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); });
  417. var consolidatedRanges = [];
  418. var lastRange = [NaN, NaN];
  419. for (var i = 0; i < ranges.length; ++i) {
  420. var range = ranges[i];
  421. if (range[0] <= lastRange[1] + 1) {
  422. lastRange[1] = Math.max(lastRange[1], range[1]);
  423. } else {
  424. consolidatedRanges.push(lastRange = range);
  425. }
  426. }
  427. var out = ['['];
  428. if (inverse) { out.push('^'); }
  429. out.push.apply(out, groups);
  430. for (var i = 0; i < consolidatedRanges.length; ++i) {
  431. var range = consolidatedRanges[i];
  432. out.push(encodeEscape(range[0]));
  433. if (range[1] > range[0]) {
  434. if (range[1] + 1 > range[0]) { out.push('-'); }
  435. out.push(encodeEscape(range[1]));
  436. }
  437. }
  438. out.push(']');
  439. return out.join('');
  440. }
  441. function allowAnywhereFoldCaseAndRenumberGroups(regex) {
  442. // Split into character sets, escape sequences, punctuation strings
  443. // like ('(', '(?:', ')', '^'), and runs of characters that do not
  444. // include any of the above.
  445. var parts = regex.source.match(
  446. new RegExp(
  447. '(?:'
  448. + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set
  449. + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape
  450. + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape
  451. + '|\\\\[0-9]+' // a back-reference or octal escape
  452. + '|\\\\[^ux0-9]' // other escape sequence
  453. + '|\\(\\?[:!=]' // start of a non-capturing group
  454. + '|[\\(\\)\\^]' // start/emd of a group, or line start
  455. + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters
  456. + ')',
  457. 'g'));
  458. var n = parts.length;
  459. // Maps captured group numbers to the number they will occupy in
  460. // the output or to -1 if that has not been determined, or to
  461. // undefined if they need not be capturing in the output.
  462. var capturedGroups = [];
  463. // Walk over and identify back references to build the capturedGroups
  464. // mapping.
  465. for (var i = 0, groupIndex = 0; i < n; ++i) {
  466. var p = parts[i];
  467. if (p === '(') {
  468. // groups are 1-indexed, so max group index is count of '('
  469. ++groupIndex;
  470. } else if ('\\' === p.charAt(0)) {
  471. var decimalValue = +p.substring(1);
  472. if (decimalValue && decimalValue <= groupIndex) {
  473. capturedGroups[decimalValue] = -1;
  474. }
  475. }
  476. }
  477. // Renumber groups and reduce capturing groups to non-capturing groups
  478. // where possible.
  479. for (var i = 1; i < capturedGroups.length; ++i) {
  480. if (-1 === capturedGroups[i]) {
  481. capturedGroups[i] = ++capturedGroupIndex;
  482. }
  483. }
  484. for (var i = 0, groupIndex = 0; i < n; ++i) {
  485. var p = parts[i];
  486. if (p === '(') {
  487. ++groupIndex;
  488. if (capturedGroups[groupIndex] === undefined) {
  489. parts[i] = '(?:';
  490. }
  491. } else if ('\\' === p.charAt(0)) {
  492. var decimalValue = +p.substring(1);
  493. if (decimalValue && decimalValue <= groupIndex) {
  494. parts[i] = '\\' + capturedGroups[groupIndex];
  495. }
  496. }
  497. }
  498. // Remove any prefix anchors so that the output will match anywhere.
  499. // ^^ really does mean an anchored match though.
  500. for (var i = 0, groupIndex = 0; i < n; ++i) {
  501. if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
  502. }
  503. // Expand letters to groupts to handle mixing of case-sensitive and
  504. // case-insensitive patterns if necessary.
  505. if (regex.ignoreCase && needToFoldCase) {
  506. for (var i = 0; i < n; ++i) {
  507. var p = parts[i];
  508. var ch0 = p.charAt(0);
  509. if (p.length >= 2 && ch0 === '[') {
  510. parts[i] = caseFoldCharset(p);
  511. } else if (ch0 !== '\\') {
  512. // TODO: handle letters in numeric escapes.
  513. parts[i] = p.replace(
  514. /[a-zA-Z]/g,
  515. function (ch) {
  516. var cc = ch.charCodeAt(0);
  517. return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
  518. });
  519. }
  520. }
  521. }
  522. return parts.join('');
  523. }
  524. var rewritten = [];
  525. for (var i = 0, n = regexs.length; i < n; ++i) {
  526. var regex = regexs[i];
  527. if (regex.global || regex.multiline) { throw new Error('' + regex); }
  528. rewritten.push(
  529. '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
  530. }
  531. return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
  532. }
  533. var PR_innerHtmlWorks = null;
  534. function getInnerHtml(node) {
  535. // inner html is hopelessly broken in Safari 2.0.4 when the content is
  536. // an html description of well formed XML and the containing tag is a PRE
  537. // tag, so we detect that case and emulate innerHTML.
  538. if (null === PR_innerHtmlWorks) {
  539. var testNode = document.createElement('PRE');
  540. testNode.appendChild(
  541. document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
  542. PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
  543. }
  544. if (PR_innerHtmlWorks) {
  545. var content = node.innerHTML;
  546. // XMP tags contain unescaped entities so require special handling.
  547. if (isRawContent(node)) {
  548. content = textToHtml(content);
  549. } else if (!isPreformatted(node, content)) {
  550. content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
  551. .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
  552. }
  553. return content;
  554. }
  555. var out = [];
  556. for (var child = node.firstChild; child; child = child.nextSibling) {
  557. normalizedHtml(child, out);
  558. }
  559. return out.join('');
  560. }
  561. /** returns a function that expand tabs to spaces. This function can be fed
  562. * successive chunks of text, and will maintain its own internal state to
  563. * keep track of how tabs are expanded.
  564. * @return {function (string) : string} a function that takes
  565. * plain text and return the text with tabs expanded.
  566. * @private
  567. */
  568. function makeTabExpander(tabWidth) {
  569. var SPACES = ' ';
  570. var charInLine = 0;
  571. return function (plainText) {
  572. // walk over each character looking for tabs and newlines.
  573. // On tabs, expand them. On newlines, reset charInLine.
  574. // Otherwise increment charInLine
  575. var out = null;
  576. var pos = 0;
  577. for (var i = 0, n = plainText.length; i < n; ++i) {
  578. var ch = plainText.charAt(i);
  579. switch (ch) {
  580. case '\t':
  581. if (!out) { out = []; }
  582. out.push(plainText.substring(pos, i));
  583. // calculate how much space we need in front of this part
  584. // nSpaces is the amount of padding -- the number of spaces needed
  585. // to move us to the next column, where columns occur at factors of
  586. // tabWidth.
  587. var nSpaces = tabWidth - (charInLine % tabWidth);
  588. charInLine += nSpaces;
  589. for (; nSpaces >= 0; nSpaces -= SPACES.length) {
  590. out.push(SPACES.substring(0, nSpaces));
  591. }
  592. pos = i + 1;
  593. break;
  594. case '\n':
  595. charInLine = 0;
  596. break;
  597. default:
  598. ++charInLine;
  599. }
  600. }
  601. if (!out) { return plainText; }
  602. out.push(plainText.substring(pos));
  603. return out.join('');
  604. };
  605. }
  606. var pr_chunkPattern = new RegExp(
  607. '[^<]+' // A run of characters other than '<'
  608. + '|<\!--[\\s\\S]*?--\>' // an HTML comment
  609. + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>' // a CDATA section
  610. // a probable tag that should not be highlighted
  611. + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
  612. + '|<', // A '<' that does not begin a larger chunk
  613. 'g');
  614. var pr_commentPrefix = /^<\!--/;
  615. var pr_cdataPrefix = /^<!\[CDATA\[/;
  616. var pr_brPrefix = /^<br\b/i;
  617. var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
  618. /** split markup into chunks of html tags (style null) and
  619. * plain text (style {@link #PR_PLAIN}), converting tags which are
  620. * significant for tokenization (<br>) into their textual equivalent.
  621. *
  622. * @param {string} s html where whitespace is considered significant.
  623. * @return {Object} source code and extracted tags.
  624. * @private
  625. */
  626. function extractTags(s) {
  627. // since the pattern has the 'g' modifier and defines no capturing groups,
  628. // this will return a list of all chunks which we then classify and wrap as
  629. // PR_Tokens
  630. var matches = s.match(pr_chunkPattern);
  631. var sourceBuf = [];
  632. var sourceBufLen = 0;
  633. var extractedTags = [];
  634. if (matches) {
  635. for (var i = 0, n = matches.length; i < n; ++i) {
  636. var match = matches[i];
  637. if (match.length > 1 && match.charAt(0) === '<') {
  638. if (pr_commentPrefix.test(match)) { continue; }
  639. if (pr_cdataPrefix.test(match)) {
  640. // strip CDATA prefix and suffix. Don't unescape since it's CDATA
  641. sourceBuf.push(match.substring(9, match.length - 3));
  642. sourceBufLen += match.length - 12;
  643. } else if (pr_brPrefix.test(match)) {
  644. // <br> tags are lexically significant so convert them to text.
  645. // This is undone later.
  646. sourceBuf.push('\n');
  647. ++sourceBufLen;
  648. } else {
  649. if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
  650. // A <span class="nocode"> will start a section that should be
  651. // ignored. Continue walking the list until we see a matching end
  652. // tag.
  653. var name = match.match(pr_tagNameRe)[2];
  654. var depth = 1;
  655. var j;
  656. end_tag_loop:
  657. for (j = i + 1; j < n; ++j) {
  658. var name2 = matches[j].match(pr_tagNameRe);
  659. if (name2 && name2[2] === name) {
  660. if (name2[1] === '/') {
  661. if (--depth === 0) { break end_tag_loop; }
  662. } else {
  663. ++depth;
  664. }
  665. }
  666. }
  667. if (j < n) {
  668. extractedTags.push(
  669. sourceBufLen, matches.slice(i, j + 1).join(''));
  670. i = j;
  671. } else { // Ignore unclosed sections.
  672. extractedTags.push(sourceBufLen, match);
  673. }
  674. } else {
  675. extractedTags.push(sourceBufLen, match);
  676. }
  677. }
  678. } else {
  679. var literalText = htmlToText(match);
  680. sourceBuf.push(literalText);
  681. sourceBufLen += literalText.length;
  682. }
  683. }
  684. }
  685. return { source: sourceBuf.join(''), tags: extractedTags };
  686. }
  687. /** True if the given tag contains a class attribute with the nocode class. */
  688. function isNoCodeTag(tag) {
  689. return !!tag
  690. // First canonicalize the representation of attributes
  691. .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
  692. ' $1="$2$3$4"')
  693. // Then look for the attribute we want.
  694. .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
  695. }
  696. /**
  697. * Apply the given language handler to sourceCode and add the resulting
  698. * decorations to out.
  699. * @param {number} basePos the index of sourceCode within the chunk of source
  700. * whose decorations are already present on out.
  701. */
  702. function appendDecorations(basePos, sourceCode, langHandler, out) {
  703. if (!sourceCode) { return; }
  704. var job = {
  705. source: sourceCode,
  706. basePos: basePos
  707. };
  708. langHandler(job);
  709. out.push.apply(out, job.decorations);
  710. }
  711. /** Given triples of [style, pattern, context] returns a lexing function,
  712. * The lexing function interprets the patterns to find token boundaries and
  713. * returns a decoration list of the form
  714. * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
  715. * where index_n is an index into the sourceCode, and style_n is a style
  716. * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to
  717. * all characters in sourceCode[index_n-1:index_n].
  718. *
  719. * The stylePatterns is a list whose elements have the form
  720. * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
  721. *
  722. * Style is a style constant like PR_PLAIN, or can be a string of the
  723. * form 'lang-FOO', where FOO is a language extension describing the
  724. * language of the portion of the token in $1 after pattern executes.
  725. * E.g., if style is 'lang-lisp', and group 1 contains the text
  726. * '(hello (world))', then that portion of the token will be passed to the
  727. * registered lisp handler for formatting.
  728. * The text before and after group 1 will be restyled using this decorator
  729. * so decorators should take care that this doesn't result in infinite
  730. * recursion. For example, the HTML lexer rule for SCRIPT elements looks
  731. * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match
  732. * '<script>foo()<\/script>', which would cause the current decorator to
  733. * be called with '<script>' which would not match the same rule since
  734. * group 1 must not be empty, so it would be instead styled as PR_TAG by
  735. * the generic tag rule. The handler registered for the 'js' extension would
  736. * then be called with 'foo()', and finally, the current decorator would
  737. * be called with '<\/script>' which would not match the original rule and
  738. * so the generic tag rule would identify it as a tag.
  739. *
  740. * Pattern must only match prefixes, and if it matches a prefix, then that
  741. * match is considered a token with the same style.
  742. *
  743. * Context is applied to the last non-whitespace, non-comment token
  744. * recognized.
  745. *
  746. * Shortcut is an optional string of characters, any of which, if the first
  747. * character, gurantee that this pattern and only this pattern matches.
  748. *
  749. * @param {Array} shortcutStylePatterns patterns that always start with
  750. * a known character. Must have a shortcut string.
  751. * @param {Array} fallthroughStylePatterns patterns that will be tried in
  752. * order if the shortcut ones fail. May have shortcuts.
  753. *
  754. * @return {function (Object)} a
  755. * function that takes source code and returns a list of decorations.
  756. */
  757. function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
  758. var shortcuts = {};
  759. var tokenizer;
  760. (function () {
  761. var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
  762. var allRegexs = [];
  763. var regexKeys = {};
  764. for (var i = 0, n = allPatterns.length; i < n; ++i) {
  765. var patternParts = allPatterns[i];
  766. var shortcutChars = patternParts[3];
  767. if (shortcutChars) {
  768. for (var c = shortcutChars.length; --c >= 0;) {
  769. shortcuts[shortcutChars.charAt(c)] = patternParts;
  770. }
  771. }
  772. var regex = patternParts[1];
  773. var k = '' + regex;
  774. if (!regexKeys.hasOwnProperty(k)) {
  775. allRegexs.push(regex);
  776. regexKeys[k] = null;
  777. }
  778. }
  779. allRegexs.push(/[\0-\uffff]/);
  780. tokenizer = combinePrefixPatterns(allRegexs);
  781. })();
  782. var nPatterns = fallthroughStylePatterns.length;
  783. var notWs = /\S/;
  784. /**
  785. * Lexes job.source and produces an output array job.decorations of style
  786. * classes preceded by the position at which they start in job.source in
  787. * order.
  788. *
  789. * @param {Object} job an object like {@code
  790. * source: {string} sourceText plain text,
  791. * basePos: {int} position of job.source in the larger chunk of
  792. * sourceCode.
  793. * }
  794. */
  795. var decorate = function (job) {
  796. var sourceCode = job.source, basePos = job.basePos;
  797. /** Even entries are positions in source in ascending order. Odd enties
  798. * are style markers (e.g., PR_COMMENT) that run from that position until
  799. * the end.
  800. * @type {Array.<number|string>}
  801. */
  802. var decorations = [basePos, PR_PLAIN];
  803. var pos = 0; // index into sourceCode
  804. var tokens = sourceCode.match(tokenizer) || [];
  805. var styleCache = {};
  806. for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
  807. var token = tokens[ti];
  808. var style = styleCache[token];
  809. var match = void 0;
  810. var isEmbedded;
  811. if (typeof style === 'string') {
  812. isEmbedded = false;
  813. } else {
  814. var patternParts = shortcuts[token.charAt(0)];
  815. if (patternParts) {
  816. match = token.match(patternParts[1]);
  817. style = patternParts[0];
  818. } else {
  819. for (var i = 0; i < nPatterns; ++i) {
  820. patternParts = fallthroughStylePatterns[i];
  821. match = token.match(patternParts[1]);
  822. if (match) {
  823. style = patternParts[0];
  824. break;
  825. }
  826. }
  827. if (!match) { // make sure that we make progress
  828. style = PR_PLAIN;
  829. }
  830. }
  831. isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
  832. if (isEmbedded && !(match && typeof match[1] === 'string')) {
  833. isEmbedded = false;
  834. style = PR_SOURCE;
  835. }
  836. if (!isEmbedded) { styleCache[token] = style; }
  837. }
  838. var tokenStart = pos;
  839. pos += token.length;
  840. if (!isEmbedded) {
  841. decorations.push(basePos + tokenStart, style);
  842. } else { // Treat group 1 as an embedded block of source code.
  843. var embeddedSource = match[1];
  844. var embeddedSourceStart = token.indexOf(embeddedSource);
  845. var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
  846. if (match[2]) {
  847. // If embeddedSource can be blank, then it would match at the
  848. // beginning which would cause us to infinitely recurse on the
  849. // entire token, so we catch the right context in match[2].
  850. embeddedSourceEnd = token.length - match[2].length;
  851. embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
  852. }
  853. var lang = style.substring(5);
  854. // Decorate the left of the embedded source
  855. appendDecorations(
  856. basePos + tokenStart,
  857. token.substring(0, embeddedSourceStart),
  858. decorate, decorations);
  859. // Decorate the embedded source
  860. appendDecorations(
  861. basePos + tokenStart + embeddedSourceStart,
  862. embeddedSource,
  863. langHandlerForExtension(lang, embeddedSource),
  864. decorations);
  865. // Decorate the right of the embedded section
  866. appendDecorations(
  867. basePos + tokenStart + embeddedSourceEnd,
  868. token.substring(embeddedSourceEnd),
  869. decorate, decorations);
  870. }
  871. }
  872. job.decorations = decorations;
  873. };
  874. return decorate;
  875. }
  876. /** returns a function that produces a list of decorations from source text.
  877. *
  878. * This code treats ", ', and ` as string delimiters, and \ as a string
  879. * escape. It does not recognize perl's qq() style strings.
  880. * It has no special handling for double delimiter escapes as in basic, or
  881. * the tripled delimiters used in python, but should work on those regardless
  882. * although in those cases a single string literal may be broken up into
  883. * multiple adjacent string literals.
  884. *
  885. * It recognizes C, C++, and shell style comments.
  886. *
  887. * @param {Object} options a set of optional parameters.
  888. * @return {function (Object)} a function that examines the source code
  889. * in the input job and builds the decoration list.
  890. */
  891. function sourceDecorator(options) {
  892. var shortcutStylePatterns = [], fallthroughStylePatterns = [];
  893. if (options['tripleQuotedStrings']) {
  894. // '''multi-line-string''', 'single-line-string', and double-quoted
  895. shortcutStylePatterns.push(
  896. [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
  897. null, '\'"']);
  898. } else if (options['multiLineStrings']) {
  899. // 'multi-line-string', "multi-line-string"
  900. shortcutStylePatterns.push(
  901. [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
  902. null, '\'"`']);
  903. } else {
  904. // 'single-line-string', "single-line-string"
  905. shortcutStylePatterns.push(
  906. [PR_STRING,
  907. /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
  908. null, '"\'']);
  909. }
  910. if (options['verbatimStrings']) {
  911. // verbatim-string-literal production from the C# grammar. See issue 93.
  912. fallthroughStylePatterns.push(
  913. [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
  914. }
  915. if (options['hashComments']) {
  916. if (options['cStyleComments']) {
  917. // Stop C preprocessor declarations at an unclosed open comment
  918. shortcutStylePatterns.push(
  919. [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
  920. null, '#']);
  921. fallthroughStylePatterns.push(
  922. [PR_STRING,
  923. /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
  924. null]);
  925. } else {
  926. shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
  927. }
  928. }
  929. if (options['cStyleComments']) {
  930. fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
  931. fallthroughStylePatterns.push(
  932. [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
  933. }
  934. if (options['regexLiterals']) {
  935. var REGEX_LITERAL = (
  936. // A regular expression literal starts with a slash that is
  937. // not followed by * or / so that it is not confused with
  938. // comments.
  939. '/(?=[^/*])'
  940. // and then contains any number of raw characters,
  941. + '(?:[^/\\x5B\\x5C]'
  942. // escape sequences (\x5C),
  943. + '|\\x5C[\\s\\S]'
  944. // or non-nesting character sets (\x5B\x5D);
  945. + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
  946. // finally closed by a /.
  947. + '/');
  948. fallthroughStylePatterns.push(
  949. ['lang-regex',
  950. new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
  951. ]);
  952. }
  953. var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
  954. if (keywords.length) {
  955. fallthroughStylePatterns.push(
  956. [PR_KEYWORD,
  957. new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
  958. }
  959. shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']);
  960. fallthroughStylePatterns.push(
  961. // TODO(mikesamuel): recognize non-latin letters and numerals in idents
  962. [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null],
  963. [PR_TYPE, /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
  964. [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null],
  965. [PR_LITERAL,
  966. new RegExp(
  967. '^(?:'
  968. // A hex number
  969. + '0x[a-f0-9]+'
  970. // or an octal or decimal number,
  971. + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
  972. // possibly in scientific notation
  973. + '(?:e[+\\-]?\\d+)?'
  974. + ')'
  975. // with an optional modifier like UL for unsigned long
  976. + '[a-z]*', 'i'),
  977. null, '0123456789'],
  978. [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
  979. return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
  980. }
  981. var decorateSource = sourceDecorator({
  982. 'keywords': ALL_KEYWORDS,
  983. 'hashComments': true,
  984. 'cStyleComments': true,
  985. 'multiLineStrings': true,
  986. 'regexLiterals': true
  987. });
  988. /** Breaks {@code job.source} around style boundaries in
  989. * {@code job.decorations} while re-interleaving {@code job.extractedTags},
  990. * and leaves the result in {@code job.prettyPrintedHtml}.
  991. * @param {Object} job like {
  992. * source: {string} source as plain text,
  993. * extractedTags: {Array.<number|string>} extractedTags chunks of raw
  994. * html preceded by their position in {@code job.source}
  995. * in order
  996. * decorations: {Array.<number|string} an array of style classes preceded
  997. * by the position at which they start in job.source in order
  998. * }
  999. * @private
  1000. */
  1001. function recombineTagsAndDecorations(job) {
  1002. var sourceText = job.source;
  1003. var extractedTags = job.extractedTags;
  1004. var decorations = job.decorations;
  1005. var html = [];
  1006. // index past the last char in sourceText written to html
  1007. var outputIdx = 0;
  1008. var openDecoration = null;
  1009. var currentDecoration = null;
  1010. var tagPos = 0; // index into extractedTags
  1011. var decPos = 0; // index into decorations
  1012. var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
  1013. var adjacentSpaceRe = /([\r\n ]) /g;
  1014. var startOrSpaceRe = /(^| ) /gm;
  1015. var newlineRe = /\r\n?|\n/g;
  1016. var trailingSpaceRe = /[ \r\n]$/;
  1017. var lastWasSpace = true; // the last text chunk emitted ended with a space.
  1018. // A helper function that is responsible for opening sections of decoration
  1019. // and outputing properly escaped chunks of source
  1020. function emitTextUpTo(sourceIdx) {
  1021. if (sourceIdx > outputIdx) {
  1022. if (openDecoration && openDecoration !== currentDecoration) {
  1023. // Close the current decoration
  1024. html.push('</span>');
  1025. openDecoration = null;
  1026. }
  1027. if (!openDecoration && currentDecoration) {
  1028. openDecoration = currentDecoration;
  1029. html.push('<span class="', openDecoration, '">');
  1030. }
  1031. // This interacts badly with some wikis which introduces paragraph tags
  1032. // into pre blocks for some strange reason.
  1033. // It's necessary for IE though which seems to lose the preformattedness
  1034. // of <pre> tags when their innerHTML is assigned.
  1035. // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
  1036. // and it serves to undo the conversion of <br>s to newlines done in
  1037. // chunkify.
  1038. var htmlChunk = textToHtml(
  1039. tabExpander(sourceText.substring(outputIdx, sourceIdx)))
  1040. .replace(lastWasSpace
  1041. ? startOrSpaceRe
  1042. : adjacentSpaceRe, '$1&nbsp;');
  1043. // Keep track of whether we need to escape space at the beginning of the
  1044. // next chunk.
  1045. lastWasSpace = trailingSpaceRe.test(htmlChunk);
  1046. // IE collapses multiple adjacient <br>s into 1 line break.
  1047. // Prefix every <br> with '&nbsp;' can prevent such IE's behavior.
  1048. var lineBreakHtml = window['_pr_isIE6']() ? '&nbsp;<br />' : '<br />';
  1049. html.push(htmlChunk.replace(newlineRe, lineBreakHtml));
  1050. outputIdx = sourceIdx;
  1051. }
  1052. }
  1053. while (true) {
  1054. // Determine if we're going to consume a tag this time around. Otherwise
  1055. // we consume a decoration or exit.
  1056. var outputTag;
  1057. if (tagPos < extractedTags.length) {
  1058. if (decPos < decorations.length) {
  1059. // Pick one giving preference to extractedTags since we shouldn't open
  1060. // a new style that we're going to have to immediately close in order
  1061. // to output a tag.
  1062. outputTag = extractedTags[tagPos] <= decorations[decPos];
  1063. } else {
  1064. outputTag = true;
  1065. }
  1066. } else {
  1067. outputTag = false;
  1068. }
  1069. // Consume either a decoration or a tag or exit.
  1070. if (outputTag) {
  1071. emitTextUpTo(extractedTags[tagPos]);
  1072. if (openDecoration) {
  1073. // Close the current decoration
  1074. html.push('</span>');
  1075. openDecoration = null;
  1076. }
  1077. html.push(extractedTags[tagPos + 1]);
  1078. tagPos += 2;
  1079. } else if (decPos < decorations.length) {
  1080. emitTextUpTo(decorations[decPos]);
  1081. currentDecoration = decorations[decPos + 1];
  1082. decPos += 2;
  1083. } else {
  1084. break;
  1085. }
  1086. }
  1087. emitTextUpTo(sourceText.length);
  1088. if (openDecoration) {
  1089. html.push('</span>');
  1090. }
  1091. job.prettyPrintedHtml = html.join('');
  1092. }
  1093. /** Maps language-specific file extensions to handlers. */
  1094. var langHandlerRegistry = {};
  1095. /** Register a language handler for the given file extensions.
  1096. * @param {function (Object)} handler a function from source code to a list
  1097. * of decorations. Takes a single argument job which describes the
  1098. * state of the computation. The single parameter has the form
  1099. * {@code {
  1100. * source: {string} as plain text.
  1101. * decorations: {Array.<number|string>} an array of style classes
  1102. * preceded by the position at which they start in
  1103. * job.source in order.
  1104. * The language handler should assigned this field.
  1105. * basePos: {int} the position of source in the larger source chunk.
  1106. * All positions in the output decorations array are relative
  1107. * to the larger source chunk.
  1108. * } }
  1109. * @param {Array.<string>} fileExtensions
  1110. */
  1111. function registerLangHandler(handler, fileExtensions) {
  1112. for (var i = fileExtensions.length; --i >= 0;) {
  1113. var ext = fileExtensions[i];
  1114. if (!langHandlerRegistry.hasOwnProperty(ext)) {
  1115. langHandlerRegistry[ext] = handler;
  1116. } else if ('console' in window) {
  1117. console.warn('cannot override language handler %s', ext);
  1118. }
  1119. }
  1120. }
  1121. function langHandlerForExtension(extension, source) {
  1122. if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
  1123. // Treat it as markup if the first non whitespace character is a < and
  1124. // the last non-whitespace character is a >.
  1125. extension = /^\s*</.test(source)
  1126. ? 'default-markup'
  1127. : 'default-code';
  1128. }
  1129. return langHandlerRegistry[extension];
  1130. }
  1131. registerLangHandler(decorateSource, ['default-code']);
  1132. registerLangHandler(
  1133. createSimpleLexer(
  1134. [],
  1135. [
  1136. [PR_PLAIN, /^[^<?]+/],
  1137. [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
  1138. [PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/],
  1139. // Unescaped content in an unknown language
  1140. ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/],
  1141. ['lang-', /^<%([\s\S]+?)(?:%>|$)/],
  1142. [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
  1143. ['lang-', /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
  1144. // Unescaped content in javascript. (Or possibly vbscript).
  1145. ['lang-js', /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
  1146. // Contains unescaped stylesheet content
  1147. ['lang-css', /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
  1148. ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]
  1149. ]),
  1150. ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
  1151. registerLangHandler(
  1152. createSimpleLexer(
  1153. [
  1154. [PR_PLAIN, /^[\s]+/, null, ' \t\r\n'],
  1155. [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
  1156. ],
  1157. [
  1158. [PR_TAG, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
  1159. [PR_ATTRIB_NAME, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
  1160. ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
  1161. [PR_PUNCTUATION, /^[=<>\/]+/],
  1162. ['lang-js', /^on\w+\s*=\s*\"([^\"]+)\"/i],
  1163. ['lang-js', /^on\w+\s*=\s*\'([^\']+)\'/i],
  1164. ['lang-js', /^on\w+\s*=\s*([^\"\'>\s]+)/i],
  1165. ['lang-css', /^style\s*=\s*\"([^\"]+)\"/i],
  1166. ['lang-css', /^style\s*=\s*\'([^\']+)\'/i],
  1167. ['lang-css', /^style\s*=\s*([^\"\'>\s]+)/i]
  1168. ]),
  1169. ['in.tag']);
  1170. registerLangHandler(
  1171. createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
  1172. registerLangHandler(sourceDecorator({
  1173. 'keywords': CPP_KEYWORDS,
  1174. 'hashComments': true,
  1175. 'cStyleComments': true
  1176. }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
  1177. registerLangHandler(sourceDecorator({
  1178. 'keywords': 'null true false'
  1179. }), ['json']);
  1180. registerLangHandler(sourceDecorator({
  1181. 'keywords': CSHARP_KEYWORDS,
  1182. 'hashComments': true,
  1183. 'cStyleComments': true,
  1184. 'verbatimStrings': true
  1185. }), ['cs']);
  1186. registerLangHandler(sourceDecorator({
  1187. 'keywords': JAVA_KEYWORDS,
  1188. 'cStyleComments': true
  1189. }), ['java']);
  1190. registerLangHandler(sourceDecorator({
  1191. 'keywords': SH_KEYWORDS,
  1192. 'hashComments': true,
  1193. 'multiLineStrings': true
  1194. }), ['bsh', 'csh', 'sh']);
  1195. registerLangHandler(sourceDecorator({
  1196. 'keywords': PYTHON_KEYWORDS,
  1197. 'hashComments': true,
  1198. 'multiLineStrings': true,
  1199. 'tripleQuotedStrings': true
  1200. }), ['cv', 'py']);
  1201. registerLangHandler(sourceDecorator({
  1202. 'keywords': PERL_KEYWORDS,
  1203. 'hashComments': true,
  1204. 'multiLineStrings': true,
  1205. 'regexLiterals': true
  1206. }), ['perl', 'pl', 'pm']);
  1207. registerLangHandler(sourceDecorator({
  1208. 'keywords': RUBY_KEYWORDS,
  1209. 'hashComments': true,
  1210. 'multiLineStrings': true,
  1211. 'regexLiterals': true
  1212. }), ['rb']);
  1213. registerLangHandler(sourceDecorator({
  1214. 'keywords': JSCRIPT_KEYWORDS,
  1215. 'cStyleComments': true,
  1216. 'regexLiterals': true
  1217. }), ['js']);
  1218. registerLangHandler(
  1219. createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
  1220. function applyDecorator(job) {
  1221. var sourceCodeHtml = job.sourceCodeHtml;
  1222. var opt_langExtension = job.langExtension;
  1223. // Prepopulate output in case processing fails with an exception.
  1224. job.prettyPrintedHtml = sourceCodeHtml;
  1225. try {
  1226. // Extract tags, and convert the source code to plain text.
  1227. var sourceAndExtractedTags = extractTags(sourceCodeHtml);
  1228. /** Plain text. @type {string} */
  1229. var source = sourceAndExtractedTags.source;
  1230. job.source = source;
  1231. job.basePos = 0;
  1232. /** Even entries are positions in source in ascending order. Odd entries
  1233. * are tags that were extracted at that position.
  1234. * @type {Array.<number|string>}
  1235. */
  1236. job.extractedTags = sourceAndExtractedTags.tags;
  1237. // Apply the appropriate language handler
  1238. langHandlerForExtension(opt_langExtension, source)(job);
  1239. // Integrate the decorations and tags back into the source code to produce
  1240. // a decorated html string which is left in job.prettyPrintedHtml.
  1241. recombineTagsAndDecorations(job);
  1242. } catch (e) {
  1243. if ('console' in window) {
  1244. console.log(e);
  1245. console.trace();
  1246. }
  1247. }
  1248. }
  1249. function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
  1250. var job = {
  1251. sourceCodeHtml: sourceCodeHtml,
  1252. langExtension: opt_langExtension
  1253. };
  1254. applyDecorator(job);
  1255. return job.prettyPrintedHtml;
  1256. }
  1257. function prettyPrint(opt_whenDone) {
  1258. var isIE678 = window['_pr_isIE6']();
  1259. var ieNewline = isIE678 === 6 ? '\r\n' : '\r';
  1260. // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
  1261. // fetch a list of nodes to rewrite
  1262. var codeSegments = [
  1263. document.getElementsByTagName('pre'),
  1264. document.getElementsByTagName('code'),
  1265. document.getElementsByTagName('td'), /* ND Change: Add tables to support prototypes. */
  1266. document.getElementsByTagName('xmp') ];
  1267. var elements = [];
  1268. for (var i = 0; i < codeSegments.length; ++i) {
  1269. for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
  1270. elements.push(codeSegments[i][j]);
  1271. }
  1272. }
  1273. codeSegments = null;
  1274. var clock = Date;
  1275. if (!clock['now']) {
  1276. clock = { 'now': function () { return (new Date).getTime(); } };
  1277. }
  1278. // The loop is broken into a series of continuations to make sure that we
  1279. // don't make the browser unresponsive when rewriting a large page.
  1280. var k = 0;
  1281. var prettyPrintingJob;
  1282. function doWork() {
  1283. var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
  1284. clock.now() + 250 /* ms */ :
  1285. Infinity);
  1286. for (; k < elements.length && clock.now() < endTime; k++) {
  1287. var cs = elements[k];
  1288. if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
  1289. // If the classes includes a language extensions, use it.
  1290. // Language extensions can be specified like
  1291. // <pre class="prettyprint lang-cpp">
  1292. // the language extension "cpp" is used to find a language handler as
  1293. // passed to PR_registerLangHandler.
  1294. var langExtension = cs.className.match(/\blang-(\w+)\b/);
  1295. if (langExtension) { langExtension = langExtension[1]; }
  1296. // make sure this is not nested in an already prettified element
  1297. var nested = false;
  1298. for (var p = cs.parentNode; p; p = p.parentNode) {
  1299. if ((p.tagName === 'pre' || p.tagName === 'code' ||
  1300. p.tagName === 'xmp' || p.tagName === 'td') && /* ND Change: Add tables to support prototypes */
  1301. p.className && p.className.indexOf('prettyprint') >= 0) {
  1302. nested = true;
  1303. break;
  1304. }
  1305. }
  1306. if (!nested) {
  1307. // fetch the content as a snippet of properly escaped HTML.
  1308. // Firefox adds newlines at the end.
  1309. var content = getInnerHtml(cs);
  1310. content = content.replace(/(?:\r\n?|\n)$/, '');
  1311. /* ND Change: we need to preserve &nbsp;s so change them to a special character instead of a space. */
  1312. content = content.replace(/&nbsp;/g, '\x11');
  1313. // do the pretty printing
  1314. prettyPrintingJob = {
  1315. sourceCodeHtml: content,
  1316. langExtension: langExtension,
  1317. sourceNode: cs
  1318. };
  1319. applyDecorator(prettyPrintingJob);
  1320. replaceWithPrettyPrintedHtml();
  1321. }
  1322. }
  1323. }
  1324. if (k < elements.length) {
  1325. // finish up in a continuation
  1326. setTimeout(doWork, 250);
  1327. } else if (opt_whenDone) {
  1328. opt_whenDone();
  1329. }
  1330. }
  1331. function replaceWithPrettyPrintedHtml() {
  1332. var newContent = prettyPrintingJob.prettyPrintedHtml;
  1333. if (!newContent) { return; }
  1334. /* ND Change: Restore the preserved &nbsp;s. */
  1335. newContent = newContent.replace(/\x11/g, '&nbsp;');
  1336. var cs = prettyPrintingJob.sourceNode;
  1337. // push the prettified html back into the tag.
  1338. if (!isRawContent(cs)) {
  1339. // just replace the old html with the new
  1340. cs.innerHTML = newContent;
  1341. } else {
  1342. // we need to change the tag to a <pre> since <xmp>s do not allow
  1343. // embedded tags such as the span tags used to attach styles to
  1344. // sections of source code.
  1345. var pre = document.createElement('PRE');
  1346. for (var i = 0; i < cs.attributes.length; ++i) {
  1347. var a = cs.attributes[i];
  1348. if (a.specified) {
  1349. var aname = a.name.toLowerCase();
  1350. if (aname === 'class') {
  1351. pre.className = a.value; // For IE 6
  1352. } else {
  1353. pre.setAttribute(a.name, a.value);
  1354. }
  1355. }
  1356. }
  1357. pre.innerHTML = newContent;
  1358. // remove the old
  1359. cs.parentNode.replaceChild(pre, cs);
  1360. cs = pre;
  1361. }
  1362. // Replace <br>s with line-feeds so that copying and pasting works
  1363. // on IE 6.
  1364. // Doing this on other browsers breaks lots of stuff since \r\n is
  1365. // treated as two newlines on Firefox, and doing this also slows
  1366. // down rendering.
  1367. if (isIE678 && cs.tagName === 'PRE') {
  1368. var lineBreaks = cs.getElementsByTagName('br');
  1369. for (var j = lineBreaks.length; --j >= 0;) {
  1370. var lineBreak = lineBreaks[j];
  1371. lineBreak.parentNode.replaceChild(
  1372. document.createTextNode(ieNewline), lineBreak);
  1373. }
  1374. }
  1375. }
  1376. doWork();
  1377. }
  1378. window['PR_normalizedHtml'] = normalizedHtml;
  1379. window['prettyPrintOne'] = prettyPrintOne;
  1380. window['prettyPrint'] = prettyPrint;
  1381. window['PR'] = {
  1382. 'combinePrefixPatterns': combinePrefixPatterns,
  1383. 'createSimpleLexer': createSimpleLexer,
  1384. 'registerLangHandler': registerLangHandler,
  1385. 'sourceDecorator': sourceDecorator,
  1386. 'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
  1387. 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
  1388. 'PR_COMMENT': PR_COMMENT,
  1389. 'PR_DECLARATION': PR_DECLARATION,
  1390. 'PR_KEYWORD': PR_KEYWORD,
  1391. 'PR_LITERAL': PR_LITERAL,
  1392. 'PR_NOCODE': PR_NOCODE,
  1393. 'PR_PLAIN': PR_PLAIN,
  1394. 'PR_PUNCTUATION': PR_PUNCTUATION,
  1395. 'PR_SOURCE': PR_SOURCE,
  1396. 'PR_STRING': PR_STRING,
  1397. 'PR_TAG': PR_TAG,
  1398. 'PR_TYPE': PR_TYPE
  1399. };
  1400. })();
  1401. // ____________________________________________________________________________
  1402. // Lua extension
  1403. PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,' \n\r \xa0'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],[PR.PR_STRING,/^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],[PR.PR_KEYWORD,/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_]\w*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]]),['lua'])
  1404. // Haskell extension
  1405. PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\x0B\x0C\r ]+/,null,' \n \r '],[PR.PR_STRING,/^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,null,'\"'],[PR.PR_STRING,/^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,null,'\''],[PR.PR_LITERAL,/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,null,'0123456789']],[[PR.PR_COMMENT,/^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],[PR.PR_KEYWORD,/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/,null],[PR.PR_PLAIN,/^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],[PR.PR_PUNCTUATION,/^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]]),['hs'])
  1406. // ML extension
  1407. PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,' \n\r \xa0'],[PR.PR_COMMENT,/^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,null,'#'],[PR.PR_STRING,/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],[PR.PR_KEYWORD,/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],[PR.PR_LITERAL,/^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^(?:[a-z_]\w*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],[PR.PR_PUNCTUATION,/^[^\t\n\r \xA0\"\'\w]+/]]),['fs','ml'])
  1408. // SQL extension
  1409. PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0]+/,null,' \n\r \xa0'],[PR.PR_STRING,/^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/,null,'\"\'']],[[PR.PR_COMMENT,/^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],[PR.PR_KEYWORD,/^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i,null],[PR.PR_LITERAL,/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],[PR.PR_PLAIN,/^[a-z_][\w-]*/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]]),['sql'])
  1410. // VB extension
  1411. PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[\t\n\r \xA0\u2028\u2029]+/,null,' \n\r \xa0\u2028\u2029'],[PR.PR_STRING,/^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i,null,'\"\u201c\u201d'],[PR.PR_COMMENT,/^[\'\u2018\u2019][^\r\n\u2028\u2029]*/,null,'\'\u2018\u2019']],[[PR.PR_KEYWORD,/^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i,null],[PR.PR_COMMENT,/^REM[^\r\n\u2028\u2029]*/i],[PR.PR_LITERAL,/^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],[PR.PR_PLAIN,/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],[PR.PR_PUNCTUATION,/^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],[PR.PR_PUNCTUATION,/^(?:\[|\])/]]),['vb','vbs'])