codemirror-rails 3.13 → 3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +328 -250
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +7 -6
  5. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +33 -7
  6. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +14 -10
  7. data/vendor/assets/javascripts/codemirror/addons/edit/trailingspace.js +15 -0
  8. data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +70 -17
  9. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +56 -20
  10. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +135 -39
  11. data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +324 -571
  12. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +199 -109
  13. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +60 -113
  14. data/vendor/assets/javascripts/codemirror/addons/lint/coffeescript-lint.js +24 -0
  15. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +431 -0
  16. data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +7 -1
  17. data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +46 -20
  18. data/vendor/assets/javascripts/codemirror/addons/search/search.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +370 -13
  20. data/vendor/assets/javascripts/codemirror/keymaps/extra.js +43 -0
  21. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +535 -214
  22. data/vendor/assets/javascripts/codemirror/modes/clike.js +56 -0
  23. data/vendor/assets/javascripts/codemirror/modes/javascript.js +19 -14
  24. data/vendor/assets/javascripts/codemirror/modes/markdown.js +2 -2
  25. data/vendor/assets/javascripts/codemirror/modes/ruby.js +67 -16
  26. data/vendor/assets/javascripts/codemirror/modes/smarty.js +167 -110
  27. data/vendor/assets/javascripts/codemirror/modes/sql.js +97 -15
  28. data/vendor/assets/javascripts/codemirror/modes/xml.js +14 -18
  29. data/vendor/assets/stylesheets/codemirror.css +0 -1
  30. data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +82 -0
  31. metadata +7 -2
@@ -302,4 +302,60 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
302
302
  }
303
303
  }
304
304
  });
305
+ mimes(["x-shader/x-vertex", "x-shader/x-fragment"], {
306
+ name: "clike",
307
+ keywords: words("float int bool void " +
308
+ "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
309
+ "mat2 mat3 mat4 " +
310
+ "sampler1D sampler2D sampler3D samplerCube " +
311
+ "sampler1DShadow sampler2DShadow" +
312
+ "const attribute uniform varying " +
313
+ "break continue discard return " +
314
+ "for while do if else struct " +
315
+ "in out inout"),
316
+ blockKeywords: words("for while do if else struct"),
317
+ builtin: words("radians degrees sin cos tan asin acos atan " +
318
+ "pow exp log exp2 sqrt inversesqrt " +
319
+ "abs sign floor ceil fract mod min max clamp mix step smootstep " +
320
+ "length distance dot cross normalize ftransform faceforward " +
321
+ "reflect refract matrixCompMult " +
322
+ "lessThan lessThanEqual greaterThan greaterThanEqual " +
323
+ "equal notEqual any all not " +
324
+ "texture1D texture1DProj texture1DLod texture1DProjLod " +
325
+ "texture2D texture2DProj texture2DLod texture2DProjLod " +
326
+ "texture3D texture3DProj texture3DLod texture3DProjLod " +
327
+ "textureCube textureCubeLod " +
328
+ "shadow1D shadow2D shadow1DProj shadow2DProj " +
329
+ "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
330
+ "dFdx dFdy fwidth " +
331
+ "noise1 noise2 noise3 noise4"),
332
+ atoms: words("true false " +
333
+ "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
334
+ "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
335
+ "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
336
+ "gl_FogCoord " +
337
+ "gl_Position gl_PointSize gl_ClipVertex " +
338
+ "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
339
+ "gl_TexCoord gl_FogFragCoord " +
340
+ "gl_FragCoord gl_FrontFacing " +
341
+ "gl_FragColor gl_FragData gl_FragDepth " +
342
+ "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
343
+ "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
344
+ "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
345
+ "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
346
+ "gl_ProjectionMatrixInverseTranspose " +
347
+ "gl_ModelViewProjectionMatrixInverseTranspose " +
348
+ "gl_TextureMatrixInverseTranspose " +
349
+ "gl_NormalScale gl_DepthRange gl_ClipPlane " +
350
+ "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
351
+ "gl_FrontLightModelProduct gl_BackLightModelProduct " +
352
+ "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
353
+ "gl_FogParameters " +
354
+ "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
355
+ "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
356
+ "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
357
+ "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
358
+ "gl_MaxDrawBuffers"),
359
+ hooks: {"#": cppHook}
360
+ });
305
361
  }());
