utopia 1.9.2 → 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/.bowerrc +2 -2
  3. data/documentation/pages/_page.xnode +11 -0
  4. data/documentation/pages/wiki/controller/actions/content.md +76 -68
  5. data/documentation/pages/wiki/controller/rewrite/content.md +69 -64
  6. data/documentation/pages/wiki/controller.rb +6 -1
  7. data/documentation/pages/wiki/development-environment-setup/content.md +16 -14
  8. data/documentation/pages/wiki/server-setup/content.md +46 -40
  9. data/documentation/pages/wiki/show.xnode +1 -1
  10. data/documentation/pages/wiki/your-first-page/content.md +36 -31
  11. data/documentation/public/_components/jquery/core.js +482 -0
  12. data/documentation/public/_components/jquery/jquery.js +10220 -0
  13. data/documentation/public/_components/jquery/jquery.min.js +4 -0
  14. data/documentation/public/_components/jquery/jquery.min.map +1 -0
  15. data/documentation/public/_components/jquery/jquery.slim.js +8107 -0
  16. data/documentation/public/_components/jquery/jquery.slim.min.js +4 -0
  17. data/documentation/public/_components/jquery/jquery.slim.min.map +1 -0
  18. data/documentation/public/_components/jquery-syntax/.sass-cache/040afc1428b286fb3c50151378b349a6149698d3/jquery.syntax.core.sassc +0 -0
  19. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.editor.sassc +0 -0
  20. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.fixed.sassc +0 -0
  21. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.inline.sassc +0 -0
  22. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.list.sassc +0 -0
  23. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.plain.sassc +0 -0
  24. data/documentation/public/_components/jquery-syntax/.sass-cache/098642d80a1682613dca2bba6fd0a3bc9fd2bf04/jquery.syntax.layout.table.sassc +0 -0
  25. data/documentation/public/_components/jquery-syntax/.sass-cache/10c58b30c53bf84f8360af8a864797092be26882/jquery.syntax.core.sassc +0 -0
  26. data/documentation/public/_components/jquery-syntax/.sass-cache/10c58b30c53bf84f8360af8a864797092be26882/jquery.syntax.layout.fixed.sassc +0 -0
  27. data/documentation/public/_components/jquery-syntax/.sass-cache/10c58b30c53bf84f8360af8a864797092be26882/jquery.syntax.layout.inline.sassc +0 -0
  28. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/_layout.scssc +0 -0
  29. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.apache.sassc +0 -0
  30. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.applescript.sassc +0 -0
  31. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.assembly.sassc +0 -0
  32. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.bash-script.sassc +0 -0
  33. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.bash.sassc +0 -0
  34. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.clang.sassc +0 -0
  35. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.css.sassc +0 -0
  36. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.diff.sassc +0 -0
  37. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.html.sassc +0 -0
  38. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.ocaml.sassc +0 -0
  39. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.protobuf.sassc +0 -0
  40. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.python.sassc +0 -0
  41. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.ruby.sassc +0 -0
  42. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.brush.xml.sassc +0 -0
  43. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.core.sassc +0 -0
  44. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.editor.sassc +0 -0
  45. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.layout.editor.sassc +0 -0
  46. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.layout.fixed.sassc +0 -0
  47. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.layout.list.sassc +0 -0
  48. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.layout.plain.sassc +0 -0
  49. data/documentation/public/_components/jquery-syntax/.sass-cache/3c69ad94149e2a6d9f4ffda01814fee3947b1389/jquery.syntax.layout.table.sassc +0 -0
  50. data/documentation/public/_components/jquery-syntax/.sass-cache/8638ad407c5ea29f6547cf8ac6983da587354889/master.sassc +0 -0
  51. data/documentation/public/_components/jquery-syntax/.sass-cache/b7ab87e6269b4fe89f9475b7a260077391d3567b/jquery.syntax.layout.editor.sassc +0 -0
  52. data/documentation/public/_components/jquery-syntax/.sass-cache/b7ab87e6269b4fe89f9475b7a260077391d3567b/jquery.syntax.layout.fixed.sassc +0 -0
  53. data/documentation/public/_components/jquery-syntax/.sass-cache/b7ab87e6269b4fe89f9475b7a260077391d3567b/jquery.syntax.layout.inline.sassc +0 -0
  54. data/documentation/public/_components/jquery-syntax/.sass-cache/b7ab87e6269b4fe89f9475b7a260077391d3567b/jquery.syntax.layout.plain.sassc +0 -0
  55. data/documentation/public/_components/jquery-syntax/.sass-cache/e82f8cf4c8436da086a4506e01ef78755ebab1ce/master.scssc +0 -0
  56. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.apache.css +6 -0
  57. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.applescript.css +5 -0
  58. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.assembly.css +8 -0
  59. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.bash-script.css +6 -0
  60. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.bash.css +10 -0
  61. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.clang.css +3 -0
  62. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.css.css +14 -0
  63. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.diff.css +16 -0
  64. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.html.css +5 -0
  65. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.ocaml.css +3 -0
  66. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.protobuf.css +2 -0
  67. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.python.css +6 -0
  68. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.ruby.css +2 -0
  69. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.brush.xml.css +18 -0
  70. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.core.css +59 -0
  71. data/documentation/public/_components/jquery-syntax/base/jquery.syntax.editor.css +6 -0
  72. data/documentation/public/_components/jquery-syntax/base/theme.js +1 -0
  73. data/documentation/public/_components/jquery-syntax/bright/jquery.syntax.core.css +27 -0
  74. data/documentation/public/_components/jquery-syntax/bright/theme.js +1 -0
  75. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.apache.js +41 -0
  76. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.applescript.js +57 -0
  77. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.assembly.js +37 -0
  78. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.bash-script.js +67 -0
  79. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.bash.js +33 -0
  80. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.basic.js +51 -0
  81. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.clang.js +89 -0
  82. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.csharp.js +47 -0
  83. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.css.js +80 -0
  84. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.diff.js +24 -0
  85. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.go.js +47 -0
  86. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.haskell.js +45 -0
  87. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.html.js +66 -0
  88. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.io.js +45 -0
  89. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.java.js +45 -0
  90. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.javascript.js +40 -0
  91. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.kai.js +29 -0
  92. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.lisp.js +34 -0
  93. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.lua.js +44 -0
  94. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.nginx.js +31 -0
  95. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.ocaml.js +73 -0
  96. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.ooc.js +46 -0
  97. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.pascal.js +51 -0
  98. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.perl5.js +52 -0
  99. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.php-script.js +48 -0
  100. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.php.js +15 -0
  101. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.plain.js +10 -0
  102. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.protobuf.js +43 -0
  103. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.python.js +44 -0
  104. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.ruby.js +77 -0
  105. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.scala.js +44 -0
  106. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.smalltalk.js +29 -0
  107. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.sql.js +31 -0
  108. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.super-collider.js +57 -0
  109. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.swift.js +55 -0
  110. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.trenni.js +35 -0
  111. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.xml.js +50 -0
  112. data/documentation/public/_components/jquery-syntax/jquery.syntax.brush.yaml.js +29 -0
  113. data/documentation/public/_components/jquery-syntax/jquery.syntax.cache.js +65 -0
  114. data/documentation/public/_components/jquery-syntax/jquery.syntax.core.js +1098 -0
  115. data/documentation/public/_components/jquery-syntax/jquery.syntax.editor.js +291 -0
  116. data/documentation/public/_components/jquery-syntax/jquery.syntax.js +258 -0
  117. data/documentation/public/_components/jquery-syntax/jquery.syntax.min.js +13 -0
  118. data/documentation/public/_components/jquery-syntax/paper/jquery.syntax.core.css +31 -0
  119. data/documentation/public/_components/jquery-syntax/paper/theme.js +1 -0
  120. data/documentation/public/_static +1 -0
  121. data/documentation/tasks +1 -0
  122. data/lib/utopia/command.rb +1 -1
  123. data/lib/utopia/controller/actions.rb +1 -2
  124. data/lib/utopia/controller/respond.rb +1 -1
  125. data/lib/utopia/version.rb +1 -1
  126. data/setup/site/.bowerrc +2 -2
  127. data/setup/site/config.ru +1 -1
  128. data/setup/site/public/_static/site.css +16 -1
  129. data/setup/site/tasks/bower.rake +48 -0
  130. metadata +114 -5
  131. data/documentation/public +0 -1
  132. data/documentation/tasks/test.rake +0 -10
  133. data/documentation/tasks/utopia.rake +0 -38
