codemirror-rails 3.20 → 3.21

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +240 -135
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +6 -2
  5. data/vendor/assets/javascripts/codemirror/addons/comment/continuecomment.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -0
  7. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +5 -3
  8. data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +10 -6
  9. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +2 -0
  10. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/addons/fold/comment-fold.js +3 -1
  12. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +13 -2
  13. data/vendor/assets/javascripts/codemirror/addons/fold/foldgutter.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +2 -2
  15. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +6 -0
  16. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +3 -5
  17. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +29 -33
  18. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/addons/hint/pig-hint.js +1 -1
  20. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +1 -5
  21. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +58 -9
  22. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +58 -17
  23. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +5 -5
  24. data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +1 -1
  25. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +6 -1
  26. data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +5 -3
  27. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +26 -11
  28. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +1 -1
  29. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +22 -11
  30. data/vendor/assets/javascripts/codemirror/addons/search/search.js +22 -9
  31. data/vendor/assets/javascripts/codemirror/addons/search/searchcursor.js +48 -24
  32. data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +15 -9
  33. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +3 -3
  34. data/vendor/assets/javascripts/codemirror/addons/wrap/hardwrap.js +21 -9
  35. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +12 -1
  36. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +110 -28
  37. data/vendor/assets/javascripts/codemirror/modes/clike.js +28 -9
  38. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +3 -4
  39. data/vendor/assets/javascripts/codemirror/modes/css.js +341 -297
  40. data/vendor/assets/javascripts/codemirror/modes/erlang.js +302 -179
  41. data/vendor/assets/javascripts/codemirror/modes/gfm.js +10 -5
  42. data/vendor/assets/javascripts/codemirror/modes/gherkin.js +45 -50
  43. data/vendor/assets/javascripts/codemirror/modes/haml.js +0 -4
  44. data/vendor/assets/javascripts/codemirror/modes/haskell.js +5 -3
  45. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +0 -2
  46. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +0 -2
  47. data/vendor/assets/javascripts/codemirror/modes/javascript.js +43 -30
  48. data/vendor/assets/javascripts/codemirror/modes/jinja2.js +13 -3
  49. data/vendor/assets/javascripts/codemirror/modes/less.js +7 -6
  50. data/vendor/assets/javascripts/codemirror/modes/markdown.js +231 -45
  51. data/vendor/assets/javascripts/codemirror/modes/{ocaml.js → mllike.js} +88 -13
  52. data/vendor/assets/javascripts/codemirror/modes/pegjs.js +5 -9
  53. data/vendor/assets/javascripts/codemirror/modes/php.js +6 -7
  54. data/vendor/assets/javascripts/codemirror/modes/python.js +6 -0
  55. data/vendor/assets/javascripts/codemirror/modes/r.js +5 -1
  56. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  57. data/vendor/assets/javascripts/codemirror/modes/ruby.js +3 -1
  58. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +4 -2
  59. data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +0 -2
  60. data/vendor/assets/javascripts/codemirror/modes/sql.js +5 -4
  61. data/vendor/assets/javascripts/codemirror/modes/xml.js +87 -100
  62. data/vendor/assets/stylesheets/codemirror/themes/mbo.css +1 -1
  63. data/vendor/assets/stylesheets/codemirror/themes/midnight.css +1 -1
  64. data/vendor/assets/stylesheets/codemirror/themes/pastel-on-dark.css +49 -0
  65. data/vendor/assets/stylesheets/codemirror/themes/the-matrix.css +1 -1
  66. metadata +3 -2
@@ -203,18 +203,34 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
203
203
  return "string";
204
204
  }
205
205
 
206
- function mimes(ms, mode) {
207
- for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
206
+ function def(mimes, mode) {
207
+ var words = [];
208
+ function add(obj) {
209
+ if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
210
+ words.push(prop);
211
+ }
212
+ add(mode.keywords);
213
+ add(mode.builtin);
214
+ add(mode.atoms);
215
+ if (words.length) {
216
+ mode.helperType = mimes[0];
217
+ CodeMirror.registerHelper("hintWords", mimes[0], words);
218
+ }
219
+
220
+ for (var i = 0; i < mimes.length; ++i)
221
+ CodeMirror.defineMIME(mimes[i], mode);
208
222
  }
209
223
 
210
- mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
224
+ def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
211
225
  name: "clike",
212
226
  keywords: words(cKeywords),
213
227
  blockKeywords: words("case do else for if switch while struct"),
214
228
  atoms: words("null"),
215
- hooks: {"#": cppHook}
229
+ hooks: {"#": cppHook},
230
+ modeProps: {fold: ["brace", "include"]}
216
231
  });
