1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// Copyright (C) 2006 Google Inc.
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// Licensed under the Apache License, Version 2.0 (the "License");
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// you may not use this file except in compliance with the License.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// You may obtain a copy of the License at
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      http://www.apache.org/licenses/LICENSE-2.0
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// Unless required by applicable law or agreed to in writing, software
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// distributed under the License is distributed on an "AS IS" BASIS,
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// See the License for the specific language governing permissions and
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// limitations under the License.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @fileoverview
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * some functions for browser-side pretty printing of code contained in html.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The lexer should work on a number of languages including C and friends,
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles.
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It works passably on Ruby, PHP and Awk and a decent subset of Perl, but,
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * because of commenting conventions, doesn't work on Smalltalk, Lisp-like, or
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * CAML-like languages.
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If there's a language not mentioned here, then I don't know it, and don't
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * know whether it works.  If it has a C-like, Bash-like, or XML-like syntax
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * then it should work passably.
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Usage:
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1) include this source file in an html page via
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <script type="text/javascript" src="/path/to/prettify.js"></script>
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2) define style rules.  See the example page for examples.
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 3) mark the <pre> and <code> tags in your source with class=prettyprint.
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *    You can also use the (html deprecated) <xmp> tag, but the pretty printer
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *    needs to do more substantial DOM manipulations to support that, so some
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *    css styles may not be preserved.
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * That's it.  I wanted to keep the API as simple as possible, so there's no
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * need to specify which language the code is in.
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Change log:
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * cbeust, 2006/08/22
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   Java annotations (start with "@") are now captured as literals ("lit")
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// JSLint declarations
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*global console, document, navigator, setTimeout, window */
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * UI events.
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If set to {@code false}, {@code prettyPrint()} is synchronous.
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar PR_SHOULD_USE_CONTINUATION = true;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** the number of characters between tab columns */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar PR_TAB_WIDTH = 8;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** Walks the DOM returning a properly escaped version of innerHTML.
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @param {Node} node
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @param {Array.<string>} out output buffer that receives chunks of HTML.
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  */
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar PR_normalizedHtml;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** Contains functions for creating and registering new language handlers.
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @type {Object}
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  */
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar PR;
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** Pretty print a chunk of code.
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  *
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @param {string} sourceCodeHtml code as html
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @return {string} code as html, but prettier
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  */
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar prettyPrintOne;
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** find all the < pre > and < code > tags in the DOM with class=prettyprint
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * and prettify them.
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  * @param {Function} opt_whenDone if specified, called when the last entry
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  *     has been finished.
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  */
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvar prettyPrint;
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** browser detection. @extern */
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfunction _pr_isIE6() {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var isIE6 = navigator && navigator.userAgent &&
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      /\bMSIE 6\./.test(navigator.userAgent);
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  _pr_isIE6 = function () { return isIE6; };
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  return isIE6;
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project(function () {
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** Splits input on space and returns an Object mapping each non-empty part to
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * true.
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function wordSet(words) {
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    words = words.split(/ /g);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var set = {};
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = words.length; --i >= 0;) {
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var w = words[i];
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (w) { set[w] = null; }
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return set;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // Keyword lists for various languages.
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var FLOW_CONTROL_KEYWORDS =
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "break continue do else for if return while ";
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "double enum extern float goto int long register short signed sizeof " +
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "static struct switch typedef union unsigned void volatile ";
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "new operator private protected public this throw true try ";
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "concept concept_map const_cast constexpr decltype " +
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "dynamic_cast explicit export friend inline late_check " +
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "template typeid typename typeof using virtual wchar_t where ";
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var JAVA_KEYWORDS = COMMON_KEYWORDS +
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "boolean byte extends final finally implements import instanceof null " +
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "native package strictfp super synchronized throws transient ";
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "as base by checked decimal delegate descending event " +
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "fixed foreach from group implicit in interface internal into is lock " +
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "object out override orderby params readonly ref sbyte sealed " +
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "stackalloc string select uint ulong unchecked unsafe ushort var ";
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "debugger eval export function get null set undefined var with " +
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "Infinity NaN ";
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "goto if import last local my next no our print package redo require " +
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "sub undef unless until use wantarray while BEGIN END ";
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "elif except exec finally from global import in is lambda " +
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "nonlocal not or pass print raise try with yield " +
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "False True None ";
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      " defined elsif end ensure false in module next nil not or redo rescue " +
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "retry self super then true undef unless until when yield BEGIN END ";
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      "function in local set then until ";
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var ALL_KEYWORDS = (
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // token style names.  correspond to css classes
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a string literal */
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_STRING = 'str';
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a keyword */
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_KEYWORD = 'kwd';
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a comment */
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_COMMENT = 'com';
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a type */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_TYPE = 'typ';
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a literal value.  e.g. 1, null, true. */
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_LITERAL = 'lit';
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a punctuation string. */
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_PUNCTUATION = 'pun';
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a punctuation string. */
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_PLAIN = 'pln';
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for an sgml tag. */
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_TAG = 'tag';
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for a markup declaration such as a DOCTYPE. */
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_DECLARATION = 'dec';
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for embedded source. */
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_SOURCE = 'src';
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for an sgml attribute name. */
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_ATTRIB_NAME = 'atn';
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** token style for an sgml attribute value. */
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_ATTRIB_VALUE = 'atv';
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /**
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   * A class that indicates a section of markup that is not code, e.g. to allow
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   * embedding of line numbers within code listings.
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project   */
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_NOCODE = 'nocode';
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function isWordChar(ch) {
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** Splice one array into another.
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Like the python <code>
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * container[containerPosition:containerPosition + countReplaced] = inserted
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * </code>
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array} inserted
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array} container modified in place
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Number} containerPosition
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Number} countReplaced
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function spliceArrayInto(
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      inserted, container, containerPosition, countReplaced) {
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    inserted.unshift(containerPosition, countReplaced || 0);
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    try {
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      container.splice.apply(container, inserted);
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } finally {
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      inserted.splice(0, 2);
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** A set of tokens that can precede a regular expression literal in
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * javascript.
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * list, but I've removed ones that might be problematic when seen in
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * languages that don't support regular expression literals.
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <p>Specifically, I've removed any keywords that can't precede a regexp
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * literal in a syntactically legal javascript program, and I've removed the
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * "in" keyword since it's not a keyword in many languages, and might be used
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * as a count of inches.
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var REGEXP_PRECEDER_PATTERN = function () {
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var preceders = [
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "||=", "~" /* handles =~ and !~ */,
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "break", "case", "continue", "delete",
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "do", "else", "finally", "instanceof",
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          "return", "throw", "try", "typeof"
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          ];
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var pattern = '(?:' +
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          '(?:(?:^|[^0-9.])\\.{1,3})|' +  // a dot that's not part of a number
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          '(?:(?:^|[^\\+])\\+)|' +  // allow + but not ++
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          '(?:(?:^|[^\\-])-)';  // allow - but not --
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var i = 0; i < preceders.length; ++i) {
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var preceder = preceders[i];
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isWordChar(preceder.charAt(0))) {
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          pattern += '|\\b' + preceder;
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          pattern += '|' + preceder.replace(/([^=<>:&])/g, '\\$1');
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      pattern += '|^)\\s*$';  // matches at end, and matches empty string
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return new RegExp(pattern);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // CAVEAT: this does not properly handle the case where a regular
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // expression immediately follows another since a regular expression may
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // have flags for case-sensitivity and the like.  Having regexp tokens
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // adjacent is not
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // valid in any language I'm aware of, so I'm punting.
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // TODO: maybe style special characters inside a regexp as punctuation.
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }();
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // Define regexps here so that the interpreter doesn't have to create an
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // object each time the function containing them is called.
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // The language spec requires a new object created even if you don't access
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // the $1 members.
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_amp = /&/g;
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_lt = /</g;
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_gt = />/g;
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_quot = /\"/g;
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** like textToHtml but escapes double quotes to be attribute safe. */
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function attribToHtml(str) {
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return str.replace(pr_amp, '&amp;')
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_lt, '&lt;')
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_gt, '&gt;')
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_quot, '&quot;');
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** escapest html special characters to html. */
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function textToHtml(str) {
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return str.replace(pr_amp, '&amp;')
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_lt, '&lt;')
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_gt, '&gt;');
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_ltEnt = /&lt;/g;
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_gtEnt = /&gt;/g;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_aposEnt = /&apos;/g;
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_quotEnt = /&quot;/g;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_ampEnt = /&amp;/g;
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_nbspEnt = /&nbsp;/g;
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** unescapes html to plain text. */
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function htmlToText(html) {
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var pos = html.indexOf('&');
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pos < 0) { return html; }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // Handle numeric entities specially.  We can't use functional substitution
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // since that doesn't work in older versions of Safari.
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // These should be rare since most browsers convert them to normal chars.
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var end = html.indexOf(';', pos);
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (end >= 0) {
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var num = html.substring(pos + 3, end);
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var radix = 10;
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (num && num.charAt(0) === 'x') {
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          num = num.substring(1);
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          radix = 16;
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var codePoint = parseInt(num, radix);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!isNaN(codePoint)) {
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  html.substring(end + 1));
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return html.replace(pr_ltEnt, '<')
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_gtEnt, '>')
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_aposEnt, "'")
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_quotEnt, '"')
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_ampEnt, '&')
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(pr_nbspEnt, ' ');
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** is the given node's innerHTML normally unescaped? */
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function isRawContent(node) {
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return 'XMP' === node.tagName;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function normalizedHtml(node, out) {
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    switch (node.nodeType) {
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      case 1:  // an element
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var name = node.tagName.toLowerCase();
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.push('<', name);
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (var i = 0; i < node.attributes.length; ++i) {
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attr = node.attributes[i];
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (!attr.specified) { continue; }
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          out.push(' ');
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          normalizedHtml(attr, out);
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.push('>');
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (var child = node.firstChild; child; child = child.nextSibling) {
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          normalizedHtml(child, out);
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          out.push('<\/', name, '>');
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      case 2: // an attribute
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      case 3: case 4: // text
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.push(textToHtml(node.nodeValue));
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_innerHtmlWorks = null;
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function getInnerHtml(node) {
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // inner html is hopelessly broken in Safari 2.0.4 when the content is
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // an html description of well formed XML and the containing tag is a PRE
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // tag, so we detect that case and emulate innerHTML.
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (null === PR_innerHtmlWorks) {
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var testNode = document.createElement('PRE');
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      testNode.appendChild(
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (PR_innerHtmlWorks) {
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var content = node.innerHTML;
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // XMP tags contain unescaped entities so require special handling.
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (isRawContent(node)) {
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        content = textToHtml(content);
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return content;
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var out = [];
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var child = node.firstChild; child; child = child.nextSibling) {
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      normalizedHtml(child, out);
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return out.join('');
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** returns a function that expand tabs to spaces.  This function can be fed
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * successive chunks of text, and will maintain its own internal state to
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * keep track of how tabs are expanded.
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return {function (string) : string} a function that takes
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   plain text and return the text with tabs expanded.
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function makeTabExpander(tabWidth) {
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var SPACES = '                ';
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var charInLine = 0;
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return function (plainText) {
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // walk over each character looking for tabs and newlines.
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // On tabs, expand them.  On newlines, reset charInLine.
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Otherwise increment charInLine
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var out = null;
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var pos = 0;
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var i = 0, n = plainText.length; i < n; ++i) {
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var ch = plainText.charAt(i);
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        switch (ch) {
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          case '\t':
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!out) { out = []; }
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.push(plainText.substring(pos, i));
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // calculate how much space we need in front of this part
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // nSpaces is the amount of padding -- the number of spaces needed
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // to move us to the next column, where columns occur at factors of
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // tabWidth.
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            var nSpaces = tabWidth - (charInLine % tabWidth);
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            charInLine += nSpaces;
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              out.push(SPACES.substring(0, nSpaces));
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pos = i + 1;
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          case '\n':
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            charInLine = 0;
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          default:
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ++charInLine;
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (!out) { return plainText; }
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      out.push(plainText.substring(pos));
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return out.join('');
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // The below pattern matches one of the following
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // (1) /[^<]+/ : A run of characters other than '<'
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // (2) /<!--.*?-->/: an HTML comment
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // (3) /<!\[CDATA\[.*?\]\]>/: a cdata section
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // (3) /<\/?[a-zA-Z][^>]*>/ : A probably tag that should not be highlighted
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // (4) /</ : A '<' that does not begin a larger chunk.  Treated as 1
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_chunkPattern =
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /(?:[^<]+|<!--[\s\S]*?-->|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g;
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_commentPrefix = /^<!--/;
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_cdataPrefix = /^<\[CDATA\[/;
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_brPrefix = /^<br\b/i;
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var pr_tagNameRe = /^<(\/?)([a-zA-Z]+)/;
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** split markup into chunks of html tags (style null) and
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * plain text (style {@link #PR_PLAIN}), converting tags which are
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * significant for tokenization (<br>) into their textual equivalent.
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {string} s html where whitespace is considered significant.
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return {Object} source code and extracted tags.
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function extractTags(s) {
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // since the pattern has the 'g' modifier and defines no capturing groups,
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // this will return a list of all chunks which we then classify and wrap as
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // PR_Tokens
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var matches = s.match(pr_chunkPattern);
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var sourceBuf = [];
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var sourceBufLen = 0;
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var extractedTags = [];
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (matches) {
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var i = 0, n = matches.length; i < n; ++i) {
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var match = matches[i];
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (match.length > 1 && match.charAt(0) === '<') {
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (pr_commentPrefix.test(match)) { continue; }
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (pr_cdataPrefix.test(match)) {
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sourceBuf.push(match.substring(9, match.length - 3));
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sourceBufLen += match.length - 12;
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          } else if (pr_brPrefix.test(match)) {
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // <br> tags are lexically significant so convert them to text.
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // This is undone later.
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sourceBuf.push('\n');
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ++sourceBufLen;
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          } else {
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // A <span class="nocode"> will start a section that should be
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // ignored.  Continue walking the list until we see a matching end
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // tag.
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var name = match.match(pr_tagNameRe)[2];
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var depth = 1;
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              end_tag_loop:
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              for (var j = i + 1; j < n; ++j) {
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                var name2 = matches[j].match(pr_tagNameRe);
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (name2 && name2[2] === name) {
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  if (name2[1] === '/') {
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (--depth === 0) { break end_tag_loop; }
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  } else {
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ++depth;
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  }
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              }
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              if (j < n) {
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                extractedTags.push(
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    sourceBufLen, matches.slice(i, j + 1).join(''));
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                i = j;
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              } else {  // Ignore unclosed sections.
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                extractedTags.push(sourceBufLen, match);
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              }
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              extractedTags.push(sourceBufLen, match);
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var literalText = htmlToText(match);
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          sourceBuf.push(literalText);
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          sourceBufLen += literalText.length;
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return { source: sourceBuf.join(''), tags: extractedTags };
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** True if the given tag contains a class attribute with the nocode class. */
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function isNoCodeTag(tag) {
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return !!tag
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // First canonicalize the representation of attributes
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 ' $1="$2$3$4"')
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Then look for the attribute we want.
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** Given triples of [style, pattern, context] returns a lexing function,
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * The lexing function interprets the patterns to find token boundaries and
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * returns a decoration list of the form
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * where index_n is an index into the sourceCode, and style_n is a style
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * all characters in sourceCode[index_n-1:index_n].
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * The stylePatterns is a list whose elements have the form
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * [style : string, pattern : RegExp, context : RegExp, shortcut : string].
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    &
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Style is a style constant like PR_PLAIN.
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Pattern must only match prefixes, and if it matches a prefix and context
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * is null or matches the last non-comment token parsed, then that match is
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * considered a token with the same style.
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Context is applied to the last non-whitespace, non-comment token
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * recognized.
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * Shortcut is an optional string of characters, any of which, if the first
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * character, gurantee that this pattern and only this pattern matches.
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array} shortcutStylePatterns patterns that always start with
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   a known character.  Must have a shortcut string.
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array} fallthroughStylePatterns patterns that will be tried in
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   order if the shortcut ones fail.  May have shortcuts.
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return {function (string, number?) : Array.<number|string>} a
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   function that takes source code and returns a list of decorations.
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function createSimpleLexer(shortcutStylePatterns,
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                             fallthroughStylePatterns) {
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var shortcuts = {};
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    (function () {
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var i = allPatterns.length; --i >= 0;) {
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var patternParts = allPatterns[i];
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var shortcutChars = patternParts[3];
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (shortcutChars) {
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          for (var c = shortcutChars.length; --c >= 0;) {
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            shortcuts[shortcutChars.charAt(c)] = patternParts;
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    })();
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var nPatterns = fallthroughStylePatterns.length;
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var notWs = /\S/;
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return function (sourceCode, opt_basePos) {
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      opt_basePos = opt_basePos || 0;
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var decorations = [opt_basePos, PR_PLAIN];
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var lastToken = '';
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var pos = 0;  // index into sourceCode
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var tail = sourceCode;
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      while (tail.length) {
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var style;
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var token = null;
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var match;
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var patternParts = shortcuts[tail.charAt(0)];
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (patternParts) {
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          match = tail.match(patternParts[1]);
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          token = match[0];
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          style = patternParts[0];
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          for (var i = 0; i < nPatterns; ++i) {
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            patternParts = fallthroughStylePatterns[i];
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            var contextPattern = patternParts[2];
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (contextPattern && !contextPattern.test(lastToken)) {
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // rule can't be used
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              continue;
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            match = tail.match(patternParts[1]);
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (match) {
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              token = match[0];
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              style = patternParts[0];
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              break;
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (!token) {  // make sure that we make progress
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            style = PR_PLAIN;
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            token = tail.substring(0, 1);
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        decorations.push(opt_basePos + pos, style);
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pos += token.length;
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tail = tail.substring(token.length);
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (style !== PR_COMMENT && notWs.test(token)) { lastToken = token; }
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return decorations;
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_MARKUP_LEXER = createSimpleLexer([], [
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_PLAIN,       /^[^<]+/, null],
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/, null],
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_COMMENT,     /^<!--[\s\S]*?(?:-->|$)/, null],
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_SOURCE,      /^<\?[\s\S]*?(?:\?>|$)/, null],
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_SOURCE,      /^<%[\s\S]*?(?:%>|$)/, null],
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_SOURCE,
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project       // Tags whose content is not escaped, and which contain source code.
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project       /^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i, null],
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_TAG,         /^<\/?\w[^<>]*>/, null]
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ]);
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // Splits any of the source|style|xmp entries above into a start tag,
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  // source content, and end tag.
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_SOURCE_CHUNK_PARTS = /^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/;
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** split markup on tags, comments, application directives, and other top
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * level constructs.  Tags are returned as a single token - attributes are
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * not yet broken out.
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function tokenizeMarkup(source) {
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var decorations = PR_MARKUP_LEXER(source);
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = 0; i < decorations.length; i += 2) {
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (decorations[i + 1] === PR_SOURCE) {
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var start, end;
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = decorations[i];
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Split out start and end script tags as actual tags, and leave the
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // body with style SCRIPT.
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var sourceChunk = source.substring(start, end);
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var match = sourceChunk.match(PR_SOURCE_CHUNK_PARTS);
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (match) {
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          decorations.splice(
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              i, 2,
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              start, PR_TAG,  // the open chunk
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              start + match[1].length, PR_SOURCE,
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              start + match[1].length + (match[2] || '').length, PR_TAG);
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return decorations;
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var PR_TAG_LEXER = createSimpleLexer([
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_ATTRIB_VALUE, /^\'[^\']*(?:\'|$)/, null, "'"],
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_ATTRIB_VALUE, /^\"[^\"]*(?:\"|$)/, null, '"'],
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_PUNCTUATION,  /^[<>\/=]+/, null, '<>/=']
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ], [
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_TAG,          /^[\w:\-]+/, /^</],
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_ATTRIB_VALUE, /^[\w\-]+/, /^=/],
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_ATTRIB_NAME,  /^[\w:\-]+/, null],
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      [PR_PLAIN,        /^\s+/, null, ' \t\r\n']
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ]);
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** split tags attributes and their values out from the tag name, and
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * recursively lex source chunks.
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function splitTagAttributes(source, decorations) {
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = 0; i < decorations.length; i += 2) {
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var style = decorations[i + 1];
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (style === PR_TAG) {
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var start, end;
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = decorations[i];
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var chunk = source.substring(start, end);
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var subDecorations = PR_TAG_LEXER(chunk, start);
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        spliceArrayInto(subDecorations, decorations, i, 2);
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        i += subDecorations.length - 2;
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return decorations;
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** returns a function that produces a list of decorations from source text.
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * This code treats ", ', and ` as string delimiters, and \ as a string
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * escape.  It does not recognize perl's qq() style strings.
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * It has no special handling for double delimiter escapes as in basic, or
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * the tripled delimiters used in python, but should work on those regardless
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * although in those cases a single string literal may be broken up into
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * multiple adjacent string literals.
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * It recognizes C, C++, and shell style comments.
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Object} options a set of optional parameters.
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return {function (string) : Array.<string|number>} a
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *     decorator that takes sourceCode as plain text and that returns a
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *     decoration list
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function sourceDecorator(options) {
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (options.tripleQuotedStrings) {
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // '''multi-line-string''', 'single-line-string', and double-quoted
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      shortcutStylePatterns.push(
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project           null, '\'"']);
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else if (options.multiLineStrings) {
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // 'multi-line-string', "multi-line-string"
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      shortcutStylePatterns.push(
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project           null, '\'"`']);
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // 'single-line-string', "single-line-string"
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      shortcutStylePatterns.push(
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          [PR_STRING,
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project           null, '"\'']);
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    fallthroughStylePatterns.push(
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_PLAIN,   /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']);
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (options.hashComments) {
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (options.cStyleComments) {
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      fallthroughStylePatterns.push(
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (options.regexLiterals) {
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var REGEX_LITERAL = (
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // A regular expression literal starts with a slash that is
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // not followed by * or / so that it is not confused with
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // comments.
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          '^/(?=[^/*])'
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // and then contains any number of raw characters,
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          + '(?:[^/\\x5B\\x5C]'
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // escape sequences (\x5C),
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          +    '|\\x5C[\\s\\S]'
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // or non-nesting character sets (\x5B\x5D);
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // finally closed by a /.
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          + '(?:/|$)');
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      fallthroughStylePatterns.push(
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          [PR_STRING, new RegExp(REGEX_LITERAL), REGEXP_PRECEDER_PATTERN]);
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var keywords = wordSet(options.keywords);
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    options = null;
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** splits the given string into comment, string, and "other" tokens.
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      * @param {string} sourceCode as plain text
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      * @return {Array.<number|string>} a decoration list.
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      * @private
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      */
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var splitStringAndCommentTokens = createSimpleLexer(
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        shortcutStylePatterns, fallthroughStylePatterns);
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_PLAIN,       /^\s+/, null, ' \r\n'],
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_PLAIN,       /^[a-z_$@][a-z_$@0-9]*/i, null],
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // A hex number
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_LITERAL,     /^0x[a-f0-9]+[a-z]/i, null],
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // An octal or decimal number, possibly in scientific notation
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_LITERAL,
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i,
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         null, '123456789'],
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null]
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Fallback will handle decimal points not adjacent to a digit
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      ]);
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** splits plain text tokens into more specific tokens, and then tries to
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      * recognize keywords, and types.
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      * @private
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      */
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    function splitNonStringNonCommentTokens(source, decorations) {
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var i = 0; i < decorations.length; i += 2) {
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var style = decorations[i + 1];
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (style === PR_PLAIN) {
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var start, end, chunk, subDecs;
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          start = decorations[i];
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          chunk = source.substring(start, end);
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start);
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          for (var j = 0, m = subDecs.length; j < m; j += 2) {
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            var subStyle = subDecs[j + 1];
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subStyle === PR_PLAIN) {
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var subStart = subDecs[j];
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length;
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var token = source.substring(subStart, subEnd);
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              if (token === '.') {
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subDecs[j + 1] = PR_PUNCTUATION;
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              } else if (token in keywords) {
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subDecs[j + 1] = PR_KEYWORD;
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) {
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // classify types and annotations using Java's style conventions
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE;
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              }
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          spliceArrayInto(subDecs, decorations, i, 2);
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          i += subDecs.length - 2;
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return decorations;
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return function (sourceCode) {
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Split into strings, comments, and other.
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // We do this because strings and comments are easily recognizable and can
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // contain stuff that looks like other tokens, so we want to mark those
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // early so we don't recurse into them.
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var decorations = splitStringAndCommentTokens(sourceCode);
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Split non comment|string tokens on whitespace and word boundaries
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      decorations = splitNonStringNonCommentTokens(sourceCode, decorations);
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return decorations;
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var decorateSource = sourceDecorator({
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        keywords: ALL_KEYWORDS,
823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hashComments: true,
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cStyleComments: true,
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        multiLineStrings: true,
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        regexLiterals: true
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      });
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** identify regions of markup that are really source code, and recursivley
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * lex them.
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function splitSourceNodes(source, decorations) {
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = 0; i < decorations.length; i += 2) {
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var style = decorations[i + 1];
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (style === PR_SOURCE) {
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Recurse using the non-markup lexer
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var start, end;
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = decorations[i];
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var subDecorations = decorateSource(source.substring(start, end));
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (var j = 0, m = subDecorations.length; j < m; j += 2) {
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          subDecorations[j] += start;
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        spliceArrayInto(subDecorations, decorations, i, 2);
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        i += subDecorations.length - 2;
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return decorations;
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** identify attribute values that really contain source code and recursively
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * lex them.
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function splitSourceAttributes(source, decorations) {
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var nextValueIsSource = false;
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = 0; i < decorations.length; i += 2) {
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var style = decorations[i + 1];
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var start, end;
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (style === PR_ATTRIB_NAME) {
862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = decorations[i];
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        nextValueIsSource = /^on|^style$/i.test(source.substring(start, end));
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else if (style === PR_ATTRIB_VALUE) {
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (nextValueIsSource) {
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          start = decorations[i];
868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribValue = source.substring(start, end);
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribLen = attribValue.length;
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var quoted =
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              (attribLen >= 2 && /^[\"\']/.test(attribValue) &&
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project               attribValue.charAt(0) === attribValue.charAt(attribLen - 1));
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribSource;
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribSourceStart;
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribSourceEnd;
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (quoted) {
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceStart = start + 1;
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceEnd = end - 1;
881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSource = attribValue;
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          } else {
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceStart = start + 1;
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceEnd = end - 1;
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSource = attribValue.substring(1, attribValue.length - 1);
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var attribSourceDecorations = decorateSource(attribSource);
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          for (var j = 0, m = attribSourceDecorations.length; j < m; j += 2) {
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceDecorations[j] += attribSourceStart;
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (quoted) {
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribSourceDecorations.push(attribSourceEnd, PR_ATTRIB_VALUE);
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            spliceArrayInto(attribSourceDecorations, decorations, i + 2, 0);
896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          } else {
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            spliceArrayInto(attribSourceDecorations, decorations, i, 2);
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        nextValueIsSource = false;
901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return decorations;
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** returns a decoration list given a string of markup.
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * This code recognizes a number of constructs.
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <!-- ... --> comment
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <!\w ... >   declaration
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <\w ... >    tag
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * </\w ... >   tag
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <?...?>      embedded source
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * <%...%>      embedded source
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * &[#\w]...;   entity
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * It does not recognizes %foo; doctype entities from  .
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * It will recurse into any <style>, <script>, and on* attributes using
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * PR_lexSource.
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function decorateMarkup(sourceCode) {
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // This function works as follows:
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // 1) Start by splitting the markup into text and tag chunks
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Input:  string s
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Output: List<PR_Token> where style in (PR_PLAIN, null)
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // 2) Then split the text chunks further into comments, declarations,
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    tags, etc.
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    After each split, consider whether the token is the start of an
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    embedded source section, i.e. is an open <script> tag.  If it is, find
931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    the corresponding close token, and don't bother to lex in between.
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Input:  List<string>
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Output: List<PR_Token> with style in
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //            (PR_TAG, PR_PLAIN, PR_SOURCE, null)
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // 3) Finally go over each tag token and split out attribute names and
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    values.
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Input:  List<PR_Token>
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //    Output: List<PR_Token> where style in
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //            (PR_TAG, PR_PLAIN, PR_SOURCE, NAME, VALUE, null)
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var decorations = tokenizeMarkup(sourceCode);
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    decorations = splitTagAttributes(sourceCode, decorations);
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    decorations = splitSourceNodes(sourceCode, decorations);
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    decorations = splitSourceAttributes(sourceCode, decorations);
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return decorations;
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /**
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {string} sourceText plain text
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array.<number|string>} extractedTags chunks of raw html preceded
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   by their position in sourceText in order.
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array.<number|string>} decorations style classes preceded by their
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *   position in sourceText in order.
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @return {string} html
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @private
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function recombineTagsAndDecorations(sourceText, extractedTags, decorations) {
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var html = [];
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // index past the last char in sourceText written to html
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var outputIdx = 0;
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var openDecoration = null;
962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var currentDecoration = null;
963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var tagPos = 0;  // index into extractedTags
964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var decPos = 0;  // index into decorations
965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var tabExpander = makeTabExpander(PR_TAB_WIDTH);
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var adjacentSpaceRe = /([\r\n ]) /g;
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var startOrSpaceRe = /(^| ) /gm;
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var newlineRe = /\r\n?|\n/g;
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var trailingSpaceRe = /[ \r\n]$/;
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
972de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // A helper function that is responsible for opening sections of decoration
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // and outputing properly escaped chunks of source
975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    function emitTextUpTo(sourceIdx) {
976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (sourceIdx > outputIdx) {
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (openDecoration && openDecoration !== currentDecoration) {
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // Close the current decoration
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          html.push('</span>');
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          openDecoration = null;
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!openDecoration && currentDecoration) {
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          openDecoration = currentDecoration;
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          html.push('<span class="', openDecoration, '">');
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This interacts badly with some wikis which introduces paragraph tags
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // into pre blocks for some strange reason.
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // It's necessary for IE though which seems to lose the preformattedness
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // of <pre> tags when their innerHTML is assigned.
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // and it serves to undo the conversion of <br>s to newlines done in
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // chunkify.
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var htmlChunk = textToHtml(
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            .replace(lastWasSpace
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     ? startOrSpaceRe
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     : adjacentSpaceRe, '$1&nbsp;');
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Keep track of whether we need to escape space at the beginning of the
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // next chunk.
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        lastWasSpace = trailingSpaceRe.test(htmlChunk);
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        html.push(htmlChunk.replace(newlineRe, '<br />'));
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        outputIdx = sourceIdx;
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (true) {
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Determine if we're going to consume a tag this time around.  Otherwise
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // we consume a decoration or exit.
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var outputTag;
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (tagPos < extractedTags.length) {
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (decPos < decorations.length) {
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // Pick one giving preference to extractedTags since we shouldn't open
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // a new style that we're going to have to immediately close in order
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // to output a tag.
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          outputTag = extractedTags[tagPos] <= decorations[decPos];
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          outputTag = true;
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else {
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        outputTag = false;
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Consume either a decoration or a tag or exit.
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (outputTag) {
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        emitTextUpTo(extractedTags[tagPos]);
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (openDecoration) {
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // Close the current decoration
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          html.push('</span>');
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          openDecoration = null;
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        html.push(extractedTags[tagPos + 1]);
1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tagPos += 2;
1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else if (decPos < decorations.length) {
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        emitTextUpTo(decorations[decPos]);
1034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        currentDecoration = decorations[decPos + 1];
1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        decPos += 2;
1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else {
1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    emitTextUpTo(sourceText.length);
1041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (openDecoration) {
1042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      html.push('</span>');
1043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return html.join('');
1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** Maps language-specific file extensions to handlers. */
1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  var langHandlerRegistry = {};
1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  /** Register a language handler for the given file extensions.
1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {function (string) : Array.<number|string>} handler
1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *     a function from source code to a list of decorations.
1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    * @param {Array.<string>} fileExtensions
1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    */
1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function registerLangHandler(handler, fileExtensions) {
1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = fileExtensions.length; --i >= 0;) {
1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var ext = fileExtensions[i];
1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (!langHandlerRegistry.hasOwnProperty(ext)) {
1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        langHandlerRegistry[ext] = handler;
1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else if ('console' in window) {
1061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        console.log('cannot override language handler %s', ext);
1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(decorateSource, ['default-code']);
1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(decorateMarkup,
1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                      ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']);
1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: CPP_KEYWORDS,
1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          cStyleComments: true
1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['c', 'cc', 'cpp', 'cxx', 'cyc']);
1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: CSHARP_KEYWORDS,
1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          cStyleComments: true
1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['cs']);
1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: JAVA_KEYWORDS,
1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          cStyleComments: true
1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['java']);
1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: SH_KEYWORDS,
1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          multiLineStrings: true
1086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['bsh', 'csh', 'sh']);
1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: PYTHON_KEYWORDS,
1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          multiLineStrings: true,
1091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          tripleQuotedStrings: true
1092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['cv', 'py']);
1093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: PERL_KEYWORDS,
1095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          multiLineStrings: true,
1097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          regexLiterals: true
1098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['perl', 'pl', 'pm']);
1099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: RUBY_KEYWORDS,
1101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          hashComments: true,
1102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          multiLineStrings: true,
1103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          regexLiterals: true
1104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['rb']);
1105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  registerLangHandler(sourceDecorator({
1106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          keywords: JSCRIPT_KEYWORDS,
1107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          cStyleComments: true,
1108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          regexLiterals: true
1109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }), ['js']);
1110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
1112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    try {
1113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Extract tags, and convert the source code to plain text.
1114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
1115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      /** Plain text. @type {string} */
1116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var source = sourceAndExtractedTags.source;
1117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      /** Even entries are positions in source in ascending order.  Odd entries
1119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        * are tags that were extracted at that position.
1120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        * @type {Array.<number|string>}
1121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        */
1122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var extractedTags = sourceAndExtractedTags.tags;
1123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Pick a lexer and apply it.
1125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (!langHandlerRegistry.hasOwnProperty(opt_langExtension)) {
1126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Treat it as markup if the first non whitespace character is a < and
1127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // the last non-whitespace character is a >.
1128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opt_langExtension =
1129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /^\s*</.test(source) ? 'default-markup' : 'default-code';
1130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      /** Even entries are positions in source in ascending order.  Odd enties
1133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        * are style markers (e.g., PR_COMMENT) that run from that position until
1134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        * the end.
1135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        * @type {Array.<number|string>}
1136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        */
1137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var decorations = langHandlerRegistry[opt_langExtension].call({}, source);
1138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // Integrate the decorations and tags back into the source code to produce
1140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      // a decorated html string.
1141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return recombineTagsAndDecorations(source, extractedTags, decorations);
1142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } catch (e) {
1143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if ('console' in window) {
1144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        console.log(e);
1145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        console.trace();
1146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      return sourceCodeHtml;
1148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
1150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  function prettyPrint(opt_whenDone) {
1152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var isIE6 = _pr_isIE6();
1153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // fetch a list of nodes to rewrite
1155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var codeSegments = [
1156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        document.getElementsByTagName('pre'),
1157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        document.getElementsByTagName('code'),
1158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        document.getElementsByTagName('xmp') ];
1159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var elements = [];
1160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (var i = 0; i < codeSegments.length; ++i) {
1161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (var j = 0; j < codeSegments[i].length; ++j) {
1162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        elements.push(codeSegments[i][j]);
1163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    codeSegments = null;
1166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // the loop is broken into a series of continuations to make sure that we
1168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // don't make the browser unresponsive when rewriting a large page.
1169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    var k = 0;
1170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    function doWork() {
1172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      var endTime = (PR_SHOULD_USE_CONTINUATION ?
1173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     new Date().getTime() + 250 /* ms */ :
1174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     Infinity);
1175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      for (; k < elements.length && new Date().getTime() < endTime; k++) {
1176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        var cs = elements[k];
1177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
1178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // If the classes includes a language extensions, use it.
1179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // Language extensions can be specified like
1180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          //     <pre class="prettyprint lang-cpp">
1181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // the language extension "cpp" is used to find a language handler as
1182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // passed to PR_registerLangHandler.
1183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var langExtension = cs.className.match(/\blang-(\w+)\b/);
1184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (langExtension) { langExtension = langExtension[1]; }
1185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          // make sure this is not nested in an already prettified element
1187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          var nested = false;
1188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          for (var p = cs.parentNode; p; p = p.parentNode) {
1189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((p.tagName === 'pre' || p.tagName === 'code' ||
1190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 p.tagName === 'xmp') &&
1191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                p.className && p.className.indexOf('prettyprint') >= 0) {
1192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              nested = true;
1193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              break;
1194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
1196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          if (!nested) {
1197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // fetch the content as a snippet of properly escaped HTML.
1198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Firefox adds newlines at the end.
1199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            var content = getInnerHtml(cs);
1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            content = content.replace(/(?:\r\n?|\n)$/, '');
1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // do the pretty printing
1203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            var newContent = prettyPrintOne(content, langExtension);
1204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // push the prettified html back into the tag.
1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!isRawContent(cs)) {
1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // just replace the old html with the new
1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              cs.innerHTML = newContent;
1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // we need to change the tag to a <pre> since <xmp>s do not allow
1211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // embedded tags such as the span tags used to attach styles to
1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // sections of source code.
1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var pre = document.createElement('PRE');
1214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              for (var i = 0; i < cs.attributes.length; ++i) {
1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                var a = cs.attributes[i];
1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (a.specified) {
1217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  var aname = a.name.toLowerCase();
1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  if (aname === 'class') {
1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pre.className = a.value;  // For IE 6
1220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  } else {
1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pre.setAttribute(a.name, a.value);
1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  }
1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              }
1225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              pre.innerHTML = newContent;
1226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              // remove the old
1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              cs.parentNode.replaceChild(pre, cs);
1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              cs = pre;
1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Replace <br>s with line-feeds so that copying and pasting works
1233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // on IE 6.
1234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Doing this on other browsers breaks lots of stuff since \r\n is
1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // treated as two newlines on Firefox, and doing this also slows
1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // down rendering.
1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isIE6 && cs.tagName === 'PRE') {
1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              var lineBreaks = cs.getElementsByTagName('br');
1239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              for (var j = lineBreaks.length; --j >= 0;) {
1240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                var lineBreak = lineBreaks[j];
1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                lineBreak.parentNode.replaceChild(
1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    document.createTextNode('\r\n'), lineBreak);
1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project              }
1244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project          }
1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      if (k < elements.length) {
1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // finish up in a continuation
1250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setTimeout(doWork, 250);
1251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      } else if (opt_whenDone) {
1252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opt_whenDone();
1253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      }
1254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    doWork();
1257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  }
1258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  window['PR_normalizedHtml'] = normalizedHtml;
1260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  window['prettyPrintOne'] = prettyPrintOne;
1261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  window['prettyPrint'] = prettyPrint;
1262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project  window['PR'] = {
1263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'createSimpleLexer': createSimpleLexer,
1264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'registerLangHandler': registerLangHandler,
1265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'sourceDecorator': sourceDecorator,
1266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
1267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
1268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_COMMENT': PR_COMMENT,
1269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_DECLARATION': PR_DECLARATION,
1270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_KEYWORD': PR_KEYWORD,
1271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_LITERAL': PR_LITERAL,
1272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_NOCODE': PR_NOCODE,
1273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_PLAIN': PR_PLAIN,
1274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_PUNCTUATION': PR_PUNCTUATION,
1275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_SOURCE': PR_SOURCE,
1276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_STRING': PR_STRING,
1277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_TAG': PR_TAG,
1278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        'PR_TYPE': PR_TYPE
1279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project      };
1280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project})();
1281