codemirror-rails 4.8 → 4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -6
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +289 -184
  5. data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/display/panel.js +94 -0
  7. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +4 -4
  8. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +1 -2
  9. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +1 -1
  10. data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +8 -3
  12. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +7 -4
  14. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +3 -4
  15. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +170 -63
  16. data/vendor/assets/javascripts/codemirror/addons/mode/simple.js +11 -8
  17. data/vendor/assets/javascripts/codemirror/addons/scroll/annotatescrollbar.js +76 -0
  18. data/vendor/assets/javascripts/codemirror/addons/scroll/simplescrollbars.js +139 -0
  19. data/vendor/assets/javascripts/codemirror/addons/search/matchesonscrollbar.js +90 -0
  20. data/vendor/assets/javascripts/codemirror/addons/search/search.js +9 -4
  21. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +5 -3
  22. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +25 -7
  23. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +181 -109
  24. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -2
  25. data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +5 -3
  26. data/vendor/assets/javascripts/codemirror/modes/cypher.js +1 -1
  27. data/vendor/assets/javascripts/codemirror/modes/dart.js +50 -0
  28. data/vendor/assets/javascripts/codemirror/modes/dockerfile.js +5 -9
  29. data/vendor/assets/javascripts/codemirror/modes/ebnf.js +195 -0
  30. data/vendor/assets/javascripts/codemirror/modes/javascript.js +2 -0
  31. data/vendor/assets/javascripts/codemirror/modes/markdown.js +3 -3
  32. data/vendor/assets/javascripts/codemirror/modes/puppet.js +2 -2
  33. data/vendor/assets/javascripts/codemirror/modes/shell.js +2 -1
  34. data/vendor/assets/javascripts/codemirror/modes/soy.js +198 -0
  35. data/vendor/assets/javascripts/codemirror/modes/spreadsheet.js +109 -0
  36. data/vendor/assets/javascripts/codemirror/modes/stex.js +4 -6
  37. data/vendor/assets/javascripts/codemirror/modes/textile.js +392 -476
  38. data/vendor/assets/javascripts/codemirror/modes/turtle.js +3 -1
  39. data/vendor/assets/stylesheets/codemirror.css +2 -11
  40. data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +14 -0
  41. data/vendor/assets/stylesheets/codemirror/addons/scroll/simplescrollbars.css +66 -0
  42. data/vendor/assets/stylesheets/codemirror/addons/search/matchesonscrollbar.css +8 -0
  43. data/vendor/assets/stylesheets/codemirror/themes/tomorrow-night-bright.css +35 -0
  44. data/vendor/assets/stylesheets/codemirror/themes/zenburn.css +37 -0
  45. metadata +14 -3
  46. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +0 -102
@@ -62,7 +62,7 @@
62
62
  var curPunc;
63
63
  var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "right", "round", "rtrim", "shortestPath", "sign", "sin", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "trim", "type", "upper"]);
64
64
  var preds = wordRegexp(["all", "and", "any", "has", "in", "none", "not", "or", "single", "xor"]);
65
- var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "distinct", "drop", "else", "end", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "remove", "return", "scan", "set", "skip", "start", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]);
65
+ var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "distinct", "drop", "else", "end", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]);
66
66
  var operatorChars = /[*+\-<>=&|~%^]/;
67
67
 
68
68
  return {
@@ -0,0 +1,50 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../clike/clike"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../clike/clike"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var keywords = ("this super static final const abstract class extends external factory " +
15
+ "implements get native operator set typedef with enum throw rethrow " +
16
+ "assert break case continue default in return new deferred async await " +
17
+ "try catch finally do else for if switch while import library export " +
18
+ "part of show hide is").split(" ");
19
+ var blockKeywords = "try catch finally do else for if switch while".split(" ");
20
+ var atoms = "true false null".split(" ");
21
+ var builtins = "void bool num int double dynamic var String".split(" ");
22
+
23
+ function set(words) {
24
+ var obj = {};
25
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
26
+ return obj;
27
+ }
28
+
29
+ CodeMirror.defineMIME("application/dart", {
30
+ name: "clike",
31
+ keywords: set(keywords),
32
+ multiLineStrings: true,
33
+ blockKeywords: set(blockKeywords),
34
+ builtin: set(builtins),
35
+ atoms: set(atoms),
36
+ hooks: {
37
+ "@": function(stream) {
38
+ stream.eatWhile(/[\w\$_]/);
39
+ return "meta";
40
+ }
41
+ }
42
+ });
43
+
44
+ CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins));
45
+
46
+ // This is needed to make loading through meta.js work.
47
+ CodeMirror.defineMode("dart", function(conf) {
48
+ return CodeMirror.getMode(conf, "application/dart");
49
+ }, "clike");
50
+ });
@@ -24,14 +24,12 @@
24
24
  // Block comment: This is a line starting with a comment