217
- mimes(["text/x-c++src", "text/x-c++hdr"], {
232
+
233
+ def(["text/x-c++src", "text/x-c++hdr"], {
218
234
  name: "clike",
219
235
  keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
220
236
  "static_cast typeid catch operator template typename class friend private " +
@@ -222,7 +238,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
222
238
  "wchar_t"),
223
239
  blockKeywords: words("catch class do else finally for if struct switch try while"),
224
240
  atoms: words("true false null"),
225
- hooks: {"#": cppHook}
241
+ hooks: {"#": cppHook},
242
+ modeProps: {fold: ["brace", "include"]}
226
243
  });
227
244
  CodeMirror.defineMIME("text/x-java", {
228
245
  name: "clike",
@@ -238,7 +255,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
238
255
  stream.eatWhile(/[\w\$_]/);
239
256
  return "meta";
240
257
  }
241
- }
258
+ },
259
+ modeProps: {fold: ["brace", "import"]}
242
260
  });
243
261
  CodeMirror.defineMIME("text/x-csharp", {
244
262
  name: "clike",
@@ -303,7 +321,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
303
321
  }
304
322
  }
305
323
  });
306
- mimes(["x-shader/x-vertex", "x-shader/x-fragment"], {
324
+ def(["x-shader/x-vertex", "x-shader/x-fragment"], {
307
325
  name: "clike",
308
326
  keywords: words("float int bool void " +
309
327
  "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
@@ -357,6 +375,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
357
375
  "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
358
376
  "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
359
377
  "gl_MaxDrawBuffers"),
360
- hooks: {"#": cppHook}
378
+ hooks: {"#": cppHook},
379
+ modeProps: {fold: ["brace", "include"]}
361
380
  });
362
381
  }());