@@ -2,6 +2,7 @@
2
2
 
3
3
  CodeMirror.defineMode("javascript", function(config, parserConfig) {
4
4
  var indentUnit = config.indentUnit;
5
+ var statementIndent = parserConfig.statementIndent;
5
6
  var jsonMode = parserConfig.json;
6
7
  var isTS = parserConfig.typescript;
7
8
 
@@ -226,8 +227,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
226
227
  }
227
228
  function pushlex(type, info) {
228
229
  var result = function() {
229
- var state = cx.state;
230
- state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
230
+ var state = cx.state, indent = state.indented;
231
+ if (state.lexical.type == "stat") indent = state.lexical.indented;
232
+ state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
231
233
  };
232
234
  result.lex = true;
233
235
  return result;
@@ -270,17 +272,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
270
272
  return pass(pushlex("stat"), expression, expect(";"), poplex);
271
273
  }
272
274
  function expression(type) {
273
- return expressionInner(type, maybeoperatorComma);
275
+ return expressionInner(type, false);
274
276
  }
275
277
  function expressionNoComma(type) {
276
- return expressionInner(type, maybeoperatorNoComma);
278
+ return expressionInner(type, true);
277
279
  }
278
- function expressionInner(type, maybeop) {
280
+ function expressionInner(type, noComma) {
281
+ var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
279
282
  if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
280
283
  if (type == "function") return cont(functiondef);
281
- if (type == "keyword c") return cont(maybeexpression);
284
+ if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
282
285
  if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
283
- if (type == "operator") return cont(expression);
286
+ if (type == "operator") return cont(noComma ? expressionNoComma : expression);
284
287
  if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
285
288
  if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
286
289
  return cont();
@@ -289,9 +292,13 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
289
292
  if (type.match(/[;\}\)\],]/)) return pass();
290
293
  return pass(expression);
291
294
  }
295
+ function maybeexpressionNoComma(type) {
296
+ if (type.match(/[;\}\)\],]/)) return pass();
297
+ return pass(expressionNoComma);
298
+ }
292
299
 
293
300
  function maybeoperatorComma(type, value) {
294
- if (type == ",") return pass();
301
+ if (type == ",") return cont(expression);
295
302
  return maybeoperatorNoComma(type, value, maybeoperatorComma);
296
303
  }
297
304
  function maybeoperatorNoComma(type, value, me) {
@@ -435,18 +442,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
435
442
  if (state.tokenize != jsTokenBase) return 0;
436
443
  var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
437
444
  if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
445
+ if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
446
+ lexical = lexical.prev;
438
447
  var type = lexical.type, closing = firstChar == type;
439
- if (parserConfig.statementIndent != null) {
440
- if (type == ")" && lexical.prev && lexical.prev.type == "stat") lexical = lexical.prev;
441
- if (lexical.type == "stat") return lexical.indented + parserConfig.statementIndent;
442
- }
443
448
 
444
449
  if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
445
450
  else if (type == "form" && firstChar == "{") return lexical.indented;
446
451
  else if (type == "form") return lexical.indented + indentUnit;
447
452
  else if (type == "stat")
448
- return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
449
- else if (lexical.info == "switch" && !closing)
453
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
454
+ else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
450
455
  return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
451
456
  else if (lexical.align) return lexical.column + (closing ? 0 : 1);
452
457
  else return lexical.indented + (closing ? 0 : indentUnit);
@@ -308,11 +308,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
308
308
  return type;
309
309
  }
310
310
 
311
- if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
311
+ if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
312
312
  return switchInline(stream, state, inlineElement(linkinline, '>'));
313
313
  }
314
314
 
315
- if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) {
315
+ if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
316
316
  return switchInline(stream, state, inlineElement(linkemail, '>'));
317
317
  }
