prettify.js 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. // Copyright (C) 2006 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview
  16. * some functions for browser-side pretty printing of code contained in html.
  17. *
  18. * <p>
  19. * For a fairly comprehensive set of languages see the
  20. * <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs">README</a>
  21. * file that came with this source. At a minimum, the lexer should work on a
  22. * number of languages including C and friends, Java, Python, Bash, SQL, HTML,
  23. * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk
  24. * and a subset of Perl, but, because of commenting conventions, doesn't work on
  25. * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.
  26. * <p>
  27. * Usage: <ol>
  28. * <li> include this source file in an html page via
  29. * {@code <script type="text/javascript" src="/path/to/prettify.js"></script>}
  30. * <li> define style rules. See the example page for examples.
  31. * <li> mark the {@code <pre>} and {@code <code>} tags in your source with
  32. * {@code class=prettyprint.}
  33. * You can also use the (html deprecated) {@code <xmp>} tag, but the pretty
  34. * printer needs to do more substantial DOM manipulations to support that, so
  35. * some css styles may not be preserved.
  36. * </ol>
  37. * That's it. I wanted to keep the API as simple as possible, so there's no
  38. * need to specify which language the code is in, but if you wish, you can add
  39. * another class to the {@code <pre>} or {@code <code>} element to specify the
  40. * language, as in {@code <pre class="prettyprint lang-java">}. Any class that
  41. * starts with "lang-" followed by a file extension, specifies the file type.
  42. * See the "lang-*.js" files in this directory for code that implements
  43. * per-language file handlers.
  44. * <p>
  45. * Change log:<br>
  46. * cbeust, 2006/08/22
  47. * <blockquote>
  48. * Java annotations (start with "@") are now captured as literals ("lit")
  49. * </blockquote>
  50. * @requires console
  51. */
  52. // JSLint declarations
  53. /*global console, document, navigator, setTimeout, window, define */
  54. /** @define {boolean} */
  55. var IN_GLOBAL_SCOPE = true;
  56. /**
  57. * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
  58. * UI events.
  59. * If set to {@code false}, {@code prettyPrint()} is synchronous.
  60. */
  61. window['PR_SHOULD_USE_CONTINUATION'] = true;
  62. /**
  63. * Pretty print a chunk of code.
  64. * @param {string} sourceCodeHtml The HTML to pretty print.
  65. * @param {string} opt_langExtension The language name to use.
  66. * Typically, a filename extension like 'cpp' or 'java'.
  67. * @param {number|boolean} opt_numberLines True to number lines,
  68. * or the 1-indexed number of the first line in sourceCodeHtml.
  69. * @return {string} code as html, but prettier
  70. */
  71. var prettyPrintOne;
  72. /**
  73. * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
  74. * {@code class=prettyprint} and prettify them.
  75. *
  76. * @param {Function} opt_whenDone called when prettifying is done.
  77. * @param {HTMLElement|HTMLDocument} opt_root an element or document
  78. * containing all the elements to pretty print.
  79. * Defaults to {@code document.body}.
  80. */
  81. var prettyPrint;
  82. (function () {
  83. var win = window;
  84. // Keyword lists for various languages.
  85. // We use things that coerce to strings to make them compact when minified
  86. // and to defeat aggressive optimizers that fold large string constants.
  87. var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"];
  88. var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," +
  89. "double,enum,extern,float,goto,inline,int,long,register,short,signed," +
  90. "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];
  91. var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," +
  92. "new,operator,private,protected,public,this,throw,true,try,typeof"];
  93. var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool," +
  94. "concept,concept_map,const_cast,constexpr,decltype,delegate," +
  95. "dynamic_cast,explicit,export,friend,generic,late_check," +
  96. "mutable,namespace,nullptr,property,reinterpret_cast,static_assert," +
  97. "static_cast,template,typeid,typename,using,virtual,where"];
  98. var JAVA_KEYWORDS = [COMMON_KEYWORDS,
  99. "abstract,assert,boolean,byte,extends,final,finally,implements,import," +
  100. "instanceof,interface,null,native,package,strictfp,super,synchronized," +
  101. "throws,transient"];
  102. var CSHARP_KEYWORDS = [JAVA_KEYWORDS,
  103. "as,base,by,checked,decimal,delegate,descending,dynamic,event," +
  104. "fixed,foreach,from,group,implicit,in,internal,into,is,let," +
  105. "lock,object,out,override,orderby,params,partial,readonly,ref,sbyte," +
  106. "sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort," +
  107. "var,virtual,where"];
  108. var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," +
  109. "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," +
  110. "throw,true,try,unless,until,when,while,yes";
  111. var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,
  112. "debugger,eval,export,function,get,null,set,undefined,var,with," +
  113. "Infinity,NaN"];
  114. var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +
  115. "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +
  116. "sub,undef,unless,until,use,wantarray,while,BEGIN,END";
  117. var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "and,as,assert,class,def,del," +
  118. "elif,except,exec,finally,from,global,import,in,is,lambda," +
  119. "nonlocal,not,or,pass,print,raise,try,with,yield," +
  120. "False,True,None"];
  121. var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," +
  122. "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," +
  123. "rescue,retry,self,super,then,true,undef,unless,until,when,yield," +
  124. "BEGIN,END"];
  125. var RUST_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "as,assert,const,copy,drop," +
  126. "enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv," +
  127. "pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"];
  128. var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," +
  129. "function,in,local,set,then,until"];
  130. var ALL_KEYWORDS = [
  131. CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS,
  132. PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];
  133. var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;
  134. // token style names. correspond to css classes
  135. /**
  136. * token style for a string literal
  137. * @const
  138. */
  139. var PR_STRING = 'str';
  140. /**
  141. * token style for a keyword
  142. * @const
  143. */
  144. var PR_KEYWORD = 'kwd';
  145. /**
  146. * token style for a comment
  147. * @const
  148. */
  149. var PR_COMMENT = 'com';
  150. /**
  151. * token style for a type
  152. * @const
  153. */
  154. var PR_TYPE = 'typ';
  155. /**
  156. * token style for a literal value. e.g. 1, null, true.
  157. * @const
  158. */
  159. var PR_LITERAL = 'lit';
  160. /**
  161. * token style for a punctuation string.
  162. * @const
  163. */
  164. var PR_PUNCTUATION = 'pun';
  165. /**
  166. * token style for plain text.
  167. * @const
  168. */
  169. var PR_PLAIN = 'pln';
  170. /**
  171. * token style for an sgml tag.
  172. * @const
  173. */
  174. var PR_TAG = 'tag';
  175. /**
  176. * token style for a markup declaration such as a DOCTYPE.
  177. * @const
  178. */
  179. var PR_DECLARATION = 'dec';
  180. /**
  181. * token style for embedded source.
  182. * @const
  183. */
  184. var PR_SOURCE = 'src';
  185. /**
  186. * token style for an sgml attribute name.
  187. * @const
  188. */
  189. var PR_ATTRIB_NAME = 'atn';
  190. /**
  191. * token style for an sgml attribute value.
  192. * @const
  193. */
  194. var PR_ATTRIB_VALUE = 'atv';
  195. /**
  196. * A class that indicates a section of markup that is not code, e.g. to allow
  197. * embedding of line numbers within code listings.
  198. * @const
  199. */
  200. var PR_NOCODE = 'nocode';
  201. /**
  202. * A set of tokens that can precede a regular expression literal in
  203. * javascript
  204. * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html
  205. * has the full list, but I've removed ones that might be problematic when
  206. * seen in languages that don't support regular expression literals.
  207. *
  208. * <p>Specifically, I've removed any keywords that can't precede a regexp
  209. * literal in a syntactically legal javascript program, and I've removed the
  210. * "in" keyword since it's not a keyword in many languages, and might be used
  211. * as a count of inches.
  212. *
  213. * <p>The link above does not accurately describe EcmaScript rules since
  214. * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
  215. * very well in practice.
  216. *
  217. * @private
  218. * @const
  219. */
  220. var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*';
  221. // CAVEAT: this does not properly handle the case where a regular
  222. // expression immediately follows another since a regular expression may
  223. // have flags for case-sensitivity and the like. Having regexp tokens
  224. // adjacent is not valid in any language I'm aware of, so I'm punting.
  225. // TODO: maybe style special characters inside a regexp as punctuation.
  226. /**
  227. * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
  228. * matches the union of the sets of strings matched by the input RegExp.
  229. * Since it matches globally, if the input strings have a start-of-input
  230. * anchor (/^.../), it is ignored for the purposes of unioning.
  231. * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
  232. * @return {RegExp} a global regex.
  233. */
  234. function combinePrefixPatterns(regexs) {
  235. var capturedGroupIndex = 0;
  236. var needToFoldCase = false;
  237. var ignoreCase = false;
  238. for (var i = 0, n = regexs.length; i < n; ++i) {
  239. var regex = regexs[i];
  240. if (regex.ignoreCase) {
  241. ignoreCase = true;
  242. } else if (/[a-z]/i.test(regex.source.replace(
  243. /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
  244. needToFoldCase = true;
  245. ignoreCase = false;
  246. break;
  247. }
  248. }
  249. var escapeCharToCodeUnit = {
  250. 'b': 8,
  251. 't': 9,
  252. 'n': 0xa,
  253. 'v': 0xb,
  254. 'f': 0xc,
  255. 'r': 0xd
  256. };
  257. function decodeEscape(charsetPart) {
  258. var cc0 = charsetPart.charCodeAt(0);
  259. if (cc0 !== 92 /* \\ */) {
  260. return cc0;
  261. }
  262. var c1 = charsetPart.charAt(1);
  263. cc0 = escapeCharToCodeUnit[c1];
  264. if (cc0) {
  265. return cc0;
  266. } else if ('0' <= c1 && c1 <= '7') {
  267. return parseInt(charsetPart.substring(1), 8);
  268. } else if (c1 === 'u' || c1 === 'x') {
  269. return parseInt(charsetPart.substring(2), 16);
  270. } else {
  271. return charsetPart.charCodeAt(1);
  272. }
  273. }
  274. function encodeEscape(charCode) {
  275. if (charCode < 0x20) {
  276. return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
  277. }
  278. var ch = String.fromCharCode(charCode);
  279. return (ch === '\\' || ch === '-' || ch === ']' || ch === '^')
  280. ? "\\" + ch : ch;
  281. }
  282. function caseFoldCharset(charSet) {
  283. var charsetParts = charSet.substring(1, charSet.length - 1).match(
  284. new RegExp(
  285. '\\\\u[0-9A-Fa-f]{4}'
  286. + '|\\\\x[0-9A-Fa-f]{2}'
  287. + '|\\\\[0-3][0-7]{0,2}'
  288. + '|\\\\[0-7]{1,2}'
  289. + '|\\\\[\\s\\S]'
  290. + '|-'
  291. + '|[^-\\\\]',
  292. 'g'));
  293. var ranges = [];
  294. var inverse = charsetParts[0] === '^';
  295. var out = ['['];
  296. if (inverse) { out.push('^'); }
  297. for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
  298. var p = charsetParts[i];
  299. if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups.
  300. out.push(p);
  301. } else {
  302. var start = decodeEscape(p);
  303. var end;
  304. if (i + 2 < n && '-' === charsetParts[i + 1]) {
  305. end = decodeEscape(charsetParts[i + 2]);
  306. i += 2;
  307. } else {
  308. end = start;
  309. }
  310. ranges.push([start, end]);
  311. // If the range might intersect letters, then expand it.
  312. // This case handling is too simplistic.
  313. // It does not deal with non-latin case folding.
  314. // It works for latin source code identifiers though.
  315. if (!(end < 65 || start > 122)) {
  316. if (!(end < 65 || start > 90)) {
  317. ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
  318. }
  319. if (!(end < 97 || start > 122)) {
  320. ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
  321. }
  322. }
  323. }
  324. }
  325. // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
  326. // -> [[1, 12], [14, 14], [16, 17]]
  327. ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); });
  328. var consolidatedRanges = [];
  329. var lastRange = [];
  330. for (var i = 0; i < ranges.length; ++i) {
  331. var range = ranges[i];
  332. if (range[0] <= lastRange[1] + 1) {
  333. lastRange[1] = Math.max(lastRange[1], range[1]);
  334. } else {
  335. consolidatedRanges.push(lastRange = range);
  336. }
  337. }
  338. for (var i = 0; i < consolidatedRanges.length; ++i) {
  339. var range = consolidatedRanges[i];
  340. out.push(encodeEscape(range[0]));
  341. if (range[1] > range[0]) {
  342. if (range[1] + 1 > range[0]) { out.push('-'); }
  343. out.push(encodeEscape(range[1]));
  344. }
  345. }
  346. out.push(']');
  347. return out.join('');
  348. }
  349. function allowAnywhereFoldCaseAndRenumberGroups(regex) {
  350. // Split into character sets, escape sequences, punctuation strings
  351. // like ('(', '(?:', ')', '^'), and runs of characters that do not
  352. // include any of the above.
  353. var parts = regex.source.match(
  354. new RegExp(
  355. '(?:'
  356. + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set
  357. + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape
  358. + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape
  359. + '|\\\\[0-9]+' // a back-reference or octal escape
  360. + '|\\\\[^ux0-9]' // other escape sequence
  361. + '|\\(\\?[:!=]' // start of a non-capturing group
  362. + '|[\\(\\)\\^]' // start/end of a group, or line start
  363. + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters
  364. + ')',
  365. 'g'));
  366. var n = parts.length;
  367. // Maps captured group numbers to the number they will occupy in
  368. // the output or to -1 if that has not been determined, or to
  369. // undefined if they need not be capturing in the output.
  370. var capturedGroups = [];
  371. // Walk over and identify back references to build the capturedGroups
  372. // mapping.
  373. for (var i = 0, groupIndex = 0; i < n; ++i) {
  374. var p = parts[i];
  375. if (p === '(') {
  376. // groups are 1-indexed, so max group index is count of '('
  377. ++groupIndex;
  378. } else if ('\\' === p.charAt(0)) {
  379. var decimalValue = +p.substring(1);
  380. if (decimalValue) {
  381. if (decimalValue <= groupIndex) {
  382. capturedGroups[decimalValue] = -1;
  383. } else {
  384. // Replace with an unambiguous escape sequence so that
  385. // an octal escape sequence does not turn into a backreference
  386. // to a capturing group from an earlier regex.
  387. parts[i] = encodeEscape(decimalValue);
  388. }
  389. }
  390. }
  391. }
  392. // Renumber groups and reduce capturing groups to non-capturing groups
  393. // where possible.
  394. for (var i = 1; i < capturedGroups.length; ++i) {
  395. if (-1 === capturedGroups[i]) {
  396. capturedGroups[i] = ++capturedGroupIndex;
  397. }
  398. }
  399. for (var i = 0, groupIndex = 0; i < n; ++i) {
  400. var p = parts[i];
  401. if (p === '(') {
  402. ++groupIndex;
  403. if (!capturedGroups[groupIndex]) {
  404. parts[i] = '(?:';
  405. }
  406. } else if ('\\' === p.charAt(0)) {
  407. var decimalValue = +p.substring(1);
  408. if (decimalValue && decimalValue <= groupIndex) {
  409. parts[i] = '\\' + capturedGroups[decimalValue];
  410. }
  411. }
  412. }
  413. // Remove any prefix anchors so that the output will match anywhere.
  414. // ^^ really does mean an anchored match though.
  415. for (var i = 0; i < n; ++i) {
  416. if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
  417. }
  418. // Expand letters to groups to handle mixing of case-sensitive and
  419. // case-insensitive patterns if necessary.
  420. if (regex.ignoreCase && needToFoldCase) {
  421. for (var i = 0; i < n; ++i) {
  422. var p = parts[i];
  423. var ch0 = p.charAt(0);
  424. if (p.length >= 2 && ch0 === '[') {
  425. parts[i] = caseFoldCharset(p);
  426. } else if (ch0 !== '\\') {
  427. // TODO: handle letters in numeric escapes.
  428. parts[i] = p.replace(
  429. /[a-zA-Z]/g,
  430. function (ch) {
  431. var cc = ch.charCodeAt(0);
  432. return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
  433. });
  434. }
  435. }
  436. }
  437. return parts.join('');
  438. }
  439. var rewritten = [];
  440. for (var i = 0, n = regexs.length; i < n; ++i) {
  441. var regex = regexs[i];
  442. if (regex.global || regex.multiline) { throw new Error('' + regex); }
  443. rewritten.push(
  444. '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
  445. }
  446. return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
  447. }
  448. /**
  449. * Split markup into a string of source code and an array mapping ranges in
  450. * that string to the text nodes in which they appear.
  451. *
  452. * <p>
  453. * The HTML DOM structure:</p>
  454. * <pre>
  455. * (Element "p"
  456. * (Element "b"
  457. * (Text "print ")) ; #1
  458. * (Text "'Hello '") ; #2
  459. * (Element "br") ; #3
  460. * (Text " + 'World';")) ; #4
  461. * </pre>
  462. * <p>
  463. * corresponds to the HTML
  464. * {@code <p><b>print </b>'Hello '<br> + 'World';</p>}.</p>
  465. *
  466. * <p>
  467. * It will produce the output:</p>
  468. * <pre>
  469. * {
  470. * sourceCode: "print 'Hello '\n + 'World';",
  471. * // 1 2
  472. * // 012345678901234 5678901234567
  473. * spans: [0, #1, 6, #2, 14, #3, 15, #4]
  474. * }
  475. * </pre>
  476. * <p>
  477. * where #1 is a reference to the {@code "print "} text node above, and so
  478. * on for the other text nodes.
  479. * </p>
  480. *
  481. * <p>
  482. * The {@code} spans array is an array of pairs. Even elements are the start
  483. * indices of substrings, and odd elements are the text nodes (or BR elements)
  484. * that contain the text for those substrings.
  485. * Substrings continue until the next index or the end of the source.
  486. * </p>
  487. *
  488. * @param {Node} node an HTML DOM subtree containing source-code.
  489. * @param {boolean} isPreformatted true if white-space in text nodes should
  490. * be considered significant.
  491. * @return {Object} source code and the text nodes in which they occur.
  492. */
  493. function extractSourceSpans(node, isPreformatted) {
  494. var nocode = /(?:^|\s)nocode(?:\s|$)/;
  495. var chunks = [];
  496. var length = 0;
  497. var spans = [];
  498. var k = 0;
  499. function walk(node) {
  500. var type = node.nodeType;
  501. if (type == 1) { // Element
  502. if (nocode.test(node.className)) { return; }
  503. for (var child = node.firstChild; child; child = child.nextSibling) {
  504. walk(child);
  505. }
  506. var nodeName = node.nodeName.toLowerCase();
  507. if ('br' === nodeName || 'li' === nodeName) {
  508. chunks[k] = '\n';
  509. spans[k << 1] = length++;
  510. spans[(k++ << 1) | 1] = node;
  511. }
  512. } else if (type == 3 || type == 4) { // Text
  513. var text = node.nodeValue;
  514. if (text.length) {
  515. if (!isPreformatted) {
  516. text = text.replace(/[ \t\r\n]+/g, ' ');
  517. } else {
  518. text = text.replace(/\r\n?/g, '\n'); // Normalize newlines.
  519. }
  520. // 清除代码尾部的空行
  521. text = text.replace(/\n[\s\t]+$/g,"");
  522. // TODO: handle tabs here?
  523. chunks[k] = text;
  524. spans[k << 1] = length;
  525. length += text.length;
  526. spans[(k++ << 1) | 1] = node;
  527. }
  528. }
  529. }
  530. walk(node);
  531. return {
  532. sourceCode: chunks.join('').replace(/\n$/, ''),
  533. spans: spans
  534. };
  535. }
  536. /**
  537. * Apply the given language handler to sourceCode and add the resulting
  538. * decorations to out.
  539. * @param {number} basePos the index of sourceCode within the chunk of source
  540. * whose decorations are already present on out.
  541. */
  542. function appendDecorations(basePos, sourceCode, langHandler, out) {
  543. if (!sourceCode) { return; }
  544. var job = {
  545. sourceCode: sourceCode,
  546. basePos: basePos
  547. };
  548. langHandler(job);
  549. out.push.apply(out, job.decorations);
  550. }
  551. var notWs = /\S/;
  552. /**
  553. * Given an element, if it contains only one child element and any text nodes
  554. * it contains contain only space characters, return the sole child element.
  555. * Otherwise returns undefined.
  556. * <p>
  557. * This is meant to return the CODE element in {@code <pre><code ...>} when
  558. * there is a single child element that contains all the non-space textual
  559. * content, but not to return anything where there are multiple child elements
  560. * as in {@code <pre><code>...</code><code>...</code></pre>} or when there
  561. * is textual content.
  562. */
  563. function childContentWrapper(element) {
  564. var wrapper = undefined;
  565. for (var c = element.firstChild; c; c = c.nextSibling) {
  566. var type = c.nodeType;
  567. wrapper = (type === 1) // Element Node
  568. ? (wrapper ? element : c)
  569. : (type === 3) // Text Node
  570. ? (notWs.test(c.nodeValue) ? element : wrapper)
  571. : wrapper;
  572. }
  573. return wrapper === element ? undefined : wrapper;
  574. }
  575. /** Given triples of [style, pattern, context] returns a lexing function,
  576. * The lexing function interprets the patterns to find token boundaries and
  577. * returns a decoration list of the form
  578. * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
  579. * where index_n is an index into the sourceCode, and style_n is a style
  580. * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to
  581. * all characters in sourceCode[index_n-1:index_n].
  582. *
  583. * The stylePatterns is a list whose elements have the form
  584. * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
  585. *
  586. * Style is a style constant like PR_PLAIN, or can be a string of the
  587. * form 'lang-FOO', where FOO is a language extension describing the
  588. * language of the portion of the token in $1 after pattern executes.
  589. * E.g., if style is 'lang-lisp', and group 1 contains the text
  590. * '(hello (world))', then that portion of the token will be passed to the
  591. * registered lisp handler for formatting.
  592. * The text before and after group 1 will be restyled using this decorator
  593. * so decorators should take care that this doesn't result in infinite
  594. * recursion. For example, the HTML lexer rule for SCRIPT elements looks
  595. * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match
  596. * '<script>foo()<\/script>', which would cause the current decorator to
  597. * be called with '<script>' which would not match the same rule since
  598. * group 1 must not be empty, so it would be instead styled as PR_TAG by
  599. * the generic tag rule. The handler registered for the 'js' extension would
  600. * then be called with 'foo()', and finally, the current decorator would
  601. * be called with '<\/script>' which would not match the original rule and
  602. * so the generic tag rule would identify it as a tag.
  603. *
  604. * Pattern must only match prefixes, and if it matches a prefix, then that
  605. * match is considered a token with the same style.
  606. *
  607. * Context is applied to the last non-whitespace, non-comment token
  608. * recognized.
  609. *
  610. * Shortcut is an optional string of characters, any of which, if the first
  611. * character, gurantee that this pattern and only this pattern matches.
  612. *
  613. * @param {Array} shortcutStylePatterns patterns that always start with
  614. * a known character. Must have a shortcut string.
  615. * @param {Array} fallthroughStylePatterns patterns that will be tried in
  616. * order if the shortcut ones fail. May have shortcuts.
  617. *
  618. * @return {function (Object)} a
  619. * function that takes source code and returns a list of decorations.
  620. */
  621. function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
  622. var shortcuts = {};
  623. var tokenizer;
  624. (function () {
  625. var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
  626. var allRegexs = [];
  627. var regexKeys = {};
  628. for (var i = 0, n = allPatterns.length; i < n; ++i) {
  629. var patternParts = allPatterns[i];
  630. var shortcutChars = patternParts[3];
  631. if (shortcutChars) {
  632. for (var c = shortcutChars.length; --c >= 0;) {
  633. shortcuts[shortcutChars.charAt(c)] = patternParts;
  634. }
  635. }
  636. var regex = patternParts[1];
  637. var k = '' + regex;
  638. if (!regexKeys.hasOwnProperty(k)) {
  639. allRegexs.push(regex);
  640. regexKeys[k] = null;
  641. }
  642. }
  643. allRegexs.push(/[\0-\uffff]/);
  644. tokenizer = combinePrefixPatterns(allRegexs);
  645. })();
  646. var nPatterns = fallthroughStylePatterns.length;
  647. /**
  648. * Lexes job.sourceCode and produces an output array job.decorations of
  649. * style classes preceded by the position at which they start in
  650. * job.sourceCode in order.
  651. *
  652. * @param {Object} job an object like <pre>{
  653. * sourceCode: {string} sourceText plain text,
  654. * basePos: {int} position of job.sourceCode in the larger chunk of
  655. * sourceCode.
  656. * }</pre>
  657. */
  658. var decorate = function (job) {
  659. var sourceCode = job.sourceCode, basePos = job.basePos;
  660. /** Even entries are positions in source in ascending order. Odd enties
  661. * are style markers (e.g., PR_COMMENT) that run from that position until
  662. * the end.
  663. * @type {Array.<number|string>}
  664. */
  665. var decorations = [basePos, PR_PLAIN];
  666. var pos = 0; // index into sourceCode
  667. var tokens = sourceCode.match(tokenizer) || [];
  668. var styleCache = {};
  669. for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
  670. var token = tokens[ti];
  671. var style = styleCache[token];
  672. var match = void 0;
  673. var isEmbedded;
  674. if (typeof style === 'string') {
  675. isEmbedded = false;
  676. } else {
  677. var patternParts = shortcuts[token.charAt(0)];
  678. if (patternParts) {
  679. match = token.match(patternParts[1]);
  680. style = patternParts[0];
  681. } else {
  682. for (var i = 0; i < nPatterns; ++i) {
  683. patternParts = fallthroughStylePatterns[i];
  684. match = token.match(patternParts[1]);
  685. if (match) {
  686. style = patternParts[0];
  687. break;
  688. }
  689. }
  690. if (!match) { // make sure that we make progress
  691. style = PR_PLAIN;
  692. }
  693. }
  694. isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
  695. if (isEmbedded && !(match && typeof match[1] === 'string')) {
  696. isEmbedded = false;
  697. style = PR_SOURCE;
  698. }
  699. if (!isEmbedded) { styleCache[token] = style; }
  700. }
  701. var tokenStart = pos;
  702. pos += token.length;
  703. if (!isEmbedded) {
  704. decorations.push(basePos + tokenStart, style);
  705. } else { // Treat group 1 as an embedded block of source code.
  706. var embeddedSource = match[1];
  707. var embeddedSourceStart = token.indexOf(embeddedSource);
  708. var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
  709. if (match[2]) {
  710. // If embeddedSource can be blank, then it would match at the
  711. // beginning which would cause us to infinitely recurse on the
  712. // entire token, so we catch the right context in match[2].
  713. embeddedSourceEnd = token.length - match[2].length;
  714. embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
  715. }
  716. var lang = style.substring(5);
  717. // Decorate the left of the embedded source
  718. appendDecorations(
  719. basePos + tokenStart,
  720. token.substring(0, embeddedSourceStart),
  721. decorate, decorations);
  722. // Decorate the embedded source
  723. appendDecorations(
  724. basePos + tokenStart + embeddedSourceStart,
  725. embeddedSource,
  726. langHandlerForExtension(lang, embeddedSource),
  727. decorations);
  728. // Decorate the right of the embedded section
  729. appendDecorations(
  730. basePos + tokenStart + embeddedSourceEnd,
  731. token.substring(embeddedSourceEnd),
  732. decorate, decorations);
  733. }
  734. }
  735. job.decorations = decorations;
  736. };
  737. return decorate;
  738. }
  739. /** returns a function that produces a list of decorations from source text.
  740. *
  741. * This code treats ", ', and ` as string delimiters, and \ as a string
  742. * escape. It does not recognize perl's qq() style strings.
  743. * It has no special handling for double delimiter escapes as in basic, or
  744. * the tripled delimiters used in python, but should work on those regardless
  745. * although in those cases a single string literal may be broken up into
  746. * multiple adjacent string literals.
  747. *
  748. * It recognizes C, C++, and shell style comments.
  749. *
  750. * @param {Object} options a set of optional parameters.
  751. * @return {function (Object)} a function that examines the source code
  752. * in the input job and builds the decoration list.
  753. */
  754. function sourceDecorator(options) {
  755. var shortcutStylePatterns = [], fallthroughStylePatterns = [];
  756. if (options['tripleQuotedStrings']) {
  757. // '''multi-line-string''', 'single-line-string', and double-quoted
  758. shortcutStylePatterns.push(
  759. [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
  760. null, '\'"']);
  761. } else if (options['multiLineStrings']) {
  762. // 'multi-line-string', "multi-line-string"
  763. shortcutStylePatterns.push(
  764. [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
  765. null, '\'"`']);
  766. } else {
  767. // 'single-line-string', "single-line-string"
  768. shortcutStylePatterns.push(
  769. [PR_STRING,
  770. /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
  771. null, '"\'']);
  772. }
  773. if (options['verbatimStrings']) {
  774. // verbatim-string-literal production from the C# grammar. See issue 93.
  775. fallthroughStylePatterns.push(
  776. [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
  777. }
  778. var hc = options['hashComments'];
  779. if (hc) {
  780. if (options['cStyleComments']) {
  781. if (hc > 1) { // multiline hash comments
  782. shortcutStylePatterns.push(
  783. [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
  784. } else {
  785. // Stop C preprocessor declarations at an unclosed open comment
  786. shortcutStylePatterns.push(
  787. [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
  788. null, '#']);
  789. }
  790. // #include <stdio.h>
  791. fallthroughStylePatterns.push(
  792. [PR_STRING,
  793. /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,
  794. null]);
  795. } else {
  796. shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
  797. }
  798. }
  799. if (options['cStyleComments']) {
  800. fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
  801. fallthroughStylePatterns.push(
  802. [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
  803. }
  804. var regexLiterals = options['regexLiterals'];
  805. if (regexLiterals) {
  806. /**
  807. * @const
  808. */
  809. var regexExcls = regexLiterals > 1
  810. ? '' // Multiline regex literals
  811. : '\n\r';
  812. /**
  813. * @const
  814. */
  815. var regexAny = regexExcls ? '.' : '[\\S\\s]';
  816. /**
  817. * @const
  818. */
  819. var REGEX_LITERAL = (
  820. // A regular expression literal starts with a slash that is
  821. // not followed by * or / so that it is not confused with
  822. // comments.
  823. '/(?=[^/*' + regexExcls + '])'
  824. // and then contains any number of raw characters,
  825. + '(?:[^/\\x5B\\x5C' + regexExcls + ']'
  826. // escape sequences (\x5C),
  827. + '|\\x5C' + regexAny
  828. // or non-nesting character sets (\x5B\x5D);
  829. + '|\\x5B(?:[^\\x5C\\x5D' + regexExcls + ']'
  830. + '|\\x5C' + regexAny + ')*(?:\\x5D|$))+'
  831. // finally closed by a /.
  832. + '/');
  833. fallthroughStylePatterns.push(
  834. ['lang-regex',
  835. RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
  836. ]);
  837. }
  838. var types = options['types'];
  839. if (types) {
  840. fallthroughStylePatterns.push([PR_TYPE, types]);
  841. }
  842. var keywords = ("" + options['keywords']).replace(/^ | $/g, '');
  843. if (keywords.length) {
  844. fallthroughStylePatterns.push(
  845. [PR_KEYWORD,
  846. new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'),
  847. null]);
  848. }
  849. shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']);
  850. var punctuation =
  851. // The Bash man page says
  852. // A word is a sequence of characters considered as a single
  853. // unit by GRUB. Words are separated by metacharacters,
  854. // which are the following plus space, tab, and newline: { }
  855. // | & $ ; < >
  856. // ...
  857. // A word beginning with # causes that word and all remaining
  858. // characters on that line to be ignored.
  859. // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a
  860. // comment but empirically
  861. // $ echo {#}
  862. // {#}
  863. // $ echo \$#
  864. // $#
  865. // $ echo }#
  866. // }#
  867. // so /(?:^|[|&;<>\s])/ is more appropriate.
  868. // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3
  869. // suggests that this definition is compatible with a
  870. // default mode that tries to use a single token definition
  871. // to recognize both bash/python style comments and C
  872. // preprocessor directives.
  873. // This definition of punctuation does not include # in the list of
  874. // follow-on exclusions, so # will not be broken before if preceeded
  875. // by a punctuation character. We could try to exclude # after
  876. // [|&;<>] but that doesn't seem to cause many major problems.
  877. // If that does turn out to be a problem, we should change the below
  878. // when hc is truthy to include # in the run of punctuation characters
  879. // only when not followint [|&;<>].
  880. '^.[^\\s\\w.$@\'"`/\\\\]*';
  881. if (options['regexLiterals']) {
  882. punctuation += '(?!\s*\/)';
  883. }
  884. fallthroughStylePatterns.push(
  885. // TODO(mikesamuel): recognize non-latin letters and numerals in idents
  886. [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null],
  887. [PR_TYPE, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null],
  888. [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null],
  889. [PR_LITERAL,
  890. new RegExp(
  891. '^(?:'
  892. // A hex number
  893. + '0x[a-f0-9]+'
  894. // or an octal or decimal number,
  895. + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
  896. // possibly in scientific notation
  897. + '(?:e[+\\-]?\\d+)?'
  898. + ')'
  899. // with an optional modifier like UL for unsigned long
  900. + '[a-z]*', 'i'),
  901. null, '0123456789'],
  902. // Don't treat escaped quotes in bash as starting strings.
  903. // See issue 144.
  904. [PR_PLAIN, /^\\[\s\S]?/, null],
  905. [PR_PUNCTUATION, new RegExp(punctuation), null]);
  906. return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
  907. }
  908. var decorateSource = sourceDecorator({
  909. 'keywords': ALL_KEYWORDS,
  910. 'hashComments': true,
  911. 'cStyleComments': true,
  912. 'multiLineStrings': true,
  913. 'regexLiterals': true
  914. });
  915. /**
  916. * Given a DOM subtree, wraps it in a list, and puts each line into its own
  917. * list item.
  918. *
  919. * @param {Node} node modified in place. Its content is pulled into an
  920. * HTMLOListElement, and each line is moved into a separate list item.
  921. * This requires cloning elements, so the input might not have unique
  922. * IDs after numbering.
  923. * @param {boolean} isPreformatted true iff white-space in text nodes should
  924. * be treated as significant.
  925. */
  926. function numberLines(node, opt_startLineNum, isPreformatted) {
  927. var nocode = /(?:^|\s)nocode(?:\s|$)/;
  928. var lineBreak = /\r\n?|\n/;
  929. var invalidTail = /^[\s\t]+$/;
  930. var document = node.ownerDocument;
  931. var li = document.createElement('li');
  932. while (node.firstChild) {
  933. li.appendChild(node.firstChild);
  934. }
  935. // An array of lines. We split below, so this is initialized to one
  936. // un-split line.
  937. var listItems = [li];
  938. function walk(node) {
  939. var type = node.nodeType;
  940. if (type == 1 && !nocode.test(node.className)) { // Element
  941. if ('br' === node.nodeName) {
  942. breakAfter(node);
  943. // Discard the <BR> since it is now flush against a </LI>.
  944. if (node.parentNode) {
  945. node.parentNode.removeChild(node);
  946. }
  947. } else {
  948. for (var child = node.firstChild; child; child = child.nextSibling) {
  949. walk(child);
  950. }
  951. }
  952. } else if ((type == 3 || type == 4) && isPreformatted) { // Text
  953. var text = node.nodeValue;
  954. var match = text.match(lineBreak);
  955. if (match) {
  956. var firstLine = text.substring(0, match.index);
  957. node.nodeValue = firstLine;
  958. var tail = text.substring(match.index + match[0].length);
  959. if (tail && !invalidTail.test(tail) ) { // 清除代码尾部的空行, org: if (tail) {
  960. var parent = node.parentNode;
  961. parent.insertBefore(
  962. document.createTextNode(tail), node.nextSibling);
  963. }
  964. breakAfter(node);
  965. if (!firstLine) {
  966. // Don't leave blank text nodes in the DOM.
  967. node.parentNode.removeChild(node);
  968. }
  969. }
  970. }
  971. }
  972. // Split a line after the given node.
  973. function breakAfter(lineEndNode) {
  974. // If there's nothing to the right, then we can skip ending the line
  975. // here, and move root-wards since splitting just before an end-tag
  976. // would require us to create a bunch of empty copies.
  977. while (!lineEndNode.nextSibling) {
  978. lineEndNode = lineEndNode.parentNode;
  979. if (!lineEndNode) { return; }
  980. }
  981. function breakLeftOf(limit, copy) {
  982. // Clone shallowly if this node needs to be on both sides of the break.
  983. var rightSide = copy ? limit.cloneNode(false) : limit;
  984. var parent = limit.parentNode;
  985. if (parent) {
  986. // We clone the parent chain.
  987. // This helps us resurrect important styling elements that cross lines.
  988. // E.g. in <i>Foo<br>Bar</i>
  989. // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.
  990. var parentClone = breakLeftOf(parent, 1);
  991. // Move the clone and everything to the right of the original
  992. // onto the cloned parent.
  993. var next = limit.nextSibling;
  994. parentClone.appendChild(rightSide);
  995. for (var sibling = next; sibling; sibling = next) {
  996. next = sibling.nextSibling;
  997. parentClone.appendChild(sibling);
  998. }
  999. }
  1000. return rightSide;
  1001. }
  1002. var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);
  1003. // Walk the parent chain until we reach an unattached LI.
  1004. for (var parent;
  1005. // Check nodeType since IE invents document fragments.
  1006. (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {
  1007. copiedListItem = parent;
  1008. }
  1009. // Put it on the list of lines for later processing.
  1010. listItems.push(copiedListItem);
  1011. }
  1012. // Split lines while there are lines left to split.
  1013. for (var i = 0; // Number of lines that have been split so far.
  1014. i < listItems.length; // length updated by breakAfter calls.
  1015. ++i) {
  1016. walk(listItems[i]);
  1017. }
  1018. // Make sure numeric indices show correctly.
  1019. if (opt_startLineNum === (opt_startLineNum|0)) {
  1020. listItems[0].setAttribute('value', opt_startLineNum);
  1021. }
  1022. var ol = document.createElement('ol');
  1023. ol.className = 'linenums';
  1024. var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;
  1025. for (var i = 0, n = listItems.length; i < n; ++i) {
  1026. li = listItems[i];
  1027. // Stick a class on the LIs so that stylesheets can
  1028. // color odd/even rows, or any other row pattern that
  1029. // is co-prime with 10.
  1030. li.className = 'L' + ((i + offset) % 10);
  1031. if (!li.firstChild) {
  1032. li.appendChild(document.createTextNode('\xA0'));
  1033. }
  1034. ol.appendChild(li);
  1035. }
  1036. node.appendChild(ol);
  1037. }
  1038. /**
  1039. * Breaks {@code job.sourceCode} around style boundaries in
  1040. * {@code job.decorations} and modifies {@code job.sourceNode} in place.
  1041. * @param {Object} job like <pre>{
  1042. * sourceCode: {string} source as plain text,
  1043. * sourceNode: {HTMLElement} the element containing the source,
  1044. * spans: {Array.<number|Node>} alternating span start indices into source
  1045. * and the text node or element (e.g. {@code <BR>}) corresponding to that
  1046. * span.
  1047. * decorations: {Array.<number|string} an array of style classes preceded
  1048. * by the position at which they start in job.sourceCode in order
  1049. * }</pre>
  1050. * @private
  1051. */
  1052. function recombineTagsAndDecorations(job) {
  1053. var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent);
  1054. isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;
  1055. var newlineRe = /\n/g;
  1056. var source = job.sourceCode;
  1057. var sourceLength = source.length;
  1058. // Index into source after the last code-unit recombined.
  1059. var sourceIndex = 0;
  1060. var spans = job.spans;
  1061. var nSpans = spans.length;
  1062. // Index into spans after the last span which ends at or before sourceIndex.
  1063. var spanIndex = 0;
  1064. var decorations = job.decorations;
  1065. var nDecorations = decorations.length;
  1066. // Index into decorations after the last decoration which ends at or before
  1067. // sourceIndex.
  1068. var decorationIndex = 0;
  1069. // Remove all zero-length decorations.
  1070. decorations[nDecorations] = sourceLength;
  1071. var decPos, i;
  1072. for (i = decPos = 0; i < nDecorations;) {
  1073. if (decorations[i] !== decorations[i + 2]) {
  1074. decorations[decPos++] = decorations[i++];
  1075. decorations[decPos++] = decorations[i++];
  1076. } else {
  1077. i += 2;
  1078. }
  1079. }
  1080. nDecorations = decPos;
  1081. // Simplify decorations.
  1082. for (i = decPos = 0; i < nDecorations;) {
  1083. var startPos = decorations[i];
  1084. // Conflate all adjacent decorations that use the same style.
  1085. var startDec = decorations[i + 1];
  1086. var end = i + 2;
  1087. while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {
  1088. end += 2;
  1089. }
  1090. decorations[decPos++] = startPos;
  1091. decorations[decPos++] = startDec;
  1092. i = end;
  1093. }
  1094. nDecorations = decorations.length = decPos;
  1095. var sourceNode = job.sourceNode;
  1096. var oldDisplay;
  1097. if (sourceNode) {
  1098. oldDisplay = sourceNode.style.display;
  1099. sourceNode.style.display = 'none';
  1100. }
  1101. try {
  1102. var decoration = null;
  1103. while (spanIndex < nSpans) {
  1104. var spanStart = spans[spanIndex];
  1105. var spanEnd = spans[spanIndex + 2] || sourceLength;
  1106. var decEnd = decorations[decorationIndex + 2] || sourceLength;
  1107. var end = Math.min(spanEnd, decEnd);
  1108. var textNode = spans[spanIndex + 1];
  1109. var styledText;
  1110. if (textNode.nodeType !== 1 // Don't muck with <BR>s or <LI>s
  1111. // Don't introduce spans around empty text nodes.
  1112. && (styledText = source.substring(sourceIndex, end))) {
  1113. // This may seem bizarre, and it is. Emitting LF on IE causes the
  1114. // code to display with spaces instead of line breaks.
  1115. // Emitting Windows standard issue linebreaks (CRLF) causes a blank
  1116. // space to appear at the beginning of every line but the first.
  1117. // Emitting an old Mac OS 9 line separator makes everything spiffy.
  1118. if (isIE8OrEarlier) {
  1119. styledText = styledText.replace(newlineRe, '\r');
  1120. }
  1121. textNode.nodeValue = styledText;
  1122. var document = textNode.ownerDocument;
  1123. var span = document.createElement('span');
  1124. span.className = decorations[decorationIndex + 1];
  1125. var parentNode = textNode.parentNode;
  1126. parentNode.replaceChild(span, textNode);
  1127. span.appendChild(textNode);
  1128. if (sourceIndex < spanEnd) { // Split off a text node.
  1129. spans[spanIndex + 1] = textNode
  1130. // TODO: Possibly optimize by using '' if there's no flicker.
  1131. = document.createTextNode(source.substring(end, spanEnd));
  1132. parentNode.insertBefore(textNode, span.nextSibling);
  1133. }
  1134. }
  1135. sourceIndex = end;
  1136. if (sourceIndex >= spanEnd) {
  1137. spanIndex += 2;
  1138. }
  1139. if (sourceIndex >= decEnd) {
  1140. decorationIndex += 2;
  1141. }
  1142. }
  1143. } finally {
  1144. if (sourceNode) {
  1145. sourceNode.style.display = oldDisplay;
  1146. }
  1147. }
  1148. }
  1149. /** Maps language-specific file extensions to handlers. */
  1150. var langHandlerRegistry = {};
  1151. /** Register a language handler for the given file extensions.
  1152. * @param {function (Object)} handler a function from source code to a list
  1153. * of decorations. Takes a single argument job which describes the
  1154. * state of the computation. The single parameter has the form
  1155. * {@code {
  1156. * sourceCode: {string} as plain text.
  1157. * decorations: {Array.<number|string>} an array of style classes
  1158. * preceded by the position at which they start in
  1159. * job.sourceCode in order.
  1160. * The language handler should assigned this field.
  1161. * basePos: {int} the position of source in the larger source chunk.
  1162. * All positions in the output decorations array are relative
  1163. * to the larger source chunk.
  1164. * } }
  1165. * @param {Array.<string>} fileExtensions
  1166. */
  1167. function registerLangHandler(handler, fileExtensions) {
  1168. for (var i = fileExtensions.length; --i >= 0;) {
  1169. var ext = fileExtensions[i];
  1170. if (!langHandlerRegistry.hasOwnProperty(ext)) {
  1171. langHandlerRegistry[ext] = handler;
  1172. } else if (win['console']) {
  1173. console['warn']('cannot override language handler %s', ext);
  1174. }
  1175. }
  1176. }
  1177. function langHandlerForExtension(extension, source) {
  1178. if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
  1179. // Treat it as markup if the first non whitespace character is a < and
  1180. // the last non-whitespace character is a >.
  1181. extension = /^\s*</.test(source)
  1182. ? 'default-markup'
  1183. : 'default-code';
  1184. }
  1185. return langHandlerRegistry[extension];
  1186. }
  1187. registerLangHandler(decorateSource, ['default-code']);
  1188. registerLangHandler(
  1189. createSimpleLexer(
  1190. [],
  1191. [
  1192. [PR_PLAIN, /^[^<?]+/],
  1193. [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
  1194. [PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/],
  1195. // Unescaped content in an unknown language
  1196. ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/],
  1197. ['lang-', /^<%([\s\S]+?)(?:%>|$)/],
  1198. [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
  1199. ['lang-', /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
  1200. // Unescaped content in javascript. (Or possibly vbscript).
  1201. ['lang-js', /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
  1202. // Contains unescaped stylesheet content
  1203. ['lang-css', /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
  1204. ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]
  1205. ]),
  1206. ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
  1207. registerLangHandler(
  1208. createSimpleLexer(
  1209. [
  1210. [PR_PLAIN, /^[\s]+/, null, ' \t\r\n'],
  1211. [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
  1212. ],
  1213. [
  1214. [PR_TAG, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
  1215. [PR_ATTRIB_NAME, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
  1216. ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
  1217. [PR_PUNCTUATION, /^[=<>\/]+/],
  1218. ['lang-js', /^on\w+\s*=\s*\"([^\"]+)\"/i],
  1219. ['lang-js', /^on\w+\s*=\s*\'([^\']+)\'/i],
  1220. ['lang-js', /^on\w+\s*=\s*([^\"\'>\s]+)/i],
  1221. ['lang-css', /^style\s*=\s*\"([^\"]+)\"/i],
  1222. ['lang-css', /^style\s*=\s*\'([^\']+)\'/i],
  1223. ['lang-css', /^style\s*=\s*([^\"\'>\s]+)/i]
  1224. ]),
  1225. ['in.tag']);
  1226. registerLangHandler(
  1227. createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
  1228. registerLangHandler(sourceDecorator({
  1229. 'keywords': CPP_KEYWORDS,
  1230. 'hashComments': true,
  1231. 'cStyleComments': true,
  1232. 'types': C_TYPES
  1233. }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
  1234. registerLangHandler(sourceDecorator({
  1235. 'keywords': 'null,true,false'
  1236. }), ['json']);
  1237. registerLangHandler(sourceDecorator({
  1238. 'keywords': CSHARP_KEYWORDS,
  1239. 'hashComments': true,
  1240. 'cStyleComments': true,
  1241. 'verbatimStrings': true,
  1242. 'types': C_TYPES
  1243. }), ['cs']);
  1244. registerLangHandler(sourceDecorator({
  1245. 'keywords': JAVA_KEYWORDS,
  1246. 'cStyleComments': true
  1247. }), ['java']);
  1248. registerLangHandler(sourceDecorator({
  1249. 'keywords': SH_KEYWORDS,
  1250. 'hashComments': true,
  1251. 'multiLineStrings': true
  1252. }), ['bash', 'bsh', 'csh', 'sh']);
  1253. registerLangHandler(sourceDecorator({
  1254. 'keywords': PYTHON_KEYWORDS,
  1255. 'hashComments': true,
  1256. 'multiLineStrings': true,
  1257. 'tripleQuotedStrings': true
  1258. }), ['cv', 'py', 'python']);
  1259. registerLangHandler(sourceDecorator({
  1260. 'keywords': PERL_KEYWORDS,
  1261. 'hashComments': true,
  1262. 'multiLineStrings': true,
  1263. 'regexLiterals': 2 // multiline regex literals
  1264. }), ['perl', 'pl', 'pm']);
  1265. registerLangHandler(sourceDecorator({
  1266. 'keywords': RUBY_KEYWORDS,
  1267. 'hashComments': true,
  1268. 'multiLineStrings': true,
  1269. 'regexLiterals': true
  1270. }), ['rb', 'ruby']);
  1271. registerLangHandler(sourceDecorator({
  1272. 'keywords': JSCRIPT_KEYWORDS,
  1273. 'cStyleComments': true,
  1274. 'regexLiterals': true
  1275. }), ['javascript', 'js']);
  1276. registerLangHandler(sourceDecorator({
  1277. 'keywords': COFFEE_KEYWORDS,
  1278. 'hashComments': 3, // ### style block comments
  1279. 'cStyleComments': true,
  1280. 'multilineStrings': true,
  1281. 'tripleQuotedStrings': true,
  1282. 'regexLiterals': true
  1283. }), ['coffee']);
  1284. registerLangHandler(sourceDecorator({
  1285. 'keywords': RUST_KEYWORDS,
  1286. 'cStyleComments': true,
  1287. 'multilineStrings': true
  1288. }), ['rc', 'rs', 'rust']);
  1289. registerLangHandler(
  1290. createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
  1291. function applyDecorator(job) {
  1292. var opt_langExtension = job.langExtension;
  1293. try {
  1294. // Extract tags, and convert the source code to plain text.
  1295. var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);
  1296. /** Plain text. @type {string} */
  1297. var source = sourceAndSpans.sourceCode;
  1298. job.sourceCode = source;
  1299. job.spans = sourceAndSpans.spans;
  1300. job.basePos = 0;
  1301. // Apply the appropriate language handler
  1302. langHandlerForExtension(opt_langExtension, source)(job);
  1303. // Integrate the decorations and tags back into the source code,
  1304. // modifying the sourceNode in place.
  1305. recombineTagsAndDecorations(job);
  1306. } catch (e) {
  1307. if (win['console']) {
  1308. console['log'](e && e['stack'] || e);
  1309. }
  1310. }
  1311. }
  1312. /**
  1313. * Pretty print a chunk of code.
  1314. * @param sourceCodeHtml {string} The HTML to pretty print.
  1315. * @param opt_langExtension {string} The language name to use.
  1316. * Typically, a filename extension like 'cpp' or 'java'.
  1317. * @param opt_numberLines {number|boolean} True to number lines,
  1318. * or the 1-indexed number of the first line in sourceCodeHtml.
  1319. */
  1320. function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
  1321. var container = document.createElement('div');
  1322. // This could cause images to load and onload listeners to fire.
  1323. // E.g. <img onerror="alert(1337)" src="nosuchimage.png">.
  1324. // We assume that the inner HTML is from a trusted source.
  1325. // The pre-tag is required for IE8 which strips newlines from innerHTML
  1326. // when it is injected into a <pre> tag.
  1327. // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie
  1328. // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript
  1329. container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>';
  1330. container = container.firstChild;
  1331. if (opt_numberLines) {
  1332. numberLines(container, opt_numberLines, true);
  1333. }
  1334. var job = {
  1335. langExtension: opt_langExtension,
  1336. numberLines: opt_numberLines,
  1337. sourceNode: container,
  1338. pre: 1
  1339. };
  1340. applyDecorator(job);
  1341. return container.innerHTML;
  1342. }
  1343. /**
  1344. * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
  1345. * {@code class=prettyprint} and prettify them.
  1346. *
  1347. * @param {Function} opt_whenDone called when prettifying is done.
  1348. * @param {HTMLElement|HTMLDocument} opt_root an element or document
  1349. * containing all the elements to pretty print.
  1350. * Defaults to {@code document.body}.
  1351. */
  1352. function $prettyPrint(opt_whenDone, opt_root) {
  1353. var root = opt_root || document.body;
  1354. var doc = root.ownerDocument || document;
  1355. function byTagName(tn) { return root.getElementsByTagName(tn); }
  1356. // fetch a list of nodes to rewrite
  1357. var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
  1358. var elements = [];
  1359. for (var i = 0; i < codeSegments.length; ++i) {
  1360. for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
  1361. elements.push(codeSegments[i][j]);
  1362. }
  1363. }
  1364. codeSegments = null;
  1365. var clock = Date;
  1366. if (!clock['now']) {
  1367. clock = { 'now': function () { return +(new Date); } };
  1368. }
  1369. // The loop is broken into a series of continuations to make sure that we
  1370. // don't make the browser unresponsive when rewriting a large page.
  1371. var k = 0;
  1372. var prettyPrintingJob;
  1373. var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/;
  1374. var prettyPrintRe = /\bprettyprint\b/;
  1375. var prettyPrintedRe = /\bprettyprinted\b/;
  1376. var preformattedTagNameRe = /pre|xmp/i;
  1377. var codeRe = /^code$/i;
  1378. var preCodeXmpRe = /^(?:pre|code|xmp)$/i;
  1379. var EMPTY = {};
  1380. function doWork() {
  1381. var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?
  1382. clock['now']() + 250 /* ms */ :
  1383. Infinity);
  1384. for (; k < elements.length && clock['now']() < endTime; k++) {
  1385. var cs = elements[k];
  1386. // Look for a preceding comment like
  1387. // <?prettify lang="..." linenums="..."?>
  1388. var attrs = EMPTY;
  1389. {
  1390. for (var preceder = cs; (preceder = preceder.previousSibling);) {
  1391. var nt = preceder.nodeType;
  1392. // <?foo?> is parsed by HTML 5 to a comment node (8)
  1393. // like <!--?foo?-->, but in XML is a processing instruction
  1394. var value = (nt === 7 || nt === 8) && preceder.nodeValue;
  1395. if (value
  1396. ? !/^\??prettify\b/.test(value)
  1397. : (nt !== 3 || /\S/.test(preceder.nodeValue))) {
  1398. // Skip over white-space text nodes but not others.
  1399. break;
  1400. }
  1401. if (value) {
  1402. attrs = {};
  1403. value.replace(
  1404. /\b(\w+)=([\w:.%+-]+)/g,
  1405. function (_, name, value) { attrs[name] = value; });
  1406. break;
  1407. }
  1408. }
  1409. }
  1410. var className = cs.className;
  1411. if ((attrs !== EMPTY || prettyPrintRe.test(className))
  1412. // Don't redo this if we've already done it.
  1413. // This allows recalling pretty print to just prettyprint elements
  1414. // that have been added to the page since last call.
  1415. && !prettyPrintedRe.test(className)) {
  1416. // make sure this is not nested in an already prettified element
  1417. var nested = false;
  1418. for (var p = cs.parentNode; p; p = p.parentNode) {
  1419. var tn = p.tagName;
  1420. if (preCodeXmpRe.test(tn)
  1421. && p.className && prettyPrintRe.test(p.className)) {
  1422. nested = true;
  1423. break;
  1424. }
  1425. }
  1426. if (!nested) {
  1427. // Mark done. If we fail to prettyprint for whatever reason,
  1428. // we shouldn't try again.
  1429. cs.className += ' prettyprinted';
  1430. // If the classes includes a language extensions, use it.
  1431. // Language extensions can be specified like
  1432. // <pre class="prettyprint lang-cpp">
  1433. // the language extension "cpp" is used to find a language handler
  1434. // as passed to PR.registerLangHandler.
  1435. // HTML5 recommends that a language be specified using "language-"
  1436. // as the prefix instead. Google Code Prettify supports both.
  1437. // http://dev.w3.org/html5/spec-author-view/the-code-element.html
  1438. var langExtension = attrs['lang'];
  1439. if (!langExtension) {
  1440. langExtension = className.match(langExtensionRe);
  1441. // Support <pre class="prettyprint"><code class="language-c">
  1442. var wrapper;
  1443. if (!langExtension && (wrapper = childContentWrapper(cs))
  1444. && codeRe.test(wrapper.tagName)) {
  1445. langExtension = wrapper.className.match(langExtensionRe);
  1446. }
  1447. if (langExtension) { langExtension = langExtension[1]; }
  1448. }
  1449. var preformatted;
  1450. if (preformattedTagNameRe.test(cs.tagName)) {
  1451. preformatted = 1;
  1452. } else {
  1453. var currentStyle = cs['currentStyle'];
  1454. var defaultView = doc.defaultView;
  1455. var whitespace = (
  1456. currentStyle
  1457. ? currentStyle['whiteSpace']
  1458. : (defaultView
  1459. && defaultView.getComputedStyle)
  1460. ? defaultView.getComputedStyle(cs, null)
  1461. .getPropertyValue('white-space')
  1462. : 0);
  1463. preformatted = whitespace
  1464. && 'pre' === whitespace.substring(0, 3);
  1465. }
  1466. // Look for a class like linenums or linenums:<n> where <n> is the
  1467. // 1-indexed number of the first line.
  1468. var lineNums = attrs['linenums'];
  1469. if (!(lineNums = lineNums === 'true' || +lineNums)) {
  1470. lineNums = className.match(/\blinenums\b(?::(\d+))?/);
  1471. lineNums =
  1472. lineNums
  1473. ? lineNums[1] && lineNums[1].length
  1474. ? +lineNums[1] : true
  1475. : false;
  1476. }
  1477. if (lineNums) { numberLines(cs, lineNums, preformatted); }
  1478. // do the pretty printing
  1479. prettyPrintingJob = {
  1480. langExtension: langExtension,
  1481. sourceNode: cs,
  1482. numberLines: lineNums,
  1483. pre: preformatted
  1484. };
  1485. applyDecorator(prettyPrintingJob);
  1486. }
  1487. }
  1488. }
  1489. if (k < elements.length) {
  1490. // finish up in a continuation
  1491. setTimeout(doWork, 250);
  1492. } else if ('function' === typeof opt_whenDone) {
  1493. opt_whenDone();
  1494. }
  1495. }
  1496. doWork();
  1497. }
  1498. /**
  1499. * Contains functions for creating and registering new language handlers.
  1500. * @type {Object}
  1501. */
  1502. var PR = win['PR'] = {
  1503. 'createSimpleLexer': createSimpleLexer,
  1504. 'registerLangHandler': registerLangHandler,
  1505. 'sourceDecorator': sourceDecorator,
  1506. 'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
  1507. 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
  1508. 'PR_COMMENT': PR_COMMENT,
  1509. 'PR_DECLARATION': PR_DECLARATION,
  1510. 'PR_KEYWORD': PR_KEYWORD,
  1511. 'PR_LITERAL': PR_LITERAL,
  1512. 'PR_NOCODE': PR_NOCODE,
  1513. 'PR_PLAIN': PR_PLAIN,
  1514. 'PR_PUNCTUATION': PR_PUNCTUATION,
  1515. 'PR_SOURCE': PR_SOURCE,
  1516. 'PR_STRING': PR_STRING,
  1517. 'PR_TAG': PR_TAG,
  1518. 'PR_TYPE': PR_TYPE,
  1519. 'prettyPrintOne':
  1520. IN_GLOBAL_SCOPE
  1521. ? (win['prettyPrintOne'] = $prettyPrintOne)
  1522. : (prettyPrintOne = $prettyPrintOne),
  1523. 'prettyPrint': prettyPrint =
  1524. IN_GLOBAL_SCOPE
  1525. ? (win['prettyPrint'] = $prettyPrint)
  1526. : (prettyPrint = $prettyPrint)
  1527. };
  1528. // Make PR available via the Asynchronous Module Definition (AMD) API.
  1529. // Per https://github.com/amdjs/amdjs-api/wiki/AMD:
  1530. // The Asynchronous Module Definition (AMD) API specifies a
  1531. // mechanism for defining modules such that the module and its
  1532. // dependencies can be asynchronously loaded.
  1533. // ...
  1534. // To allow a clear indicator that a global define function (as
  1535. // needed for script src browser loading) conforms to the AMD API,
  1536. // any global define function SHOULD have a property called "amd"
  1537. // whose value is an object. This helps avoid conflict with any
  1538. // other existing JavaScript code that could have defined a define()
  1539. // function that does not conform to the AMD API.
  1540. if (typeof define === "function" && define['amd']) {
  1541. define("google-code-prettify", [], function () {
  1542. return PR;
  1543. });
  1544. }
  1545. })();