25
25
  {
26
26
  regex: /#.*$/,
27
- token: "comment",
28
- next: "start"
27
+ token: "comment"
29
28
  },
30
29
  // Highlight an instruction without any arguments (for convenience)
31
30
  {
32
31
  regex: instructionOnlyLine,
33
- token: "variable-2",
34
- next: "start"
32
+ token: "variable-2"
35
33
  },
36
34
  // Highlight an instruction followed by arguments
37
35
  {
@@ -39,10 +37,9 @@
39
37
  token: ["variable-2", null],
40
38
  next: "arguments"
41
39
  },
42
- // Fail-safe return to start
43
40
  {
44
- token: null,
45
- next: "start"
41
+ regex: /./,
42
+ token: null
46
43
  }
47
44
  ],
48
45
  arguments: [
@@ -54,8 +51,7 @@
54
51
  },
55
52
  {
56
53
  regex: /[^#]+\\$/,
57
- token: null,
58
- next: "arguments"
54
+ token: null
59
55
  },
60
56
  {
61
57
  // Match everything except for the inline comment
@@ -0,0 +1,195 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ CodeMirror.defineMode("ebnf", function (config) {
15
+ var commentType = {slash: 0, parenthesis: 1};
16
+ var stateType = {comment: 0, _string: 1, characterClass: 2};
17
+ var bracesMode = null;
18
+
19
+ if (config.bracesMode)
20
+ bracesMode = CodeMirror.getMode(config, config.bracesMode);
21
+
22
+ return {
23
+ startState: function () {
24
+ return {
25
+ stringType: null,
26
+ commentType: null,
27
+ braced: 0,
28
+ lhs: true,
29
+ localState: null,
30
+ stack: [],
31
+ inDefinition: false
32
+ };
33
+ },
34
+ token: function (stream, state) {
35
+ if (!stream) return;
36
+
37
+ //check for state changes
38
+ if (state.stack.length === 0) {
39
+ //strings
40
+ if ((stream.peek() == '"') || (stream.peek() == "'")) {
41
+ state.stringType = stream.peek();
42
+ stream.next(); // Skip quote
43
+ state.stack.unshift(stateType._string);
44
+ } else if (stream.match(/^\/\*/)) { //comments starting with /*
45
+ state.stack.unshift(stateType.comment);
46
+ state.commentType = commentType.slash;
47
+ } else if (stream.match(/^\(\*/)) { //comments starting with (*
48
+ state.stack.unshift(stateType.comment);
49
+ state.commentType = commentType.parenthesis;
50
+ }
51
+ }
52
+
53
+ //return state
54
+ //stack has
55
+ switch (state.stack[0]) {
56
+ case stateType._string:
57
+ while (state.stack[0] === stateType._string && !stream.eol()) {
58
+ if (stream.peek() === state.stringType) {
59
+ stream.next(); // Skip quote
60
+ state.stack.shift(); // Clear flag
61
+ } else if (stream.peek() === "\\") {
62
+ stream.next();
63
+ stream.next();
64
+ } else {
65
+ stream.match(/^.[^\\\"\']*/);
66
+ }
67
+ }
68
+ return state.lhs ? "property string" : "string"; // Token style
69
+
70
+ case stateType.comment:
71
+ while (state.stack[0] === stateType.comment && !stream.eol()) {
72
+ if (state.commentType === commentType.slash && stream.match(/\*\//)) {
73
+ state.stack.shift(); // Clear flag
74
+ state.commentType = null;
75
+ } else if (state.commentType === commentType.parenthesis && stream.match(/\*\)/)) {
76
+ state.stack.shift(); // Clear flag
77
+ state.commentType = null;
78
+ } else {
79
+ stream.match(/^.[^\*]*/);
80
+ }
81
+ }
82
+ return "comment";
83
+
84
+ case stateType.characterClass:
85
+ while (state.stack[0] === stateType.characterClass && !stream.eol()) {
86
+ if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) {
87
+ state.stack.shift();
88
+ }
89
+ }
90
+ return "operator";
91
+ }
92
+
93
+ var peek = stream.peek();
94
+
95
+ if (bracesMode !== null && (state.braced || peek === "{")) {
96
+ if (state.localState === null)
97
+ state.localState = bracesMode.startState();
98
+
99
+ var token = bracesMode.token(stream, state.localState),
100
+ text = stream.current();
101
+
102
+ if (!token) {
103
+ for (var i = 0; i < text.length; i++) {
104
+ if (text[i] === "{") {
105
+ if (state.braced === 0) {
106
+ token = "matchingbracket";
107
+ }
108
+ state.braced++;
109
+ } else if (text[i] === "}") {
110
+ state.braced--;
111
+ if (state.braced === 0) {
112
+ token = "matchingbracket";
113
+ }
114
+ }
115
+ }
116
+ }
117
+ return token;
118
+ }
119
+
120
+ //no stack
121
+ switch (peek) {
122
+ case "[":
123
+ stream.next();
124
+ state.stack.unshift(stateType.characterClass);
125
+ return "bracket";
126
+ case ":":
127
+ case "|":
128
+ case ";":
129
+ stream.next();
130
+ return "operator";
131
+ case "%":
132
+ if (stream.match("%%")) {
133
+ return "header";
134
+ } else if (stream.match(/[%][A-Za-z]+/)) {
135
+ return "keyword";
136
+ } else if (stream.match(/[%][}]/)) {
137
+ return "matchingbracket";
138
+ }
139
+ break;
140
+ case "/":
141
+ if (stream.match(/[\/][A-Za-z]+/)) {
142
+ return "keyword";
143
+ }
144
+ case "\\":
145
+ if (stream.match(/[\][a-z]+/)) {
146
+ return "string-2";
147
+ }
148
+ case ".":
149
+ if (stream.match(".")) {
150
+ return "atom";
151
+ }
152
+ case "*":
153
+ case "-":
154
+ case "+":
155
+ case "^":
156
+ if (stream.match(peek)) {
157
+ return "atom";
158
+ }
159
+ case "$":
160
+ if (stream.match("$$")) {
161
+ return "builtin";
162
+ } else if (stream.match(/[$][0-9]+/)) {
163
+ return "variable-3";
164
+ }
165
+ case "<":
166
+ if (stream.match(/<<[a-zA-Z_]+>>/)) {
167
+ return "builtin";
168
+ }
169
+ }
170
+
171
+ if (stream.match(/^\/\//)) {
172
+ stream.skipToEnd();
173
+ return "comment";
174
+ } else if (stream.match(/return/)) {
175
+ return "operator";
176
+ } else if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {
177
+ if (stream.match(/(?=[\(.])/)) {
178
+ return "variable";
179
+ } else if (stream.match(/(?=[\s\n]*[:=])/)) {
180
+ return "def";
181
+ }
182
+ return "variable-2";
183
+ } else if (["[", "]", "(", ")"].indexOf(stream.peek()) != -1) {
184
+ stream.next();
185
+ return "bracket";
186
+ } else if (!stream.eatSpace()) {
187
+ stream.next();
188
+ }
189
+ return null;
190
+ }
191
+ };
192
+ });
193
+
194
+ CodeMirror.defineMIME("text/x-ebnf", "ebnf");
195
+ });
@@ -205,6 +205,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
205
205
  ++depth;
206
206
  } else if (wordRE.test(ch)) {
207
207
  sawSomething = true;
208
+ } else if (/["'\/]/.test(ch)) {
209
+ return;
208
210
  } else if (sawSomething && !depth) {
209
211
  ++pos;
210
212
  break;
@@ -3,7 +3,7 @@
3
3
 
4
4
  (function(mod) {
5
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
- mod(require("../../lib/codemirror", require("../xml/xml"), require("../meta")));
6
+ mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
7
7
  else if (typeof define == "function" && define.amd) // AMD
8
8
  define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
9
9
  else // Plain browser env
@@ -396,13 +396,13 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
396
396
  return image;
397
397
  }
398
398
 
399
- if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
399
+ if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) {
400
400
  state.linkText = true;
401
401
  if (modeCfg.highlightFormatting) state.formatting = "link";
402
402
  return getType(state);
403
403
  }
404
404
 
405
- if (ch === ']' && state.linkText) {
405
+ if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) {
406
406
  if (modeCfg.highlightFormatting) state.formatting = "link";
407
407
  var type = getType(state);
408
408
  state.linkText = false;
@@ -140,11 +140,11 @@ CodeMirror.defineMode("puppet", function () {
140
140
  return words[word];
141
141
  }
142
142
  // Is there a match on a reference?
143
- if (/(\s+)?[A-Z]/.test(word)) {
143
+ if (/(^|\s+)[A-Z][\w:_]+/.test(word)) {
144
144
  // Negate the next()
145
145
  stream.backUp(1);
146
146
  // Match the full reference
147
- stream.match(/(\s+)?[A-Z][\w:_]+/);
147
+ stream.match(/(^|\s+)[A-Z][\w:_]+/);
148
148
  return 'def';
149
149
  }
150
150
  // Have we matched the prior resource regex?
@@ -129,7 +129,8 @@ CodeMirror.defineMode('shell', function() {
129
129
  token: function(stream, state) {
130
130
  return tokenize(stream, state);
131
131
  },
132
- lineComment: '#'
132
+ lineComment: '#',
133
+ fold: "brace"
133
134
  };
134
135
  });
135
136
 
@@ -0,0 +1,198 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../htmlmixed/htmlmixed"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var indentingTags = ["template", "literal", "msg", "fallbackmsg", "let", "if", "elseif",
15
+ "else", "switch", "case", "default", "foreach", "ifempty", "for",
16
+ "call", "param", "deltemplate", "delcall", "log"];
17
+
18
+ CodeMirror.defineMode("soy", function(config) {
19
+ var textMode = CodeMirror.getMode(config, "text/plain");
20
+ var modes = {
21
+ html: CodeMirror.getMode(config, {name: "text/html", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false}),
22
+ attributes: textMode,
23
+ text: textMode,
24
+ uri: textMode,
25
+ css: CodeMirror.getMode(config, "text/css"),
26
+ js: CodeMirror.getMode(config, {name: "text/javascript", statementIndent: 2 * config.indentUnit})
27
+ };
28
+
29
+ function last(array) {
30
+ return array[array.length - 1];
31
+ }
32
+
33
+ function tokenUntil(stream, state, untilRegExp) {
34
+ var oldString = stream.string;
35
+ var match = untilRegExp.exec(oldString.substr(stream.pos));
36
+ if (match) {
37
+ // We don't use backUp because it backs up just the position, not the state.
38
+ // This uses an undocumented API.
39
+ stream.string = oldString.substr(0, stream.pos + match.index);
40
+ }
41
+ var result = stream.hideFirstChars(state.indent, function() {
42
+ return state.localMode.token(stream, state.localState);
43
+ });
44
+ stream.string = oldString;
45
+ return result;
46
+ }
47
+
48
+ return {
49
+ startState: function() {
50
+ return {
51
+ kind: [],
52
+ kindTag: [],
53
+ soyState: [],
54
+ indent: 0,
55
+ localMode: modes.html,
56
+ localState: CodeMirror.startState(modes.html)
57
+ };
58
+ },
59
+
60
+ copyState: function(state) {
61
+ return {
62
+ tag: state.tag, // Last seen Soy tag.
63
+ kind: state.kind.concat([]), // Values of kind="" attributes.
64
+ kindTag: state.kindTag.concat([]), // Opened tags with kind="" attributes.
65
+ soyState: state.soyState.concat([]),
66
+ indent: state.indent, // Indentation of the following line.
67
+ localMode: state.localMode,
68
+ localState: CodeMirror.copyState(state.localMode, state.localState)
69
+ };
70
+ },
71
+
72
+ token: function(stream, state) {
73
+ var match;
74
+
75
+ switch (last(state.soyState)) {
76
+ case "comment":
77
+ if (stream.match(/^.*?\*\//)) {
78
+ state.soyState.pop();
79
+ } else {
80
+ stream.skipToEnd();
81
+ }
82
+ return "comment";
83
+
84
+ case "variable":
85
+ if (stream.match(/^}/)) {
86
+ state.indent -= 2 * config.indentUnit;
87
+ state.soyState.pop();
88
+ return "variable-2";
89
+ }
90
+ stream.next();
91
+ return null;
92
+
93
+ case "tag":
94
+ if (stream.match(/^\/?}/)) {
95
+ if (state.tag == "/template" || state.tag == "/deltemplate") state.indent = 0;
96
+ else state.indent -= (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit;
97
+ state.soyState.pop();
98
+ return "keyword";
99
+ } else if (stream.match(/^(\w+)(?==)/)) {
100
+ if (stream.current() == "kind" && (match = stream.match(/^="([^"]+)/, false))) {
101
+ var kind = match[1];
102
+ state.kind.push(kind);
103
+ state.kindTag.push(state.tag);
104
+ state.localMode = modes[kind] || modes.html;
105
+ state.localState = CodeMirror.startState(state.localMode);
106
+ }
107
+ return "attribute";
108
+ } else if (stream.match(/^"/)) {
109
+ state.soyState.push("string");
110
+ return "string";
111
+ }
112
+ stream.next();
113
+ return null;
114
+
115
+ case "literal":
116
+ if (stream.match(/^(?=\{\/literal})/)) {
117
+ state.indent -= config.indentUnit;
118
+ state.soyState.pop();
119
+ return this.token(stream, state);
120
+ }
121
+ return tokenUntil(stream, state, /\{\/literal}/);
122
+
123
+ case "string":
124
+ if (stream.match(/^.*?"/)) {
125
+ state.soyState.pop();
126
+ } else {
127
+ stream.skipToEnd();
128
+ }
129
+ return "string";
130
+ }
131
+
132
+ if (stream.match(/^\/\*/)) {
133
+ state.soyState.push("comment");
134
+ return "comment";
135
+ } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) {
136
+ return "comment";
137
+ } else if (stream.match(/^\{\$\w*/)) {
138
+ state.indent += 2 * config.indentUnit;
139
+ state.soyState.push("variable");
140
+ return "variable-2";
141
+ } else if (stream.match(/^\{literal}/)) {
142
+ state.indent += config.indentUnit;
143
+ state.soyState.push("literal");
144
+ return "keyword";
145
+ } else if (match = stream.match(/^\{([\/@\\]?\w*)/)) {
146
+ if (match[1] != "/switch")
147
+ state.indent += (/^(\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit;
148
+ state.tag = match[1];
149
+ if (state.tag == "/" + last(state.kindTag)) {
150
+ // We found the tag that opened the current kind="".
151
+ state.kind.pop();
152
+ state.kindTag.pop();
153
+ state.localMode = modes[last(state.kind)] || modes.html;
154
+ state.localState = CodeMirror.startState(state.localMode);
155
+ }
156
+ state.soyState.push("tag");
157
+ return "keyword";
158
+ }
159
+
160
+ return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/);
161
+ },
162
+
163
+ indent: function(state, textAfter) {
164
+ var indent = state.indent, top = last(state.soyState);
165
+ if (top == "comment") return CodeMirror.Pass;
166
+
167
+ if (top == "literal") {
168
+ if (/^\{\/literal}/.test(textAfter)) indent -= config.indentUnit;
169
+ } else {
170
+ if (/^\s*\{\/(template|deltemplate)\b/.test(textAfter)) return 0;
171
+ if (/^\{(\/|(fallbackmsg|elseif|else|ifempty)\b)/.test(textAfter)) indent -= config.indentUnit;
172
+ if (state.tag != "switch" && /^\{(case|default)\b/.test(textAfter)) indent -= config.indentUnit;
173
+ if (/^\{\/switch\b/.test(textAfter)) indent -= config.indentUnit;
174
+ }
175
+ if (indent && state.localMode.indent)
176
+ indent += state.localMode.indent(state.localState, textAfter);
177
+ return indent;
178
+ },
179
+
180
+ innerMode: function(state) {
181
+ if (state.soyState.length && last(state.soyState) != "literal") return null;
182
+ else return {state: state.localState, mode: state.localMode};
183
+ },
184
+
185
+ electricInput: /^\s*\{(\/|\/template|\/deltemplate|\/switch|fallbackmsg|elseif|else|case|default|ifempty|\/literal\})$/,
186
+ lineComment: "//",
187
+ blockCommentStart: "/*",
188
+ blockCommentEnd: "*/",
189
+ blockCommentContinue: " * ",
190
+ fold: "indent"
191
+ };
192
+ }, "htmlmixed");
193
+
194
+ CodeMirror.registerHelper("hintWords", "soy", indentingTags.concat(
195
+ ["delpackage", "namespace", "alias", "print", "css", "debugger"]));
196
+
197
+ CodeMirror.defineMIME("text/x-soy", "soy");
198
+ });