@@ -119,13 +119,13 @@ CodeMirror.defineMode("coffeescript", function(conf) {
119
119
 
120
120
  // Handle strings
121
121
  if (stream.match(stringPrefixes)) {
122
- state.tokenize = tokenFactory(stream.current(), "string");
122
+ state.tokenize = tokenFactory(stream.current(), false, "string");
123
123
  return state.tokenize(stream, state);
124
124
  }
125
125
  // Handle regex literals
126
126
  if (stream.match(regexPrefixes)) {
127
127
  if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division
128
- state.tokenize = tokenFactory(stream.current(), "string-2");
128
+ state.tokenize = tokenFactory(stream.current(), true, "string-2");
129
129
  return state.tokenize(stream, state);
130
130
  } else {
131
131
  stream.backUp(1);
@@ -161,8 +161,7 @@ CodeMirror.defineMode("coffeescript", function(conf) {
161
161
  return ERRORCLASS;
162
162
  }
163
163
 
164
- function tokenFactory(delimiter, outclass) {
165
- var singleline = delimiter.length == 1;
164
+ function tokenFactory(delimiter, singleline, outclass) {
166
165
  return function(stream, state) {
167
166
  while (!stream.eol()) {
168
167
  stream.eatWhile(/[^'"\/\\]/);
@@ -3,87 +3,80 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
3
3
 
4
4
  if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
5
5
 
6
- var indentUnit = config.indentUnit || config.tabSize || 2,
7
- hooks = parserConfig.hooks || {},
8
- atMediaTypes = parserConfig.atMediaTypes || {},
9
- atMediaFeatures = parserConfig.atMediaFeatures || {},
6
+ var indentUnit = config.indentUnit,
7
+ tokenHooks = parserConfig.tokenHooks,
8
+ mediaTypes = parserConfig.mediaTypes || {},
9
+ mediaFeatures = parserConfig.mediaFeatures || {},
10
10
  propertyKeywords = parserConfig.propertyKeywords || {},
11
11
  colorKeywords = parserConfig.colorKeywords || {},
12
12
  valueKeywords = parserConfig.valueKeywords || {},
13
- allowNested = !!parserConfig.allowNested,
14
- type = null;
13
+ fontProperties = parserConfig.fontProperties || {},
14
+ allowNested = parserConfig.allowNested;
15
15
 
16
+ var type, override;
16
17
  function ret(style, tp) { type = tp; return style; }
17
18
 
19
+ // Tokenizers
20
+
18
21
  function tokenBase(stream, state) {
19
22
  var ch = stream.next();
20
- if (hooks[ch]) {
21
- // result[0] is style and result[1] is type
22
- var result = hooks[ch](stream, state);
23
+ if (tokenHooks[ch]) {
24
+ var result = tokenHooks[ch](stream, state);
23
25
  if (result !== false) return result;
24
26
  }
25
- if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
26
- else if (ch == "=") ret(null, "compare");
27
- else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
28
- else if (ch == "\"" || ch == "'") {
27
+ if (ch == "@") {
28
+ stream.eatWhile(/[\w\\\-]/);
29
+ return ret("def", stream.current());
30
+ } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
31
+ return ret(null, "compare");
32
+ } else if (ch == "\"" || ch == "'") {
29
33
  state.tokenize = tokenString(ch);
30
34
  return state.tokenize(stream, state);
31
- }
32
- else if (ch == "#") {
35
+ } else if (ch == "#") {
33
36
  stream.eatWhile(/[\w\\\-]/);
34
37
  return ret("atom", "hash");
35
- }
36
- else if (ch == "!") {
38
+ } else if (ch == "!") {
37
39
  stream.match(/^\s*\w*/);
38
40
  return ret("keyword", "important");
39
- }
40
- else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
41
+ } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
41
42
  stream.eatWhile(/[\w.%]/);
42
43
  return ret("number", "unit");
43
- }
44
- else if (ch === "-") {
45
- if (/\d/.test(stream.peek())) {
44
+ } else if (ch === "-") {
45
+ if (/[\d.]/.test(stream.peek())) {
46
46
  stream.eatWhile(/[\w.%]/);
47
47
  return ret("number", "unit");
48
48
  } else if (stream.match(/^[^-]+-/)) {
49
49
  return ret("meta", "meta");
50
50
  }
51
- }
52
- else if (/[,+>*\/]/.test(ch)) {
51
+ } else if (/[,+>*\/]/.test(ch)) {
53
52
  return ret(null, "select-op");
54
- }
55
- else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
53
+ } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
56
54
  return ret("qualifier", "qualifier");
57
- }
58
- else if (ch == ":") {
59
- return ret("operator", ch);
60
- }
61
- else if (/[;{}\[\]\(\)]/.test(ch)) {
55
+ } else if (/[:;{}\[\]\(\)]/.test(ch)) {
62
56
  return ret(null, ch);
63
- }
64
- else if (ch == "u" && stream.match("rl(")) {
57
+ } else if (ch == "u" && stream.match("rl(")) {
65
58
  stream.backUp(1);
66
59
  state.tokenize = tokenParenthesized;
67
- return ret("property", "variable");
68
- }
69
- else {
60
+ return ret("property", "word");
61
+ } else if (/[\w\\\-]/.test(ch)) {
70
62
  stream.eatWhile(/[\w\\\-]/);
71
- return ret("property", "variable");
63
+ return ret("property", "word");
64
+ } else {
65
+ return ret(null, null);
72
66
  }
73
67
  }
74
68
 
75
- function tokenString(quote, nonInclusive) {
69
+ function tokenString(quote) {
76
70
  return function(stream, state) {
77
71
  var escaped = false, ch;
78
72
  while ((ch = stream.next()) != null) {
79
- if (ch == quote && !escaped)
73
+ if (ch == quote && !escaped) {
74
+ if (quote == ")") stream.backUp(1);
80
75
  break;
76
+ }
81
77
  escaped = !escaped && ch == "\\";
82
78
  }
83
- if (!escaped) {
84
- if (nonInclusive) stream.backUp(1);
85
- state.tokenize = tokenBase;
86
- }
79
+ if (ch == quote || !escaped && quote != ")") state.tokenize = null;
87
80
  return ret("string", "string");
88
81
  };
89
82
  }
@@ -91,218 +84,238 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
91
84
  function tokenParenthesized(stream, state) {
92
85
  stream.next(); // Must be '('
93
86
  if (!stream.match(/\s*[\"\']/, false))
94
- state.tokenize = tokenString(")", true);
87
+ state.tokenize = tokenString(")");
95
88
  else
96
- state.tokenize = tokenBase;
89
+ state.tokenize = null;
97
90
  return ret(null, "(");
98
91
  }
99
92
 
93
+ // Context management
94
+
95
+ function Context(type, indent, prev) {
96
+ this.type = type;
97
+ this.indent = indent;
98
+ this.prev = prev;
99
+ }
100
+
101
+ function pushContext(state, stream, type) {
102
+ state.context = new Context(type, stream.indentation() + indentUnit, state.context);
103
+ return type;
104
+ }
105
+
106
+ function popContext(state) {
107
+ state.context = state.context.prev;
108
+ return state.context.type;
109
+ }
110
+
111
+ function pass(type, stream, state) {
112
+ return states[state.context.type](type, stream, state);
113
+ }
114
+ function popAndPass(type, stream, state, n) {
115
+ for (var i = n || 1; i > 0; i--)
116
+ state.context = state.context.prev;
117
+ return pass(type, stream, state);
118
+ }
119
+
120
+ // Parser
121
+
122
+ function wordAsValue(stream) {
123
+ var word = stream.current().toLowerCase();
124
+ if (valueKeywords.hasOwnProperty(word))
125
+ override = "atom";
126
+ else if (colorKeywords.hasOwnProperty(word))
127
+ override = "keyword";
128
+ else
129
+ override = "variable";
130
+ }
131
+
132
+ var states = {};
133
+
134
+ states.top = function(type, stream, state) {
135
+ if (type == "{") {
136
+ return pushContext(state, stream, "block");
137
+ } else if (type == "}" && state.context.prev) {
138
+ return popContext(state);
139
+ } else if (type == "@media") {
140
+ return pushContext(state, stream, "media");
141
+ } else if (type == "@font-face") {
142
+ return "font_face_before";
143
+ } else if (type && type.charAt(0) == "@") {
144
+ return pushContext(state, stream, "at");
145
+ } else if (type == "hash") {
146
+ override = "builtin";
147
+ } else if (type == "word") {
148
+ override = "tag";
149
+ } else if (type == "variable-definition") {
150
+ return "maybeprop";
151
+ } else if (type == "interpolation") {
152
+ return pushContext(state, stream, "interpolation");
153
+ } else if (type == ":") {
154
+ return "pseudo";
155
+ } else if (allowNested && type == "(") {
156
+ return pushContext(state, stream, "params");
157
+ }
158
+ return state.context.type;
159
+ };
160
+
161
+ states.block = function(type, stream, state) {
162
+ if (type == "word") {
163
+ if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) {
164
+ override = "property";
165
+ return "maybeprop";
166
+ } else if (allowNested) {
167
+ override = stream.match(/^\s*:/, false) ? "property" : "tag";
168
+ return "block";
169
+ } else {
170
+ override += " error";
171
+ return "maybeprop";
172
+ }
173
+ } else if (type == "meta") {
174
+ return "block";
175
+ } else if (!allowNested && (type == "hash" || type == "qualifier")) {
176
+ override = "error";
177
+ return "block";
178
+ } else {
179
+ return states.top(type, stream, state);
180
+ }
181
+ };
182
+
183
+ states.maybeprop = function(type, stream, state) {
184
+ if (type == ":") return pushContext(state, stream, "prop");
185
+ return pass(type, stream, state);
186
+ };
187
+
188
+ states.prop = function(type, stream, state) {
189
+ if (type == ";") return popContext(state);
190
+ if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
191
+ if (type == "}" || type == "{") return popAndPass(type, stream, state);
192
+ if (type == "(") return pushContext(state, stream, "parens");
193
+
194
+ if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
195
+ override += " error";
196
+ } else if (type == "word") {
197
+ wordAsValue(stream);
198
+ } else if (type == "interpolation") {
199
+ return pushContext(state, stream, "interpolation");
200
+ }
201
+ return "prop";
202
+ };
203
+
204
+ states.propBlock = function(type, _stream, state) {
205
+ if (type == "}") return popContext(state);
206
+ if (type == "word") { override = "property"; return "maybeprop"; }
207
+ return state.context.type;
208
+ };
209
+
210
+ states.parens = function(type, stream, state) {
211
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
212
+ if (type == ")") return popContext(state);
213
+ return "parens";
214
+ };
215
+
216
+ states.pseudo = function(type, stream, state) {
217
+ if (type == "word") {
218
+ override = "variable-3";
219
+ return state.context.type;
220
+ }
221
+ return pass(type, stream, state);
222
+ };
223
+
224
+ states.media = function(type, stream, state) {
225
+ if (type == "(") return pushContext(state, stream, "media_parens");
226
+ if (type == "}") return popAndPass(type, stream, state);
227
+ if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
228
+
229
+ if (type == "word") {
230
+ var word = stream.current().toLowerCase();
231
+ if (word == "only" || word == "not" || word == "and")
232
+ override = "keyword";
233
+ else if (mediaTypes.hasOwnProperty(word))
234
+ override = "attribute";
235
+ else if (mediaFeatures.hasOwnProperty(word))
236
+ override = "property";
237
+ else
238
+ override = "error";
239
+ }
240
+ return state.context.type;
241
+ };
242
+
243
+ states.media_parens = function(type, stream, state) {
244
+ if (type == ")") return popContext(state);
245
+ if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
246
+ return states.media(type, stream, state);
247
+ };
248
+
249
+ states.font_face_before = function(type, stream, state) {
250
+ if (type == "{")
251
+ return pushContext(state, stream, "font_face");
252
+ return pass(type, stream, state);
253
+ };
254
+
255
+ states.font_face = function(type, stream, state) {
256
+ if (type == "}") return popContext(state);
257
+ if (type == "word") {
258
+ if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
259
+ override = "error";
260
+ else
261
+ override = "property";
262
+ return "maybeprop";
263
+ }
264
+ return "font_face";
265
+ };
266
+
267
+ states.at = function(type, stream, state) {
268
+ if (type == ";") return popContext(state);
269
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
270
+ if (type == "word") override = "tag";
271
+ else if (type == "hash") override = "builtin";
272
+ return "at";
273
+ };
274
+
275
+ states.interpolation = function(type, stream, state) {
276
+ if (type == "}") return popContext(state);
277
+ if (type == "{" || type == ";") return popAndPass(type, stream, state);
278
+ if (type != "variable") override = "error";
279
+ return "interpolation";
280
+ };
281
+
282
+ states.params = function(type, stream, state) {
283
+ if (type == ")") return popContext(state);
284
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
285
+ if (type == "word") wordAsValue(stream);
286
+ return "params";
287
+ };
288
+
100
289
  return {
101
290
  startState: function(base) {
102
- return {tokenize: tokenBase,
103
- baseIndent: base || 0,
104
- stack: [],
105
- lastToken: null};
291
+ return {tokenize: null,
292
+ state: "top",
293
+ context: new Context("top", base || 0, null)};
106
294
  },
107
295
 
108
296
  token: function(stream, state) {
109
-
110
- // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
111
- //
112
- // rule** or **ruleset:
113
- // A selector + braces combo, or an at-rule.
114
- //
115
- // declaration block:
116
- // A sequence of declarations.
117
- //
118
- // declaration:
119
- // A property + colon + value combo.
120
- //
121
- // property value:
122
- // The entire value of a property.
123
- //
124
- // component value:
125
- // A single piece of a property value. Like the 5px in
126
- // text-shadow: 0 0 5px blue;. Can also refer to things that are
127
- // multiple terms, like the 1-4 terms that make up the background-size
128
- // portion of the background shorthand.
129
- //
130
- // term:
131
- // The basic unit of author-facing CSS, like a single number (5),
132
- // dimension (5px), string ("foo"), or function. Officially defined
133
- // by the CSS 2.1 grammar (look for the 'term' production)
134
- //
135
- //
136
- // simple selector:
137
- // A single atomic selector, like a type selector, an attr selector, a
138
- // class selector, etc.
139
- //
140
- // compound selector:
141
- // One or more simple selectors without a combinator. div.example is
142
- // compound, div > .example is not.
143
- //
144
- // complex selector:
145
- // One or more compound selectors chained with combinators.
146
- //
147
- // combinator:
148
- // The parts of selectors that express relationships. There are four
149
- // currently - the space (descendant combinator), the greater-than
150
- // bracket (child combinator), the plus sign (next sibling combinator),
151
- // and the tilda (following sibling combinator).
152
- //
153
- // sequence of selectors:
154
- // One or more of the named type of selector chained with commas.
155
-
156
- state.tokenize = state.tokenize || tokenBase;
157
- if (state.tokenize == tokenBase && stream.eatSpace()) return null;
158
- var style = state.tokenize(stream, state);
159
- if (style && typeof style != "string") style = ret(style[0], style[1]);
160
-
161
- // Changing style returned based on context
162
- var context = state.stack[state.stack.length-1];
163
- if (style == "variable") {
164
- if (type == "variable-definition") state.stack.push("propertyValue");
165
- return state.lastToken = "variable-2";
166
- } else if (style == "property") {
167
- var word = stream.current().toLowerCase();
168
- if (context == "propertyValue") {
169
- if (valueKeywords.hasOwnProperty(word)) {
170
- style = "string-2";
171
- } else if (colorKeywords.hasOwnProperty(word)) {
172
- style = "keyword";
173
- } else {
174
- style = "variable-2";
175
- }
176
- } else if (context == "rule") {
177
- if (!propertyKeywords.hasOwnProperty(word)) {
178
- style += " error";
179
- }
180
- } else if (context == "block") {
181
- // if a value is present in both property, value, or color, the order
182
- // of preference is property -> color -> value
183
- if (propertyKeywords.hasOwnProperty(word)) {
184
- style = "property";
185
- } else if (colorKeywords.hasOwnProperty(word)) {
186
- style = "keyword";
187
- } else if (valueKeywords.hasOwnProperty(word)) {
188
- style = "string-2";
189
- } else {
190
- style = "tag";
191
- }
192
- } else if (!context || context == "@media{") {
193
- style = "tag";
194
- } else if (context == "@media") {
195
- if (atMediaTypes[stream.current()]) {
196
- style = "attribute"; // Known attribute
197
- } else if (/^(only|not)$/.test(word)) {
198
- style = "keyword";
199
- } else if (word == "and") {
200
- style = "error"; // "and" is only allowed in @mediaType
201
- } else if (atMediaFeatures.hasOwnProperty(word)) {
202
- style = "error"; // Known property, should be in @mediaType(
203
- } else {
204
- // Unknown, expecting keyword or attribute, assuming attribute
205
- style = "attribute error";
206
- }
207
- } else if (context == "@mediaType") {
208
- if (atMediaTypes.hasOwnProperty(word)) {
209
- style = "attribute";
210
- } else if (word == "and") {
211
- style = "operator";
212
- } else if (/^(only|not)$/.test(word)) {
213
- style = "error"; // Only allowed in @media
214
- } else {
215
- // Unknown attribute or property, but expecting property (preceded
216
- // by "and"). Should be in parentheses
217
- style = "error";
218
- }
219
- } else if (context == "@mediaType(") {
220
- if (propertyKeywords.hasOwnProperty(word)) {
221
- // do nothing, remains "property"
222
- } else if (atMediaTypes.hasOwnProperty(word)) {
223
- style = "error"; // Known property, should be in parentheses
224
- } else if (word == "and") {
225
- style = "operator";
226
- } else if (/^(only|not)$/.test(word)) {
227
- style = "error"; // Only allowed in @media
228
- } else {
229
- style += " error";
230
- }
231
- } else if (context == "@import") {
232
- style = "tag";
233
- } else {
234
- style = "error";
235
- }
236
- } else if (style == "atom") {
237
- if(!context || context == "@media{" || context == "block") {
238
- style = "builtin";
239
- } else if (context == "propertyValue") {
240
- if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
241
- style += " error";
242
- }
243
- } else {
244
- style = "error";
245
- }
246
- } else if (context == "@media" && type == "{") {
247
- style = "error";
248
- }
249
-
250
- // Push/pop context stack
251
- if (type == "{") {
252
- if (context == "@media" || context == "@mediaType") {
253
- state.stack[state.stack.length-1] = "@media{";
254
- }
255
- else {
256
- var newContext = allowNested ? "block" : "rule";
257
- state.stack.push(newContext);
258
- }
259
- }
260
- else if (type == "}") {
261
- if (context == "interpolation") style = "operator";
262
- // Pop off end of array until { is reached
263
- while(state.stack.length){
264
- var removed = state.stack.pop();
265
- if(removed.indexOf("{") > -1 || removed == "block" || removed == "rule"){
266
- break;
267
- }
268
- }
269
- }
270
- else if (type == "interpolation") state.stack.push("interpolation");
271
- else if (type == "@media") state.stack.push("@media");
272
- else if (type == "@import") state.stack.push("@import");
273
- else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
274
- state.stack[state.stack.length-1] = "@mediaType";
275
- else if (context == "@mediaType" && stream.current() == ",")
276
- state.stack[state.stack.length-1] = "@media";
277
- else if (type == "(") {
278
- if (context == "@media" || context == "@mediaType") {
279
- // Make sure @mediaType is used to avoid error on {
280
- state.stack[state.stack.length-1] = "@mediaType";
281
- state.stack.push("@mediaType(");
282
- }
283
- else state.stack.push("(");
297
+ if (!state.tokenize && stream.eatSpace()) return null;
298
+ var style = (state.tokenize || tokenBase)(stream, state);
299
+ if (style && typeof style == "object") {
300
+ type = style[1];
301
+ style = style[0];
284
302
  }
285
- else if (type == ")") {
286
- // Pop off end of array until ( is reached
287
- while(state.stack.length){
288
- var removed = state.stack.pop();
289
- if(removed.indexOf("(") > -1){
290
- break;
291
- }
292
- }
293
- }
294
- else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue");
295
- else if (context == "propertyValue" && type == ";") state.stack.pop();
296
- else if (context == "@import" && type == ";") state.stack.pop();
297
-
298
- return state.lastToken = style;
303
+ override = style;
304
+ state.state = states[state.state](type, stream, state);
305
+ return override;
299
306
  },
300
307
 
301
308
  indent: function(state, textAfter) {
302
- var n = state.stack.length;
303
- if (/^\}/.test(textAfter))
304
- n -= state.stack[n-1] == "propertyValue" ? 2 : 1;
305
- return state.baseIndent + n * indentUnit;
309
+ var cx = state.context, ch = textAfter && textAfter.charAt(0);
310
+ var indent = cx.indent;
311
+ if (cx.prev &&
312
+ (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
313
+ ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
314
+ ch == "{" && (cx.type == "at" || cx.type == "media"))) {
315
+ indent = cx.indent - indentUnit;
316
+ cx = cx.prev;
317
+ }
318
+ return indent;
306
319
  },
307
320
 
308
321
  electricChars: "}",
@@ -321,12 +334,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
321
334
  return keys;
322
335
  }
323
336
 
324
- var atMediaTypes = keySet([
337
+ var mediaTypes_ = [
325
338
  "all", "aural", "braille", "handheld", "print", "projection", "screen",
326
339
  "tty", "tv", "embossed"
327
- ]);
340
+ ], mediaTypes = keySet(mediaTypes_);
328
341
 
329
- var atMediaFeatures = keySet([
342
+ var mediaFeatures_ = [
330
343
  "width", "min-width", "max-width", "height", "min-height", "max-height",
331
344
  "device-width", "min-device-width", "max-device-width", "device-height",
332
345
  "min-device-height", "max-device-height", "aspect-ratio",
@@ -335,9 +348,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
335
348
  "max-color", "color-index", "min-color-index", "max-color-index",
336
349
  "monochrome", "min-monochrome", "max-monochrome", "resolution",
337
350
  "min-resolution", "max-resolution", "scan", "grid"
338
- ]);
351
+ ], mediaFeatures = keySet(mediaFeatures_);
339
352
 
340
- var propertyKeywords = keySet([
353
+ var propertyKeywords_ = [
341
354
  "align-content", "align-items", "align-self", "alignment-adjust",
342
355
  "alignment-baseline", "anchor-point", "animation", "animation-delay",
343
356
  "animation-direction", "animation-duration", "animation-iteration-count",
@@ -425,9 +438,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
425
438
  "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
426
439
  "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
427
440
  "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
428
- ]);
441
+ ], propertyKeywords = keySet(propertyKeywords_);
429
442
 
430
- var colorKeywords = keySet([
443
+ var colorKeywords_ = [
431
444
  "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
432
445
  "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
433
446
  "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
@@ -454,9 +467,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
454
467
  "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
455
468
  "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
456
469
  "whitesmoke", "yellow", "yellowgreen"
457
- ]);
470
+ ], colorKeywords = keySet(colorKeywords_);
458
471
 
459
- var valueKeywords = keySet([
472
+ var valueKeywords_ = [
460
473
  "above", "absolute", "activeborder", "activecaption", "afar",
461
474
  "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
462
475
  "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
@@ -539,7 +552,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
539
552
  "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
540
553
  "window", "windowframe", "windowtext", "x-large", "x-small", "xor",
541
554
  "xx-large", "xx-small"
542
- ]);
555
+ ], valueKeywords = keySet(valueKeywords_);
556
+
557
+ var fontProperties_ = [
558
+ "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
559
+ "font-stretch", "font-weight", "font-style"
560
+ ], fontProperties = keySet(fontProperties_);
561
+
562
+ var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
563
+ CodeMirror.registerHelper("hintWords", "css", allWords);
543
564
 
544
565
  function tokenCComment(stream, state) {
545
566
  var maybeEnd = false, ch;
@@ -553,67 +574,87 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
553
574
  return ["comment", "comment"];
554
575
  }
555
576
 
577
+ function tokenSGMLComment(stream, state) {
578
+ if (stream.skipTo("-->")) {
579
+ stream.match("-->");
580
+ state.tokenize = null;
581
+ } else {
582
+ stream.skipToEnd();
583
+ }
584
+ return ["comment", "comment"];
585
+ }
586
+
556
587
  CodeMirror.defineMIME("text/css", {
557
- atMediaTypes: atMediaTypes,
558
- atMediaFeatures: atMediaFeatures,
588
+ mediaTypes: mediaTypes,
589
+ mediaFeatures: mediaFeatures,
559
590
  propertyKeywords: propertyKeywords,
560
591
  colorKeywords: colorKeywords,
561
592
  valueKeywords: valueKeywords,
562
- hooks: {
593
+ fontProperties: fontProperties,
594
+ tokenHooks: {
563
595
  "<": function(stream, state) {
564
- function tokenSGMLComment(stream, state) {
565
- var dashes = 0, ch;
566
- while ((ch = stream.next()) != null) {
567
- if (dashes >= 2 && ch == ">") {
568
- state.tokenize = null;
569
- break;
570
- }
571
- dashes = (ch == "-") ? dashes + 1 : 0;
572
- }
573
- return ["comment", "comment"];
574
- }
575
- if (stream.eat("!")) {
576
- state.tokenize = tokenSGMLComment;
577
- return tokenSGMLComment(stream, state);
578
- }
596
+ if (!stream.match("!--")) return false;
597
+ state.tokenize = tokenSGMLComment;
598
+ return tokenSGMLComment(stream, state);
579
599
  },
580
600
  "/": function(stream, state) {
581
- if (stream.eat("*")) {
582
- state.tokenize = tokenCComment;
583
- return tokenCComment(stream, state);
584
- }
585
- return false;
601
+ if (!stream.eat("*")) return false;
602
+ state.tokenize = tokenCComment;
603
+ return tokenCComment(stream, state);
586
604
  }
587
605
  },
588
606
  name: "css"
589
607
  });
590
608
 
591
609
  CodeMirror.defineMIME("text/x-scss", {
592
- atMediaTypes: atMediaTypes,
593
- atMediaFeatures: atMediaFeatures,
610
+ mediaTypes: mediaTypes,
611
+ mediaFeatures: mediaFeatures,
594
612
  propertyKeywords: propertyKeywords,
595
613
  colorKeywords: colorKeywords,
596
614
  valueKeywords: valueKeywords,
615
+ fontProperties: fontProperties,
597
616
  allowNested: true,
598
- hooks: {
617
+ tokenHooks: {
618
+ "/": function(stream, state) {
619
+ if (stream.eat("/")) {
620
+ stream.skipToEnd();
621
+ return ["comment", "comment"];
622
+ } else if (stream.eat("*")) {
623
+ state.tokenize = tokenCComment;
624
+ return tokenCComment(stream, state);
625
+ } else {
626
+ return ["operator", "operator"];
627
+ }
628
+ },
599
629
  ":": function(stream) {
600
- if (stream.match(/\s*{/)) {
630
+ if (stream.match(/\s*{/))
601
631
  return [null, "{"];
602
- }
603
632
  return false;
604
633
  },
605
634
  "$": function(stream) {
606
635
  stream.match(/^[\w-]+/);
607
- if (stream.peek() == ":") {
608
- return ["variable", "variable-definition"];
609
- }
610
- return ["variable", "variable"];
611
- },
612
- ",": function(stream, state) {
613
- if (state.stack[state.stack.length - 1] == "propertyValue" && stream.match(/^ *\$/, false)) {
614
- return ["operator", ";"];
615
- }
636
+ if (stream.match(/^\s*:/, false))
637
+ return ["variable-2", "variable-definition"];
638
+ return ["variable-2", "variable"];
616
639
  },
640
+ "#": function(stream) {
641
+ if (!stream.eat("{")) return false;
642
+ return [null, "interpolation"];
643
+ }
644
+ },
645
+ name: "css",
646
+ helperType: "scss"
647
+ });
648
+
649
+ CodeMirror.defineMIME("text/x-less", {
650
+ mediaTypes: mediaTypes,
651
+ mediaFeatures: mediaFeatures,
652
+ propertyKeywords: propertyKeywords,
653
+ colorKeywords: colorKeywords,
654
+ valueKeywords: valueKeywords,
655
+ fontProperties: fontProperties,
656
+ allowNested: true,
657
+ tokenHooks: {
617
658
  "/": function(stream, state) {
618
659
  if (stream.eat("/")) {
619
660
  stream.skipToEnd();
@@ -625,15 +666,18 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
625
666
  return ["operator", "operator"];
626
667
  }
627
668
  },
628
- "#": function(stream) {
629
- if (stream.eat("{")) {
630
- return ["operator", "interpolation"];
631
- } else {
632
- stream.eatWhile(/[\w\\\-]/);
633
- return ["atom", "hash"];
634
- }
669
+ "@": function(stream) {
670
+ if (stream.match(/^(charset|document|font-face|import|keyframes|media|namespace|page|supports)\b/, false)) return false;
671
+ stream.eatWhile(/[\w\\\-]/);
672
+ if (stream.match(/^\s*:/, false))
673
+ return ["variable-2", "variable-definition"];
674
+ return ["variable-2", "variable"];
675
+ },
676
+ "&": function() {
677
+ return ["atom", "atom"];
635
678
  }
636
679
  },
637
- name: "css"
680
+ name: "css",
681
+ helperType: "less"
638
682
  });
639
683
  })();