@@ -0,0 +1,1098 @@
1
+ // This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
2
+ // Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
3
+ // See <jquery.syntax.js> for licensing details.
4
+
5
+ if (!RegExp.prototype.indexOf) {
6
+ RegExp.indexOf = function (match, index) {
7
+ return match[0].indexOf(match[index]) + match.index;
8
+ };
9
+ }
10
+
11
+ if (!RegExp.prototype.escape) {
12
+ RegExp.escape = function (pattern) {
13
+ return pattern.replace(/[\-\[\]{}()*+?.\\\^$|,#\s]/g, "\\$&");
14
+ };
15
+ }
16
+
17
+ if (!String.prototype.repeat) {
18
+ String.prototype.repeat = function(l) {
19
+ return new Array(l+1).join(this);
20
+ };
21
+ }
22
+
23
+ // Return the inner text of an element - must preserve whitespace.
24
+ // Avoid returning \r characters.
25
+ Syntax.innerText = function(element) {
26
+ var text;
27
+
28
+ if (!element) {
29
+ return "";
30
+ }
31
+
32
+ if (element.nodeName == 'BR') {
33
+ return '\n';
34
+ } else if (element.textContent) {
35
+ // W3C: FF, Safari, Chrome, etc.
36
+ text = element.textContent;
37
+ } else if (document.body.innerText) {
38
+ // IE, other older browsers.
39
+ text = element.innerText;
40
+ }
41
+
42
+ return text.replace(/\r\n?/g, '\n');
43
+ }
44
+
45
+ // Convert to stack based implementation
46
+ Syntax.extractElementMatches = function (elems, offset) {
47
+ var matches = [], current = [elems];
48
+ offset = offset || 0;
49
+
50
+ (function (elems) {
51
+ for (var i = 0; elems[i]; i++) {
52
+ var text = null, elem = elems[i];
53
+
54
+ if (elem.nodeType === 3 || elem.nodeType === 4) {
55
+ offset += elem.nodeValue.length;
56
+
57
+ } else if (elem.nodeType === 1) {
58
+ var text = Syntax.innerText(elem);
59
+
60
+ matches.push(new Syntax.Match(offset, text.length, {
61
+ klass: elem.className,
62
+ force: true,
63
+ element: elem,
64
+ allow: '*'
65
+ }, text));
66
+ }
67
+
68
+ // Traverse everything, except comment nodes
69
+ if (elem.nodeType !== 8 && elem.children) {
70
+ arguments.callee(elem.childNodes, offset);
71
+ }
72
+ }
73
+ })(elems);
74
+
75
+ // Remove the top level element, since this will be recreated based on the supplied configuration.
76
+ // Maybe there is a better way to achieve this?
77
+ matches.shift();
78
+
79
+ return matches;
80
+ }
81
+
82
+ // A helper function which automatically matches expressions with capture groups from the regular expression match.
83
+ // Each argument position corresponds to the same index regular expression group.
84
+ // Or, override by providing rule.index
85
+ Syntax.extractMatches = function() {
86
+ var rules = arguments;
87
+
88
+ return function(match, expr) {
89
+ var matches = [];
90
+
91
+ for (var i = 0; i < rules.length; i += 1) {
92
+ var rule = rules[i], index = i+1;
93
+
94
+ if (rule == null) {
95
+ continue;
96
+ }
97
+
98
+ if (typeof(rule.index) != 'undefined') {
99
+ index = rule.index;
100
+ }
101
+
102
+ if (rule.debug) {
103
+ console.log("extractMatches", rule, index, match[index], match);
104
+ }
105
+
106
+ if (match[index].length > 0) {
107
+ if (rule.brush) {
108
+ matches.push(Syntax.Brush.buildTree(rule, match[index], RegExp.indexOf(match, index)));
109
+ } else {
110
+ var expression = jQuery.extend({owner: expr.owner}, rule);
111
+
112
+ matches.push(new Syntax.Match(RegExp.indexOf(match, index), match[index].length, expression, match[index]));
113
+ }
114
+ }
115
+ }
116
+
117
+ return matches;
118
+ };
119
+ };
120
+
121
+ // Used to create processing functions that automatically link to remote documentation.
122
+ Syntax.lib.webLinkProcess = function (queryURI, lucky) {
123
+ if (lucky) {
124
+ queryURI = "http://www.google.com/search?btnI=I&q=" + encodeURIComponent(queryURI + " ");
125
+ }
126
+
127
+ return function (element, match, options) {
128
+ // Per-code block linkification control.
129
+ if (options.linkify === false)
130
+ return element;
131
+
132
+ var a = document.createElement('a');
133
+ a.href = queryURI + encodeURIComponent(Syntax.innerText(element));
134
+ a.className = element.className;
135
+
136
+ // Move children from <element> to <a>
137
+ while (element.childNodes.length > 0)
138
+ a.appendChild(element.childNodes[0]);
139
+
140
+ return a;
141
+ };
142
+ };
143
+
144
+ // Global brush registration function.
145
+ Syntax.register = function (name, callback) {
146
+ var brush = Syntax.brushes[name] = new Syntax.Brush();
147
+ brush.klass = name;
148
+
149
+ callback(brush);
150
+ };
151
+
152
+ // Library of helper patterns
153
+ Syntax.lib.cStyleComment = {pattern: /\/\*[\s\S]*?\*\//gm, klass: 'comment', allow: ['href']};
154
+ Syntax.lib.cppStyleComment = {pattern: /\/\/.*$/gm, klass: 'comment', allow: ['href']};
155
+ Syntax.lib.perlStyleComment = {pattern: /#.*$/gm, klass: 'comment', allow: ['href']};
156
+
157
+ // A hackity hack:
158
+ Syntax.lib.perlStyleRegularExpression = {pattern: /\B\/([^\\\/]|\\.)*\/[a-z]*(?=\s*($|[^\w\s'"\(]))/gm, klass: 'constant', incremental: true};
159
+ Syntax.lib.rubyStyleRegularExpression = {pattern: /\B\/([^\\\/]|\\.)*\/[a-z]*(?=\s*($|[^\w\s'"\(]|do))/gm, klass: 'constant', incremental: true};
160
+
161
+ Syntax.lib.cStyleFunction = {pattern: /([a-z_][a-z0-9_]*)\s*\(/gi, matches: Syntax.extractMatches({klass: 'function'})};
162
+ Syntax.lib.camelCaseType = {pattern: /\b_*[A-Z][\w]*\b/g, klass: 'type'};
163
+ Syntax.lib.cStyleType = {pattern: /\b[_a-z][_\w]*_t\b/gi, klass: 'type'};
164
+
165
+ Syntax.lib.xmlComment = {pattern: /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm, klass: 'comment'};
166
+ Syntax.lib.webLink = {pattern: /\w+:\/\/[\w\-.\/?%&=@:;#]*/g, klass: 'href'};
167
+
168
+ Syntax.lib.hexNumber = {pattern: /\b0x[0-9a-fA-F]+/g, klass: 'constant'};
169
+ Syntax.lib.decimalNumber = {pattern: /\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g, klass: 'constant'};
170
+
171
+ Syntax.lib.doubleQuotedString = {pattern: /"([^\\"\n]|\\.)*"/g, klass: 'string'};
172
+ Syntax.lib.singleQuotedString = {pattern: /'([^\\'\n]|\\.)*'/g, klass: 'string'};
173
+ Syntax.lib.multiLineDoubleQuotedString = {pattern: /"([^\\"]|\\.)*"/g, klass: 'string'};
174
+ Syntax.lib.multiLineSingleQuotedString = {pattern: /'([^\\']|\\.)*'/g, klass: 'string'};
175
+ Syntax.lib.stringEscape = {pattern: /\\./g, klass: 'escape', only: ['string']};
176
+
177
+ // Main match constructor. Make sure value is the correct size.
178
+ Syntax.Match = function (offset, length, expression, value) {
179
+ this.offset = offset;
180
+ this.endOffset = offset + length;
181
+ this.length = length;
182
+ this.expression = expression;
183
+ this.value = value;
184
+ this.children = [];
185
+ this.parent = null;
186
+
187
+ // When a node is bisected, this points to the next part.
188
+ this.next = null;
189
+ };
190
+
191
+ // Shifts an entire tree forward or backwards.
192
+ Syntax.Match.prototype.shift = function (offset, text) {
193
+ this.adjust(offset, null, text);
194
+
195
+ for (var i = 0; i < this.children.length; i++) {
196
+ this.children[i].shift(offset, text)
197
+ }
198
+ };
199
+
200
+ // C the current match to have different offset and length.
201
+ Syntax.Match.prototype.adjust = function (offset, length, text) {
202
+ this.offset += offset;
203
+ this.endOffset += offset;
204
+
205
+ if (length) {
206
+ this.length = length;
207
+ this.endOffset = this.offset + length;
208
+ }
209
+
210
+ if (text) {
211
+ this.value = text.substr(this.offset, this.length);
212
+ }
213
+ };
214
+
215
+ // Sort helper for sorting matches in forward order (e.g. same as the text that they were extracted from)
216
+ Syntax.Match.sort = function (a,b) {
217
+ return (a.offset - b.offset) || (b.length - a.length);
218
+ };
219
+
220
+ // Is the given match contained in the range of the parent match?
221
+ Syntax.Match.prototype.contains = function (match) {
222
+ return (match.offset >= this.offset) && (match.endOffset <= this.endOffset);
223
+ };
224
+
225
+ // Reduce a givent tree node into an html node.
226
+ Syntax.Match.defaultReduceCallback = function (node, container) {
227
+ // We avoid using jQuery in this function since it is incredibly performance sensitive.
228
+ // Using jQuery jQuery.fn.append() can reduce performance by as much as 1/3rd.
229
+ if (typeof(node) === 'string') {
230
+ node = document.createTextNode(node);
231
+ }
232
+
233
+ container.appendChild(node);
234
+ };
235
+
236
+ // Convert a tree of matches into some flat form (typically HTML nodes).
237
+ Syntax.Match.prototype.reduce = function (append, process) {
238
+ var start = this.offset;
239
+ var container = document.createElement('span');
240
+
241
+ append = append || Syntax.Match.defaultReduceCallback;
242
+
243
+ if (this.expression && this.expression.klass) {
244
+ if (container.className.length > 0)
245
+ container.className += ' ';
246
+
247
+ container.className += this.expression.klass;
248
+ }
249
+
250
+ if (this.className) {
251
+ container.className += ' ';
252
+ container.className += this.className;
253
+ }
254
+
255
+ for (var i = 0; i < this.children.length; i += 1) {
256
+ var child = this.children[i], end = child.offset;
257
+
258
+ if (child.offset < this.offset) {
259
+ console.log("Syntax Warning: Offset of child", child, "is before offset of parent", this);
260
+ }
261
+
262
+ var text = this.value.substr(start - this.offset, end - start);
263
+
264
+ append(text, container);
265
+ append(child.reduce(append, process), container);
266
+
267
+ start = child.endOffset;
268
+ }
269
+
270
+ if (start === this.offset) {
271
+ append(this.value, container);
272
+ } else if (start < this.endOffset) {
273
+ append(this.value.substr(start - this.offset, this.endOffset - start), container);
274
+ } else if (start > this.endOffset) {
275
+ console.log("Syntax Warning: Start position " + start + " exceeds end of value " + this.endOffset);
276
+ }
277
+
278
+ if (process) {
279
+ container = process(container, this);
280
+ }
281
+
282
+ return container;
283
+ };
284
+
285
+ // Main nesting check - can a match contain the given match?
286
+ Syntax.Match.prototype.canContain = function (match) {
287
+ // This is a special conditional for explicitly added ranges by the user.
288
+ // Since user added it, we honour it no matter what.
289
+ if (match.expression.force) {
290
+ return true;
291
+ }
292
+
293
+ // Can't add anything into complete trees.
294
+ if (this.complete) {
295
+ return false;
296
+ }
297
+
298
+ // match.expression.only will be checked on insertion using this.canHaveChild(match)
299
+ if (match.expression.only) {
300
+ return true;
301
+ }
302
+
303
+ // If allow is undefined, default behaviour is no children.
304
+ if (typeof(this.expression.allow) === 'undefined') {
305
+ return false;
306
+ }
307
+
308
+ // false if {disallow: [..., klass, ...]}
309
+ if (jQuery.isArray(this.expression.disallow) && jQuery.inArray(match.expression.klass, this.expression.disallow) !== -1) {
310
+ return false;
311
+ }
312
+
313
+ // true if {allow: '*'}
314
+ if (this.expression.allow === '*') {
315
+ return true;
316
+ }
317
+
318
+ // true if {allow: [..., klass, ...]}
319
+ if (jQuery.isArray(this.expression.allow) && jQuery.inArray(match.expression.klass, this.expression.allow) !== -1) {
320
+ return true;
321
+ }
322
+
323
+ return false;
324
+ };
325
+
326
+ // Return true if the given match can be spliced in as a child.
327
+ // Checked automatically when calling _splice.
328
+ Syntax.Match.prototype.canHaveChild = function(match) {
329
+ var only = match.expression.only;
330
+
331
+ // This condition is fairly slow
332
+ if (only) {
333
+ var cur = this;
334
+
335
+ while (cur !== null) {
336
+ if (jQuery.inArray(cur.expression.klass, only) !== -1) {
337
+ return true;
338
+ }
339
+
340
+ cur = cur.parent;
341
+
342
+ // We don't traverse into other trees.
343
+ if (cur && cur.complete) {
344
+ break;
345
+ }
346
+ }
347
+
348
+ return false;
349
+ }
350
+
351
+ return true;
352
+ };
353
+
354
+ // Add a child into the list of children for a given match, if it is acceptable to do so.
355
+ // Updates the owner of the match.
356
+ // Returns null if splice failed.
357
+ Syntax.Match.prototype._splice = function(i, match) {
358
+ if (this.canHaveChild(match)) {
359
+ this.children.splice(i, 0, match);
360
+ match.parent = this;
361
+
362
+ // For matches added using tags.
363
+ if (!match.expression.owner) {
364
+ match.expression.owner = this.expression.owner;
365
+ }
366
+
367
+ return this;
368
+ } else {
369
+ return null;
370
+ }
371
+ };
372
+
373
+ // This function implements a full insertion procedure, and will break up the match to fit.
374
+ // This operation is potentially very expensive, but is used to insert custom ranges into
375
+ // the tree, if they are specified by the user. A custom <span> may cover multiple leafs in
376
+ // the tree, thus some parts of the tree may need to be split. This behavior is controlled
377
+ // by whole - if true, the tree is split, if false, the match is split.
378
+ // You should avoid using this function except in very specific cases.
379
+ Syntax.Match.prototype.insert = function(match, whole) {
380
+ if (!this.contains(match))
381
+ return null;
382
+
383
+ if (whole) {
384
+ var top = this, i = 0;
385
+ while (i < top.children.length) {
386
+ if (top.children[i].contains(match)) {
387
+ top = top.children[i];
388
+ i = 0;
389
+ } else {
390
+ i += 1;
391
+ }
392
+ }
393
+
394
+ return top._insertWhole(match);
395
+ } else {
396
+ return this._insert(match);
397
+ }
398
+ }
399
+
400
+ Syntax.Match.prototype._insertWhole = function(match) {
401
+ var parts = this.bisectAtOffsets([match.offset, match.endOffset])
402
+ this.children = [];
403
+
404
+ if (parts[0]) {
405
+ this.children = this.children.concat(parts[0].children);
406
+ }
407
+
408
+ if (parts[1]) {
409
+ match.children = [];
410
+
411
+ // Update the match's expression based on the current position in the tree:
412
+ if (this.expression && this.expression.owner) {
413
+ match.expression = this.expression.owner.getRuleForKlass(match.expression.klass) || match.expression;
414
+ }
415
+
416
+ // This probably isn't ideal, it would be better to convert all children and children-of-children
417
+ // into a linear array and reinsert - it would be slightly more accurate in many cases.
418
+ for (var i = 0; i < parts[1].children.length; i += 1) {
419
+ var child = parts[1].children[i];
420
+
421
+ if (match.canContain(child)) {
422
+ match.children.push(child);
423
+ }
424
+ }
425
+
426
+ this.children.push(match);
427
+ }
428
+
429
+ if (parts[2]) {
430
+ this.children = this.children.concat(parts[2].children);
431
+ }
432
+
433
+ return this;
434
+ }
435
+
436
+ // This is not a general tree insertion function. It is optimised to run in almost constant
437
+ // time, but data must be inserted in sorted order, otherwise you will have problems.
438
+ // This function also ensures that matches won't be broken up unless absolutely necessary.
439
+ Syntax.Match.prototype.insertAtEnd = function(match) {
440
+ if (!this.contains(match)) {
441
+ console.log("Syntax Error: Child is not contained in parent node!");
442
+ return null;
443
+ }
444
+
445
+ if (!this.canContain(match)) {
446
+ return null;
447
+ }
448
+
449
+ if (this.children.length > 0) {
450
+ var i = this.children.length-1;
451
+ var child = this.children[i];
452
+
453
+ if (match.offset < child.offset) {
454
+ // Displacement: Before or LHS Overlap
455
+ // This means that the match has actually occurred before the last child.
456
+ // This is a bit of an unusual situation because the matches SHOULD be in
457
+ // sorted order.
458
+ // However, we are sure that the match is contained in this node. This situation
459
+ // sometimes occurs when sorting existing branches with matches that are supposed
460
+ // to be within that branch. When we insert the match into the branch, there are
461
+ // matches that technically should have been inserted afterwards.
462
+ // Normal usage should avoid this case, and this is best for performance.
463
+ if (match.force) {
464
+ return this._insert(match);
465
+ } else {
466
+ return null;
467
+ }
468
+ } else if (match.offset < child.endOffset) {
469
+ if (match.endOffset <= child.endOffset) {
470
+ // Displacement: Contains
471
+ //console.log("displacement => contains");
472
+ var result = child.insertAtEnd(match);
473
+ return result;
474
+ } else {
475
+ // Displacement: RHS Overlap
476
+ if (match.force) {
477
+ return this._insert(match);
478
+ } else {
479
+ return null;
480
+ }
481
+ }
482
+ } else {
483
+ // Displacement: After
484
+ return this._splice(i+1, match);
485
+ }
486
+ } else {
487
+ // Displacement: Contains [but currently no children]
488
+ return this._splice(0, match);
489
+ }
490
+ };
491
+
492
+ // This insertion function is relatively complex because it is required to split the match over
493
+ // several children. This function is used infrequently and is mostly for completeness. However,
494
+ // it might be possible to remove it to reduce code.
495
+ Syntax.Match.prototype._insert = function(match) {
496
+ if (this.children.length == 0)
497
+ return this._splice(0, match);
498
+
499
+ for (var i = 0; i < this.children.length; i += 1) {
500
+ var child = this.children[i];
501
+
502
+ // If the match ends before this child, it must be before it.
503
+ if (match.endOffset <= child.offset)
504
+ return this._splice(i, match);
505
+
506
+ // If the match starts after this child, we continue.
507
+ if (match.offset >= child.endOffset)
508
+ continue;
509
+
510
+ // There are four possibilities...
511
+ // ... with the possibility of overlapping children on the RHS.
512
+ // {------child------} {---possibly some other child---}
513
+ // |----------complete overlap---------|
514
+ // |--lhs overlap--|
515
+ // |--contains--|
516
+ // |--rhs overlap--|
517
+
518
+ // First, the easiest case:
519
+ if (child.contains(match)) {
520
+ return child._insert(match);
521
+ }
522
+
523
+ // console.log("Bisect at offsets", match, child.offset, child.endOffset);
524
+ var parts = match.bisectAtOffsets([child.offset, child.endOffset]);
525
+ // console.log("parts =", parts);
526
+ // We now have at most three parts
527
+ // {------child------} {---possibly some other child---}
528
+ // |--[0]--|-------[1]-------|--[2]--|
529
+
530
+ // console.log("parts", parts);
531
+
532
+ if (parts[0]) {
533
+ this._splice(i, parts[0])
534
+ }
535
+
536
+ if (parts[1]) {
537
+ child.insert(parts[1])
538
+ }
539
+
540
+ // Continue insertion at this level with remainder.
541
+ if (parts[2]) {
542
+ match = parts[2]
543
+ } else {
544
+ return this;
545
+ }
546
+ }
547
+
548
+ // If we got this far, the match wasn't [completely] inserted into the list of existing children, so it must be on the end.
549
+ this._splice(this.children.length, match);
550
+ }
551
+
552
+ // This algorithm recursively bisects the tree at a given offset, but it does this efficiently by folding multiple bisections
553
+ // at a time.
554
+ // Splits: / / /
555
+ // Tree: |-------------------------Top-------------------------|
556
+ // |------------A--------------------| |------C-------|
557
+ // |-------B----------|
558
+ // Step (1):
559
+ // Split Top into 4 parts:
560
+ // |------/----------------/-------------------/---------|
561
+ // For each part, check if there are any children that cover this part.
562
+ // If there is a child, recursively call bisect with all splits.
563
+ // Step (1-1):
564
+ // Split A into parts:
565
+ // |------/-----A----------/---------|
566
+ // For each part, check if there are any children that cover this part.
567
+ // If there is a child, recursively call bisect with all splits.
568
+ // Step (1-1-1):
569
+ // Split B into parts:
570
+ // |-------B---/------|
571
+ // No children covered by split. Return array of two parts, B1, B2.
572
+ // Step (1-2):
573
+ // Enumerate the results of splitting the child and merge piece-wise into own parts
574
+ // |------/-----A----------/---------|
575
+ // |------B1---|--B2--|
576
+ // Finished merging children, return array of three parts, A1, A2, A3
577
+ // Step (2):
578
+ // Enumerate the results of splitting the child and merge piece-wise into own parts.
579
+ // |------/----------------/-------------------/---------|
580
+ // |--A1--|-------A2-------|----A3---|
581
+ // |------B1---|--B2--|
582
+ // Continue by splitting next child, C.
583
+ // Once all children have been split and merged, return all parts, T1, T2, T3, T4.
584
+ // The new tree:
585
+ // |--T1--|-------T2-------|--------T3---------|---T4---|
586
+ // |--A1--|-------A2-------|----A3---| |--C1--|---C2--|
587
+ // |------B1---|--B2--|
588
+ //
589
+ // The new structure is as follows:
590
+ // T1 <- A1
591
+ // T2 <- A2 <- B1
592
+ // T3 <- A3 <- B2
593
+ // \- C1
594
+ // T4 <- C2
595
+ //
596
+ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
597
+ var parts = [], start = this.offset, prev = null, children = jQuery.merge([], this.children);
598
+
599
+ // Copy the array so we can modify it.
600
+ splits = splits.slice(0);
601
+
602
+ // We need to split including the last part.
603
+ splits.push(this.endOffset);
604
+
605
+ splits.sort(function (a,b) {
606
+ return a-b;
607
+ });
608
+
609
+ // We build a set of top level matches by looking at each split point and
610
+ // creating a new match from the end of the previous match to the split point.
611
+ for (var i = 0; i < splits.length; i += 1) {
612
+ var offset = splits[i];
613
+
614
+ // The split offset is past the end of the match, so there are no more possible
615
+ // splits.
616
+ if (offset > this.endOffset) {
617
+ break;
618
+ }
619
+
620
+ // We keep track of null parts if the offset is less than the start
621
+ // so that things align up as expected with the requested splits.
622
+ if (
623
+ offset < this.offset // If the split point is less than the start of the match.
624
+ || (offset - start) == 0 // If the match would have effectively zero length.
625
+ ) {
626
+ parts.push(null); // Preserve alignment with splits.
627
+ start = offset;
628
+ continue;
629
+ }
630
+
631
+ // Even if the previous split was out to the left, we align up the start
632
+ // to be at the start of the match we are bisecting.
633
+ if (start < this.offset)
634
+ start = this.offset;
635
+
636
+ var match = new Syntax.Match(start, offset - start, this.expression);
637
+ match.value = this.value.substr(start - this.offset, match.length);
638
+
639
+ if (prev) {
640
+ prev.next = match;
641
+ }
642
+
643
+ prev = match;
644
+
645
+ start = match.endOffset;
646
+ parts.push(match);
647
+ }
648
+
649
+ // We only need to split to produce the number of parts we have.
650
+ splits.length = parts.length;
651
+
652
+ for (var i = 0; i < parts.length; i += 1) {
653
+ if (parts[i] == null)
654
+ continue;
655
+
656
+ var offset = splits[0];
657
+
658
+ while (children.length > 0) {
659
+ if (children[0].endOffset <= parts[i].endOffset) {
660
+ parts[i].children.push(children.shift());
661
+ } else {
662
+ break;
663
+ }
664
+ }
665
+
666
+ if (children.length) {
667
+ // We may have an intersection
668
+ if (children[0].offset < parts[i].endOffset) {
669
+ var children_parts = children.shift().bisectAtOffsets(splits), j = 0;
670
+
671
+ // children_parts are the bisected children which need to be merged with parts
672
+ // in a linear fashion
673
+ for (; j < children_parts.length; j += 1) {
674
+ if (children_parts[j] == null) continue; // Preserve alignment with splits.
675
+
676
+ parts[i+j].children.push(children_parts[j]);
677
+ }
678
+
679
+ // Skip any parts which have been populated already
680
+ // (i is incremented at the start of the loop, splits shifted at the end)
681
+ i += (children_parts.length-2);
682
+ splits.splice(0, children_parts.length-2);
683
+ }
684
+ }
685
+
686
+ splits.shift();
687
+ }
688
+
689
+ if (children.length) {
690
+ console.log("Syntax Error: Children nodes not consumed", children.length, " remaining!");
691
+ }
692
+
693
+ return parts;
694
+ };
695
+
696
+ // Split a match at points in the tree that match a specific regular expression pattern.
697
+ // Uses the fast tree bisection algorithm, performance should be bounded O(S log N) where N is
698
+ // the total number of matches and S is the number of splits (?).
699
+ Syntax.Match.prototype.split = function(pattern) {
700
+ var splits = [], match;
701
+
702
+ while ((match = pattern.exec(this.value)) !== null) {
703
+ splits.push(pattern.lastIndex);
704
+ }
705
+
706
+ var matches = this.bisectAtOffsets(splits);
707
+
708
+ // Remove any null placeholders.
709
+ return jQuery.grep(matches, function(n,i){
710
+ return n;
711
+ });
712
+ };
713
+
714
+ Syntax.Match.prototype.splitLines = function() {
715
+ var lines = this.split(/\n/g);
716
+
717
+ for (var i = 0; i < lines.length; i += 1) {
718
+ var line = lines[i];
719
+ var indentOffset = line.value.search(/\S/);
720
+
721
+ var top = new Syntax.Match(line.offset, line.length, line.expression, line.value);
722
+
723
+ if (indentOffset > 0) {
724
+ var parts = line.bisectAtOffsets([line.offset + indentOffset]);
725
+ top.children = parts;
726
+ parts[0].expression = {klass: 'indent'};
727
+ parts[1].expression = {klass: 'text'};
728
+ } else {
729
+ line.expression = {klass: 'text'};
730
+ top.children = [line];
731
+ }
732
+
733
+ lines[i] = top;
734
+ }
735
+
736
+ return lines;
737
+ }
738
+
739
+ Syntax.Brush = function () {
740
+ // The primary class of this brush. Must be unique.
741
+ this.klass = null;
742
+
743
+ // A sequential list of rules for extracting matches.
744
+ this.rules = [];
745
+
746
+ // A list of all parents that this brush derives from.
747
+ this.parents = [];
748
+
749
+ // A list of processes that may be run after extracting matches.
750
+ this.processes = {};
751
+ };
752
+
753
+ // Add a parent to the brush. This brush should be loaded as a dependency.
754
+ Syntax.Brush.prototype.derives = function (name) {
755
+ this.parents.push(name);
756
+ this.rules.push({
757
+ apply: function(text, expr) {
758
+ return Syntax.brushes[name].getMatches(text);
759
+ }
760
+ });
761
+ };
762
+
763
+ // Return an array of all classes that the brush consists of.
764
+ // A derivied brush is its own klass + the klass of any and all parents.
765
+ Syntax.Brush.prototype.allKlasses = function () {
766
+ var klasses = [this.klass];
767
+
768
+ for (var i = 0; i < this.parents.length; i += 1) {
769
+ klasses = klasses.concat(Syntax.brushes[this.parents[i]].allKlasses());
770
+ }
771
+
772
+ return klasses;
773
+ }
774
+
775
+ Syntax.Brush.convertStringToTokenPattern = function (pattern, escape) {
776
+ var prefix = "\\b", postfix = "\\b";
777
+
778
+ if (!pattern.match(/^\w/)) {
779
+ if (!pattern.match(/\w$/)) {
780
+ prefix = postfix = "";
781
+ } else {
782
+ prefix = "\\B";
783
+ }
784
+ } else {
785
+ if (!pattern.match(/\w$/)) {
786
+ postfix = "\\B";
787
+ }
788
+ }
789
+
790
+ if (escape)
791
+ pattern = RegExp.escape(pattern)
792
+
793
+ return prefix + pattern + postfix;
794
+ }
795
+
796
+ Syntax.Brush.MatchPattern = function (text, rule) {
797
+ if (!rule.pattern)
798
+ return [];
799
+
800
+ // Duplicate the pattern so that the function is reentrant.
801
+ var matches = [], pattern = new RegExp;
802
+ pattern.compile(rule.pattern);
803
+
804
+ while((match = pattern.exec(text)) !== null) {
805
+ if (rule.matches) {
806
+ matches = matches.concat(rule.matches(match, rule));
807
+ } else if (rule.brush) {
808
+ matches.push(Syntax.Brush.buildTree(rule, match[0], match.index));
809
+ } else {
810
+ matches.push(new Syntax.Match(match.index, match[0].length, rule, match[0]));
811
+ }
812
+
813
+ if (rule.incremental) {
814
+ // Don't start scanning from the end of the match..
815
+ pattern.lastIndex = match.index + 1;
816
+ }
817
+ }
818
+
819
+ return matches;
820
+ }
821
+
822
+ Syntax.Brush.prototype.push = function () {
823
+ if (jQuery.isArray(arguments[0])) {
824
+ var patterns = arguments[0], rule = arguments[1];
825
+
826
+ var all = "(";
827
+
828
+ for (var i = 0; i < patterns.length; i += 1) {
829
+ if (i > 0) all += "|";
830
+
831
+ var p = patterns[i];
832
+
833
+ if (p instanceof RegExp) {
834
+ all += p.source;
835
+ } else {
836
+ all += Syntax.Brush.convertStringToTokenPattern(p, true);
837
+ }
838
+ }
839
+
840
+ all += ")";
841
+
842
+ this.push(jQuery.extend({
843
+ pattern: new RegExp(all, rule.options || 'g')
844
+ }, rule));
845
+ } else {
846
+ var rule = arguments[0];
847
+
848
+ if (typeof(rule.pattern) === 'string') {
849
+ rule.string = rule.pattern;
850
+ rule.pattern = new RegExp(Syntax.Brush.convertStringToTokenPattern(rule.string, true), rule.options || 'g')
851
+ }
852
+
853
+ if (typeof(XRegExp) !== 'undefined') {
854
+ rule.pattern = new XRegExp(rule.pattern);
855
+ }
856
+
857
+ // Default pattern extraction algorithm
858
+ rule.apply = rule.apply || Syntax.Brush.MatchPattern;
859
+
860
+ if (rule.pattern && rule.pattern.global || typeof(rule.pattern) == 'undefined') {
861
+ this.rules.push(jQuery.extend({owner: this}, rule));
862
+ } else {
863
+ console.log("Syntax Error: Malformed rule: ", rule);
864
+ }
865
+ }
866
+ };
867
+
868
+ Syntax.Brush.prototype.getMatchesForRule = function (text, rule) {
869
+ var matches = [], match = null;
870
+
871
+ // Short circuit (user defined) function:
872
+ if (typeof(rule.apply) != 'undefined') {
873
+ matches = rule.apply(text, rule);
874
+ }
875
+
876
+ if (rule.debug) {
877
+ console.log("Syntax matches:", rule, text, matches);
878
+ }
879
+
880
+ return matches;
881
+ };
882
+
883
+ Syntax.Brush.prototype.getRuleForKlass = function (klass) {
884
+ for (var i = 0; i < this.rules.length; i += 1) {
885
+ if (this.rules[i].klass == klass) {
886
+ return this.rules[i];
887
+ }
888
+ }
889
+
890
+ return null;
891
+ }
892
+
893
+ // Get all matches from a given block of text.
894
+ Syntax.Brush.prototype.getMatches = function(text) {
895
+ var matches = [];
896
+
897
+ for (var i = 0; i < this.rules.length; i += 1) {
898
+ matches = matches.concat(this.getMatchesForRule(text, this.rules[i]));
899
+ }
900
+
901
+ return matches;
902
+ };
903
+
904
+ // A helper function for building a tree from a specific rule.
905
+ // Typically used where sub-trees are required, e.g. CSS brush in HTML brush.
906
+ Syntax.Brush.buildTree = function(rule, text, offset, additionalMatches) {
907
+ var match = Syntax.brushes[rule.brush].buildTree(text, offset, additionalMatches);
908
+
909
+ jQuery.extend(match.expression, rule);
910
+
911
+ return match;
912
+ }
913
+
914
+ // This function builds a tree from a given block of text.
915
+ // This is done by applying all rules to the text to get a complete list of matches,
916
+ // sorting them in order, and inserting them into a syntax tree data structure.
917
+ // Additional matches are forcefully inserted into the tree.
918
+ // Provide an offset if the text is offset in a larger block of text. Matches
919
+ // will be shifted along appropriately.
920
+ Syntax.Brush.prototype.buildTree = function(text, offset, additionalMatches) {
921
+ offset = offset || 0;
922
+
923
+ // Fixes code that uses \r\n for line endings. /$/ matches both \r\n, which is a problem..
924
+ text = text.replace(/\r/g, '');
925
+
926
+ var matches = this.getMatches(text);
927
+
928
+ // Shift matches if offset is provided.
929
+ if (offset && offset > 0) {
930
+ for (var i = 0; i < matches.length; i += 1) {
931
+ matches[i].shift(offset);
932
+ }
933
+ }
934
+
935
+ var top = new Syntax.Match(offset, text.length, {klass: this.allKlasses().join(" "), allow: '*', owner: this}, text);
936
+
937
+ // This sort is absolutely key to the functioning of the tree insertion algorithm.
938
+ matches.sort(Syntax.Match.sort);
939
+
940
+ for (var i = 0; i < matches.length; i += 1) {
941
+ top.insertAtEnd(matches[i]);
942
+ }
943
+
944
+ if (additionalMatches) {
945
+ for (var i = 0; i < additionalMatches.length; i += 1) {
946
+ top.insert(additionalMatches[i], true);
947
+ }
948
+ }
949
+
950
+ top.complete = true;
951
+
952
+ return top;
953
+ };
954
+
955
+ // This function builds a syntax tree from the given text and matches (optional).
956
+ // The syntax tree is then flattened into html using a variety of functions.
957
+ //
958
+ // By default, you can't control reduction process through this function, but
959
+ // it is possible to control the element conversion process by replace
960
+ // .reduce(null, ...) with .reduce(reduceCallback, ...)
961
+ // See Syntax.Match.defaultReduceCallback for more details about interface.
962
+ //
963
+ // Matches is optional, and provides a set of pre-existing matches to add
964
+ // to the tree.
965
+ // Options are passed to element level processing functions.
966
+ Syntax.Brush.prototype.process = function(text, matches, options) {
967
+ var top = this.buildTree(text, 0, matches);
968
+
969
+ var lines = top.splitLines();
970
+
971
+ var html = document.createElement('code');
972
+ html.className = 'syntax';
973
+
974
+ for (var i = 0; i < lines.length; i += 1) {
975
+ var line = lines[i].reduce(null, function (container, match) {
976
+ if (match.expression) {
977
+ if (match.expression.process) {
978
+ container = match.expression.process(container, match, options);
979
+ }
980
+
981
+ if (match.expression.owner) {
982
+ var process = match.expression.owner.processes[match.expression.klass];
983
+ if (process) {
984
+ container = process(container, match, options);
985
+ }
986
+ }
987
+ }
988
+ return container;
989
+ });
990
+
991
+ html.appendChild(line);
992
+ }
993
+
994
+ return html;
995
+ };
996
+
997
+ // Highlights a given block of text with a given set of options.
998
+ // options.brush should specify the brush to use, either by direct reference
999
+ // or name.
1000
+ // Callback will be called with (highlighted_html, brush_used, original_text, options)
1001
+ Syntax.highlightText = function(text, brush, matches, options, callback) {
1002
+ brush = (brush || 'plain').toLowerCase();
1003
+ brush = Syntax.aliases[brush] || brush;
1004
+
1005
+ Syntax.brushes.get(brush, function(brush) {
1006
+ var html = brush.process(text, matches, options);
1007
+
1008
+ if (options.linkify) {
1009
+ jQuery('span.href', html).each(function(){
1010
+ jQuery(this).replaceWith(jQuery('<a>').attr('href', this.innerHTML).text(this.innerHTML));
1011
+ });
1012
+ }
1013
+
1014
+ callback(html, brush, text, options);
1015
+ });
1016
+ }
1017
+
1018
+ Syntax.extractBrushName = function (className) {
1019
+ // brush names are by default lower case - normalize so we can detect it.
1020
+ className = className.toLowerCase();
1021
+
1022
+ var match = className.match(/(brush|language)-([\S]+)/);
1023
+
1024
+ if (match) {
1025
+ return match[2];
1026
+ } else {
1027
+ var classes = className.split(/ /);
1028
+
1029
+ if (jQuery.inArray("syntax", classes) !== -1) {
1030
+ for (var i = 0; i < classes.length; i += 1) {
1031
+ var name = Syntax.aliases[classes[i]];
1032
+
1033
+ if (name) {
1034
+ return name;
1035
+ }
1036
+ }
1037
+ }
1038
+ }
1039
+
1040
+ return null;
1041
+ }
1042
+
1043
+ Syntax.extractTextBrushName = function (text) {
1044
+ var match = text.match(/-\*- mode: (.+?);(.*?)-\*-/i);
1045
+ var endOfSecondLine = text.indexOf("\n", text.indexOf("\n") + 1);
1046
+
1047
+ if (match && match.index < endOfSecondLine) {
1048
+ return brush;
1049
+ }
1050
+ }
1051
+
1052
+ // Highlight a given set of elements with a set of options.
1053
+ // Callback will be called once per element with (options, highlighted_html, original_container)
1054
+ Syntax.highlight = function (elements, options, callback) {
1055
+ elements.each(function () {
1056
+ var container = jQuery(this);
1057
+ var brush = options.brush || Syntax.extractBrushName(this.className);
1058
+ var text = Syntax.innerText(this);
1059
+
1060
+ // We can augment the plain text to extract existing annotations (e.g. <span class="foo">...</span>).
1061
+ var matches = Syntax.extractElementMatches(container);
1062
+
1063
+ if (options.matches) {
1064
+ Array.prototype.push(matches, options.matches);
1065
+ }
1066
+
1067
+ Syntax.highlightText(text, brush, matches, options, function(html, brush/*, text, options*/) {
1068
+ html = jQuery(html);
1069
+
1070
+ // If there is a theme specified, ensure it is added to the top level class.
1071
+ if (options.theme) {
1072
+ // Load dependencies
1073
+ var themes = Syntax.themes[options.theme];
1074
+ for (var i = 0; i < themes.length; i += 1) {
1075
+ html.addClass("syntax-theme-" + themes[i]);
1076
+ }
1077
+
1078
+ // Add the base theme
1079
+ html.addClass("syntax-theme-" + options.theme);
1080
+ }
1081
+
1082
+ if (brush.postprocess) {
1083
+ html = brush.postprocess(options, html, container);
1084
+ }
1085
+
1086
+ if (callback) {
1087
+ html = callback(options, html, container);
1088
+ }
1089
+
1090
+ if (html && options.replace === true) {
1091
+ container.replaceWith(html);
1092
+ }
1093
+ });
1094
+ });
1095
+ };
1096
+
1097
+ // Register the file as being loaded
1098
+ Syntax.loader.core = true;