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