318
318
 
@@ -10,7 +10,7 @@ CodeMirror.defineMode("ruby", function(config) {
10
10
  "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
11
11
  "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
12
12
  "caller", "lambda", "proc", "public", "protected", "private", "require", "load",
13
- "require_relative", "extend", "autoload"
13
+ "require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__"
14
14
  ]);
15
15
  var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then",
16
16
  "catch", "loop", "proc", "begin"]);
@@ -31,14 +31,16 @@ CodeMirror.defineMode("ruby", function(config) {
31
31
  }
32
32
  if (stream.eatSpace()) return null;
33
33
  var ch = stream.next(), m;
34
- if (ch == "`" || ch == "'" || ch == '"' ||
35
- (ch == "/" && !stream.eol() && stream.peek() != " ")) {
34
+ if (ch == "`" || ch == "'" || ch == '"') {
36
35
  return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
36
+ } else if (ch == "/" && !stream.eol() && stream.peek() != " ") {
37
+ return chain(readQuoted(ch, "string-2", true), stream, state);
37
38
  } else if (ch == "%") {
38
- var style, embed = false;
39
+ var style = "string", embed = false;
39
40
  if (stream.eat("s")) style = "atom";
40
41
  else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; }
41
- else if (stream.eat(/[wxqr]/)) style = "string";
42
+ else if (stream.eat(/[r]/)) { style = "string-2"; embed = true; }
43
+ else if (stream.eat(/[wxq]/)) style = "string";
42
44
  var delim = stream.eat(/[^\w\s]/);
43
45
  if (!delim) return "operator";
44
46
  if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
@@ -64,18 +66,42 @@ CodeMirror.defineMode("ruby", function(config) {
64
66
  } else if (ch == ":") {
65
67
  if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
66
68
  if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
67
- stream.eatWhile(/[\w\?]/);
68
- return "atom";
69
- } else if (ch == "@") {
69
+
70
+ // :> :>> :< :<< are valid symbols
71
+ if (stream.eat(/[\<\>]/)) {
72
+ stream.eat(/[\<\>]/);
73
+ return "atom";
74
+ }
75
+
76
+ // :+ :- :/ :* :| :& :! are valid symbols
77
+ if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) {
78
+ return "atom";
79
+ }
80
+
81
+ // Symbols can't start by a digit
82
+ if (stream.eat(/[a-zA-Z$@_]/)) {
83
+ stream.eatWhile(/[\w]/);
84
+ // Only one ? ! = is allowed and only as the last character
85
+ stream.eat(/[\?\!\=]/);
86
+ return "atom";
87
+ }
88
+ return "operator";
89
+ } else if (ch == "@" && stream.match(/^@?[a-zA-Z_]/)) {
70
90
  stream.eat("@");
71
- stream.eatWhile(/[\w\?]/);
91
+ stream.eatWhile(/[\w]/);
72
92
  return "variable-2";
73
93
  } else if (ch == "$") {
74
- stream.next();
75
- stream.eatWhile(/[\w\?]/);
94
+ if (stream.eat(/[a-zA-Z_]/)) {
95
+ stream.eatWhile(/[\w]/);
96
+ } else if (stream.eat(/\d/)) {
97
+ stream.eat(/\d/);
98
+ } else {
99
+ stream.next(); // Must be a special global like $: or $!
100
+ }
76
101
  return "variable-3";
77
- } else if (/\w/.test(ch)) {
78
- stream.eatWhile(/[\w\?]/);
102
+ } else if (/[a-zA-Z_]/.test(ch)) {
103
+ stream.eatWhile(/[\w]/);
104
+ stream.eat(/[\?\!]/);
79
105
  if (stream.eat(":")) return "atom";
80
106
  return "ident";
81
107
  } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
@@ -109,17 +135,42 @@ CodeMirror.defineMode("ruby", function(config) {
109
135
  return tokenBase(stream, state);
110
136
  };
111
137
  }
138
+ function tokenBaseOnce() {
139
+ var alreadyCalled = false;
140
+ return function(stream, state) {
141
+ if (alreadyCalled) {
142
+ state.tokenize.pop();
143
+ return state.tokenize[state.tokenize.length-1](stream, state);
144
+ }
145
+ alreadyCalled = true;
146
+ return tokenBase(stream, state);
147
+ };
148
+ }
112
149
  function readQuoted(quote, style, embed, unescaped) {
113
150
  return function(stream, state) {
114
151
  var escaped = false, ch;
152
+
153
+ if (state.context.type === 'read-quoted-paused') {
154
+ state.context = state.context.prev;
155
+ stream.eat("}");
156
+ }
157
+
115
158
  while ((ch = stream.next()) != null) {
116
159
  if (ch == quote && (unescaped || !escaped)) {
117
160
  state.tokenize.pop();
118
161
  break;
119
162
  }
120
- if (embed && ch == "#" && !escaped && stream.eat("{")) {
121
- state.tokenize.push(tokenBaseUntilBrace(arguments.callee));
122
- break;
163
+ if (embed && ch == "#" && !escaped) {
164
+ if (stream.eat("{")) {
165
+ if (quote == "}") {
166
+ state.context = {prev: state.context, type: 'read-quoted-paused'};
167
+ }
168
+ state.tokenize.push(tokenBaseUntilBrace());
169
+ break;
170
+ } else if (/[@\$]/.test(stream.peek())) {
171
+ state.tokenize.push(tokenBaseOnce());
172
+ break;
173
+ }
123
174
  }
124
175
  escaped = !escaped && ch == "\\";
125
176
  }
@@ -1,140 +1,197 @@
1
+ /**
2
+ * Smarty 2 and 3 mode.
3
+ */
1
4
  CodeMirror.defineMode("smarty", function(config) {
2
- var keyFuncs = ["debug", "extends", "function", "include", "literal"];
5
+ "use strict";
6
+
7
+ // our default settings; check to see if they're overridden
8
+ var settings = {
9
+ rightDelimiter: '}',
10
+ leftDelimiter: '{',
11
+ smartyVersion: 2 // for backward compatibility
12
+ };
13
+ if (config.hasOwnProperty("leftDelimiter")) {
14
+ settings.leftDelimiter = config.leftDelimiter;
15
+ }
16
+ if (config.hasOwnProperty("rightDelimiter")) {
17
+ settings.rightDelimiter = config.rightDelimiter;
18
+ }
19
+ if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) {
20
+ settings.smartyVersion = 3;
21
+ }
22
+
23
+ var keyFunctions = ["debug", "extends", "function", "include", "literal"];
3
24
  var last;
4
25
  var regs = {
5
26
  operatorChars: /[+\-*&%=<>!?]/,
6
- validIdentifier: /[a-zA-Z0-9\_]/,
7
- stringChar: /[\'\"]/
27
+ validIdentifier: /[a-zA-Z0-9_]/,
28
+ stringChar: /['"]/
8
29
  };
9
- var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{";
10
- var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}";
11
- function ret(style, lst) { last = lst; return style; }
12
30
 
13
-
14
- function tokenizer(stream, state) {
15
- function chain(parser) {
31
+ var helpers = {
32
+ cont: function(style, lastType) {
33
+ last = lastType;
34
+ return style;
35
+ },
36
+ chain: function(stream, state, parser) {
16
37
  state.tokenize = parser;
17
38
  return parser(stream, state);
18
39
  }
40
+ };
19
41
 
20
- if (stream.match(leftDelim, true)) {
21
- if (stream.eat("*")) {
22
- return chain(inBlock("comment", "*" + rightDelim));
23
- }
24
- else {
25
- state.tokenize = inSmarty;
26
- return "tag";
27
- }
28
- }
29
- else {
30
- // I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char
31
- stream.next();
32
- return null;
33
- }
34
- }
35
42
 
36
- function inSmarty(stream, state) {
37
- if (stream.match(rightDelim, true)) {
38
- state.tokenize = tokenizer;
39
- return ret("tag", null);
40
- }
43
+ // our various parsers
44
+ var parsers = {
41
45
 
42
- var ch = stream.next();
43
- if (ch == "$") {
44
- stream.eatWhile(regs.validIdentifier);
45
- return ret("variable-2", "variable");
46
- }
47
- else if (ch == ".") {
48
- return ret("operator", "property");
49
- }
50
- else if (regs.stringChar.test(ch)) {
51
- state.tokenize = inAttribute(ch);
52
- return ret("string", "string");
53
- }
54
- else if (regs.operatorChars.test(ch)) {
55
- stream.eatWhile(regs.operatorChars);
56
- return ret("operator", "operator");
57
- }
58
- else if (ch == "[" || ch == "]") {
59
- return ret("bracket", "bracket");
60
- }
61
- else if (/\d/.test(ch)) {
62
- stream.eatWhile(/\d/);
63
- return ret("number", "number");
64
- }
65
- else {
66
- if (state.last == "variable") {
67
- if (ch == "@") {
68
- stream.eatWhile(regs.validIdentifier);
69
- return ret("property", "property");
46
+ // the main tokenizer
47
+ tokenizer: function(stream, state) {
48
+ if (stream.match(settings.leftDelimiter, true)) {
49
+ if (stream.eat("*")) {
50
+ return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter));
51
+ } else {
52
+ // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode
53
+ state.depth++;
54
+ var isEol = stream.eol();
55
+ var isFollowedByWhitespace = /\s/.test(stream.peek());
56
+ if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) {
57
+ state.depth--;
58
+ return null;
59
+ } else {
60
+ state.tokenize = parsers.smarty;
61
+ last = "startTag";
62
+ return "tag";
63
+ }
70
64
  }
71
- else if (ch == "|") {
72
- stream.eatWhile(regs.validIdentifier);
73
- return ret("qualifier", "modifier");
74
- }
75
- }
76
- else if (state.last == "whitespace") {
77
- stream.eatWhile(regs.validIdentifier);
78
- return ret("attribute", "modifier");
79
- }
80
- else if (state.last == "property") {
81
- stream.eatWhile(regs.validIdentifier);
82
- return ret("property", null);
83
- }
84
- else if (/\s/.test(ch)) {
85
- last = "whitespace";
65
+ } else {
66
+ stream.next();
86
67
  return null;
87
68
  }
69
+ },
88
70
 
89
- var str = "";
90
- if (ch != "/") {
91
- str += ch;
92
- }
93
- var c = "";
94
- while ((c = stream.eat(regs.validIdentifier))) {
95
- str += c;
96
- }
97
- var i, j;
98
- for (i=0, j=keyFuncs.length; i<j; i++) {
99
- if (keyFuncs[i] == str) {
100
- return ret("keyword", "keyword");
71
+ // parsing Smarty content
72
+ smarty: function(stream, state) {
73
+ if (stream.match(settings.rightDelimiter, true)) {
74
+ if (settings.smartyVersion === 3) {
75
+ state.depth--;
76
+ if (state.depth <= 0) {
77
+ state.tokenize = parsers.tokenizer;
78
+ }
79
+ } else {
80
+ state.tokenize = parsers.tokenizer;
101
81
  }
82
+ return helpers.cont("tag", null);
102
83
  }
103
- if (/\s/.test(ch)) {
104
- return null;
84
+
85
+ if (stream.match(settings.leftDelimiter, true)) {
86
+ state.depth++;
87
+ return helpers.cont("tag", "startTag");
105
88
  }
106
- return ret("tag", "tag");
107
- }
108
- }
109
89
 
110
- function inAttribute(quote) {
111
- return function(stream, state) {
112
- while (!stream.eol()) {
113
- if (stream.next() == quote) {
114
- state.tokenize = inSmarty;
115
- break;
90
+ var ch = stream.next();
91
+ if (ch == "$") {
92
+ stream.eatWhile(regs.validIdentifier);
93
+ return helpers.cont("variable-2", "variable");
94
+ } else if (ch == "|") {
95
+ return helpers.cont("operator", "pipe");
96
+ } else if (ch == ".") {
97
+ return helpers.cont("operator", "property");
98
+ } else if (regs.stringChar.test(ch)) {
99
+ state.tokenize = parsers.inAttribute(ch);
100
+ return helpers.cont("string", "string");
101
+ } else if (regs.operatorChars.test(ch)) {
102
+ stream.eatWhile(regs.operatorChars);
103
+ return helpers.cont("operator", "operator");
104
+ } else if (ch == "[" || ch == "]") {
105
+ return helpers.cont("bracket", "bracket");
106
+ } else if (ch == "(" || ch == ")") {
107
+ return helpers.cont("bracket", "operator");
108
+ } else if (/\d/.test(ch)) {
109
+ stream.eatWhile(/\d/);
110
+ return helpers.cont("number", "number");
111
+ } else {
112
+
113
+ if (state.last == "variable") {
114
+ if (ch == "@") {
115
+ stream.eatWhile(regs.validIdentifier);
116
+ return helpers.cont("property", "property");
117
+ } else if (ch == "|") {
118
+ stream.eatWhile(regs.validIdentifier);
119
+ return helpers.cont("qualifier", "modifier");
120
+ }
121
+ } else if (state.last == "pipe") {
122
+ stream.eatWhile(regs.validIdentifier);
123
+ return helpers.cont("qualifier", "modifier");
124
+ } else if (state.last == "whitespace") {
125
+ stream.eatWhile(regs.validIdentifier);
126
+ return helpers.cont("attribute", "modifier");
127
+ } if (state.last == "property") {
128
+ stream.eatWhile(regs.validIdentifier);
129
+ return helpers.cont("property", null);
130
+ } else if (/\s/.test(ch)) {
131
+ last = "whitespace";
132
+ return null;
116
133
  }
117
- }
118
- return "string";
119
- };
120
- }
121
134
 
122
- function inBlock(style, terminator) {
123
- return function(stream, state) {
124
- while (!stream.eol()) {
125
- if (stream.match(terminator)) {
126
- state.tokenize = tokenizer;
127
- break;
135
+ var str = "";
136
+ if (ch != "/") {
137
+ str += ch;
128
138
  }
129
- stream.next();
139
+ var c = null;
140
+ while (c = stream.eat(regs.validIdentifier)) {
141
+ str += c;
142
+ }
143
+ for (var i=0, j=keyFunctions.length; i<j; i++) {
144
+ if (keyFunctions[i] == str) {
145
+ return helpers.cont("keyword", "keyword");
146
+ }
147
+ }
148
+ if (/\s/.test(ch)) {
149
+ return null;
150
+ }
151
+ return helpers.cont("tag", "tag");
130
152
  }
131
- return style;
132
- };
133
- }
153
+ },
154
+
155
+ inAttribute: function(quote) {
156
+ return function(stream, state) {
157
+ var prevChar = null;
158
+ var currChar = null;
159
+ while (!stream.eol()) {
160
+ currChar = stream.peek();
161
+ if (stream.next() == quote && prevChar !== '\\') {
162
+ state.tokenize = parsers.smarty;
163
+ break;
164
+ }
165
+ prevChar = currChar;
166
+ }
167
+ return "string";
168
+ };
169
+ },
170
+
171
+ inBlock: function(style, terminator) {
172
+ return function(stream, state) {
173
+ while (!stream.eol()) {
174
+ if (stream.match(terminator)) {
175
+ state.tokenize = parsers.tokenizer;
176
+ break;
177
+ }
178
+ stream.next();
179
+ }
180
+ return style;
181
+ };
182
+ }
183
+ };
184
+
134
185
 
186
+ // the public API for CodeMirror
135
187
  return {
136
188
  startState: function() {
137
- return { tokenize: tokenizer, mode: "smarty", last: null };
189
+ return {
190
+ tokenize: parsers.tokenizer,
191
+ mode: "smarty",
192
+ last: null,
193
+ depth: 0
194
+ };
138
195
  },
139
196
  token: function(stream, state) {
140
197
  var style = state.tokenize(stream, state);