codemirror-rails 0.2.1 → 0.2.2

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.
Binary file
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '0.2.1'
4
- CODEMIRROR_VERSION = '2.12'
3
+ VERSION = '0.2.2'
4
+ CODEMIRROR_VERSION = '2.13'
5
5
  end
6
6
  end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ # wget codemirror zip
5
+ # unzip codemirror
6
+ # copy css
7
+ # copy javascript
8
+
9
+ unless codemirror = ARGV.shift
10
+ raise 'Usage: ./upgrade_codemirror_stable.rb [CodeMirror-x.xx]'
11
+ end
12
+
13
+ base_path = File.dirname(__FILE__)
14
+ vendor = "#{base_path}/vendor/assets"
15
+ stable = "#{base_path}/#{codemirror}"
16
+
17
+ puts vendor
18
+ puts stable
19
+
20
+ globs_to_copy = {
21
+ 'lib/codemirror.css' => 'stylesheets/codemirror.css',
22
+ 'lib/codemirror.js' => 'javascripts/codemirror.js',
23
+ 'lib/overlay.js' => 'javascripts/codemirror/overlay.js',
24
+ 'lib/runmode.js' => 'javascripts/codemirror/runmode.js',
25
+ 'theme/*.css' => 'stylesheets/codemirror/themes/',
26
+ 'mode/**/*.js' => 'javascripts/codemirror/modes/',
27
+ 'mode/**/*.css' => 'stylesheets/codemirror/modes/'
28
+ }
29
+
30
+ globs_to_copy.each do |glob_from, to|
31
+ dest = "#{vendor}/#{to}"
32
+ Dir.glob("#{stable}/#{glob_from}").each do |src|
33
+ puts "#{src} => #{to}"
34
+ FileUtils.copy src, dest
35
+ end
36
+ end
@@ -119,7 +119,7 @@ var CodeMirror = (function() {
119
119
  focus: function(){focusInput(); onFocus(); fastPoll();},
120
120
  setOption: function(option, value) {
121
121
  options[option] = value;
122
- if (option == "lineNumbers" || option == "gutter") gutterChanged();
122
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber") gutterChanged();
123
123
  else if (option == "mode" || option == "indentUnit") loadMode();
124
124
  else if (option == "readOnly" && value == "nocursor") input.blur();
125
125
  else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
@@ -127,7 +127,9 @@ var CodeMirror = (function() {
127
127
  getOption: function(option) {return options[option];},
128
128
  undo: operation(undo),
129
129
  redo: operation(redo),
130
- indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
130
+ indentLine: operation(function(n, dir) {
131
+ if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
132
+ }),
131
133
  historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
132
134
  matchBrackets: operation(function(){matchBrackets(true);}),
133
135
  getTokenAt: function(pos) {
@@ -200,7 +202,8 @@ var CodeMirror = (function() {
200
202
  refresh: function(){updateDisplay(true);},
201
203
  getInputField: function(){return input;},
202
204
  getWrapperElement: function(){return wrapper;},
203
- getScrollerElement: function(){return scroller;}
205
+ getScrollerElement: function(){return scroller;},
206
+ getGutterElement: function(){return gutter;}
204
207
  };
205
208
 
206
209
  function setValue(code) {
@@ -340,6 +343,7 @@ var CodeMirror = (function() {
340
343
  if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
341
344
  if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
342
345
  }
346
+ if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
343
347
 
344
348
  // Key id to use in the movementKeys map. We also pass it to
345
349
  // fastPoll in order to 'self learn'. We need this because
@@ -347,14 +351,16 @@ var CodeMirror = (function() {
347
351
  // its start when it is inverted and a movement key is pressed
348
352
  // (and later restore it again), shouldn't be used for
349
353
  // non-movement keys.
350
- curKeyId = (mod ? "c" : "") + code;
351
- if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
354
+ curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
355
+ if (sel.inverted && movementKeys[curKeyId] === true) {
352
356
  var range = selRange(input);
353
357
  if (range) {
354
358
  reducedSelection = {anchor: range.start};
355
359
  setSelRange(input, range.start, range.start);
356
360
  }
357
361
  }
362
+ // Don't save the key as a movementkey unless it had a modifier
363
+ if (!mod && !e.altKey) curKeyId = null;
358
364
  fastPoll(curKeyId);
359
365
  }
360
366
  function onKeyUp(e) {
@@ -566,7 +572,10 @@ var CodeMirror = (function() {
566
572
  function p() {
567
573
  startOperation();
568
574
  var changed = readInput();
569
- if (changed == "moved" && keyId) movementKeys[keyId] = true;
575
+ if (changed && keyId) {
576
+ if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
577
+ if (changed == "changed") movementKeys[keyId] = false;
578
+ }
570
579
  if (!changed && !missed) {missed = true; poll.set(80, p);}
571
580
  else {pollingFast = false; slowPoll();}
572
581
  endOperation();
@@ -663,6 +672,12 @@ var CodeMirror = (function() {
663
672
  if (options.readOnly != "nocursor") input.focus();
664
673
  }
665
674
 
675
+ function scrollEditorIntoView() {
676
+ if (!cursor.getBoundingClientRect) return;
677
+ var rect = cursor.getBoundingClientRect();
678
+ var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
679
+ if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
680
+ }
666
681
  function scrollCursorIntoView() {
667
682
  var cursor = localCoords(sel.inverted ? sel.from : sel.to);
668
683
  return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
@@ -766,8 +781,8 @@ var CodeMirror = (function() {
766
781
  if (different) {
767
782
  lastHeight = scroller.clientHeight;
768
783
  code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
769
- updateGutter();
770
784
  }
785
+ if (different || updates.length) updateGutter();
771
786
 
772
787
  if (maxWidth == null) maxWidth = stringWidth(maxLine);
773
788
  if (maxWidth > scroller.clientWidth) {
@@ -871,10 +886,12 @@ var CodeMirror = (function() {
871
886
  }
872
887
  function updateCursor() {
873
888
  var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
874
- var x = charX(head.line, head.ch) + "px", y = (head.line - showingFrom) * lh + "px";
889
+ var x = charX(head.line, head.ch);
875
890
  inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
891
+ inputDiv.style.left = (x - scroller.scrollLeft) + "px";
876
892
  if (posEq(sel.from, sel.to)) {
877
- cursor.style.top = y; cursor.style.left = x;
893
+ cursor.style.top = (head.line - showingFrom) * lh + "px";
894
+ cursor.style.left = x + "px";
878
895
  cursor.style.display = "";
879
896
  }
880
897
  else cursor.style.display = "none";
@@ -994,6 +1011,10 @@ var CodeMirror = (function() {
994
1011
  }
995
1012
  return true;
996
1013
  }
1014
+ function smartHome() {
1015
+ var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
1016
+ setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
1017
+ }
997
1018
 
998
1019
  function indentLine(n, how) {
999
1020
  if (how == "smart") {
@@ -1190,8 +1211,8 @@ var CodeMirror = (function() {
1190
1211
 
1191
1212
  var oldCSS = input.style.cssText;
1192
1213
  inputDiv.style.position = "absolute";
1193
- input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e_pageY(e) - 1) +
1194
- "px; left: " + (e_pageX(e) - 1) + "px; z-index: 1000; background: white; " +
1214
+ input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1215
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
1195
1216
  "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1196
1217
  leaveInputAlone = true;
1197
1218
  var val = input.value = getSelection();
@@ -1284,7 +1305,7 @@ var CodeMirror = (function() {
1284
1305
  if (line.stateAfter) return search;
1285
1306
  var indented = line.indentation();
1286
1307
  if (minline == null || minindent > indented) {
1287
- minline = search;
1308
+ minline = search - 1;
1288
1309
  minindent = indented;
1289
1310
  }
1290
1311
  }
@@ -1321,25 +1342,26 @@ var CodeMirror = (function() {
1321
1342
  if (state) state = copyState(mode, state);
1322
1343
  else state = startState(mode);
1323
1344
 
1324
- var unchanged = 0, compare = mode.compareStates;
1345
+ var unchanged = 0, compare = mode.compareStates, realChange = false;
1325
1346
  for (var i = start, l = lines.length; i < l; ++i) {
1326
1347
  var line = lines[i], hadState = line.stateAfter;
1327
1348
  if (+new Date > end) {
1328
1349
  work.push(i);
1329
1350
  startWorker(options.workDelay);
1330
- changes.push({from: task, to: i + 1});
1351
+ if (realChange) changes.push({from: task, to: i + 1});
1331
1352
  return;
1332
1353
  }
1333
1354
  var changed = line.highlight(mode, state);
1355
+ if (changed) realChange = true;
1334
1356
  line.stateAfter = copyState(mode, state);
1335
1357
  if (compare) {
1336
1358
  if (hadState && compare(hadState, state)) break;
1337
1359
  } else {
1338
- if (changed || !hadState) unchanged = 0;
1360
+ if (changed !== false || !hadState) unchanged = 0;
1339
1361
  else if (++unchanged > 3) break;
1340
1362
  }
1341
1363
  }
1342
- changes.push({from: task, to: i + 1});
1364
+ if (realChange) changes.push({from: task, to: i + 1});
1343
1365
  }
1344
1366
  if (foundWork && options.onHighlightComplete)
1345
1367
  options.onHighlightComplete(instance);
@@ -1362,7 +1384,7 @@ var CodeMirror = (function() {
1362
1384
  if (changes.length) updateDisplay(changes);
1363
1385
  else if (selectionChanged) updateCursor();
1364
1386
  if (reScroll) scrollCursorIntoView();
1365
- if (selectionChanged) restartBlink();
1387
+ if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1366
1388
 
1367
1389
  // updateInput can be set to a boolean value to force/prevent an
1368
1390
  // update.
@@ -1527,6 +1549,7 @@ var CodeMirror = (function() {
1527
1549
  gutter: false,
1528
1550
  firstLineNumber: 1,
1529
1551
  readOnly: false,
1552
+ smartHome: true,
1530
1553
  onChange: null,
1531
1554
  onCursorActivity: null,
1532
1555
  onGutterClick: null,
@@ -1660,7 +1683,7 @@ var CodeMirror = (function() {
1660
1683
  if (ok) {++this.pos; return ch;}
1661
1684
  },
1662
1685
  eatWhile: function(match) {
1663
- var start = this.start;
1686
+ var start = this.pos;
1664
1687
  while (this.eat(match)){}
1665
1688
  return this.pos > start;
1666
1689
  },
@@ -1769,10 +1792,10 @@ var CodeMirror = (function() {
1769
1792
  }
1770
1793
  if (st.length != pos) {st.length = pos; changed = true;}
1771
1794
  if (pos && st[pos-2] != prevWord) changed = true;
1772
- // Short lines with simple highlights always count as changed,
1773
- // because they are likely to highlight the same way in various
1774
- // contexts.
1775
- return changed || (st.length < 5 && this.text.length < 10);
1795
+ // Short lines with simple highlights return null, and are
1796
+ // counted as changed by the driver because they are likely to
1797
+ // highlight the same way in various contexts.
1798
+ return changed || (st.length < 5 && this.text.length < 10 ? null : false);
1776
1799
  },
1777
1800
  // Fetch the parser token for a given character. Useful for hacks
1778
1801
  // that want to inspect the mode state (say, for completion).
@@ -1930,16 +1953,6 @@ var CodeMirror = (function() {
1930
1953
  else if (e.button & 2) return 3;
1931
1954
  else if (e.button & 4) return 2;
1932
1955
  }
1933
- function e_pageX(e) {
1934
- if (e.pageX != null) return e.pageX;
1935
- var doc = e_target(e).ownerDocument;
1936
- return e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
1937
- }
1938
- function e_pageY(e) {
1939
- if (e.pageY != null) return e.pageY;
1940
- var doc = e_target(e).ownerDocument;
1941
- return e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
1942
- }
1943
1956
 
1944
1957
  // Event handler registration. If disconnect is true, it'll return a
1945
1958
  // function that unregisters the handler.
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Link to the project's GitHub page:
3
+ * https://github.com/pickhardt/coffeescript-codemirror-mode
4
+ */
5
+ CodeMirror.defineMode('coffeescript', function(conf) {
6
+ var ERRORCLASS = 'error';
7
+
8
+ function wordRegexp(words) {
9
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
10
+ }
11
+
12
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
13
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
14
+ var doubleOperators = new RegExp("^((\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
15
+ var doubleDelimiters = new RegExp("^((\->)|(\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
16
+ var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
17
+ var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
18
+
19
+ var wordOperators = wordRegexp(['and', 'or', 'not',
20
+ 'is', 'isnt', 'in',
21
+ 'instanceof', 'typeof']);
22
+ var commonKeywords = ['break', 'by', 'catch', 'class', 'continue',
23
+ 'debugger', 'delete', 'do', 'else', 'finally',
24
+ 'for', 'in', 'of', 'if', 'new', 'return',
25
+ 'switch', 'then', 'this', 'throw', 'try',
26
+ 'unless', 'when', 'while', 'until', 'loop'];
27
+ var keywords = wordRegexp(commonKeywords);
28
+
29
+
30
+ var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
31
+ var commonConstants = ['Infinity', 'NaN', 'undefined', 'true', 'false'];
32
+ var constants = wordRegexp(commonConstants);
33
+
34
+ // Tokenizers
35
+ function tokenBase(stream, state) {
36
+ // Handle scope changes
37
+ if (stream.sol()) {
38
+ var scopeOffset = state.scopes[0].offset;
39
+ if (stream.eatSpace()) {
40
+ var lineOffset = stream.indentation();
41
+ if (lineOffset > scopeOffset) {
42
+ return 'indent';
43
+ } else if (lineOffset < scopeOffset) {
44
+ return 'dedent';
45
+ }
46
+ return null;
47
+ } else {
48
+ if (scopeOffset > 0) {
49
+ dedent(stream, state);
50
+ }
51
+ }
52
+ }
53
+ if (stream.eatSpace()) {
54
+ return null;
55
+ }
56
+
57
+ var ch = stream.peek();
58
+
59
+ // Handle comments
60
+ if (ch === '#') {
61
+ stream.skipToEnd();
62
+ return 'comment';
63
+ }
64
+
65
+ // Handle number literals
66
+ if (stream.match(/^-?[0-9\.]/, false)) {
67
+ var floatLiteral = false;
68
+ // Floats
69
+ if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
70
+ floatLiteral = true;
71
+ }
72
+ if (stream.match(/^-?\d+\.\d*/)) {
73
+ floatLiteral = true;
74
+ }
75
+ if (stream.match(/^-?\.\d+/)) {
76
+ floatLiteral = true;
77
+ }
78
+ if (floatLiteral) {
79
+ return 'number';
80
+ }
81
+ // Integers
82
+ var intLiteral = false;
83
+ // Hex
84
+ if (stream.match(/^-?0x[0-9a-f]+/i)) {
85
+ intLiteral = true;
86
+ }
87
+ // Decimal
88
+ if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
89
+ intLiteral = true;
90
+ }
91
+ // Zero by itself with no other piece of number.
92
+ if (stream.match(/^-?0(?![\dx])/i)) {
93
+ intLiteral = true;
94
+ }
95
+ if (intLiteral) {
96
+ return 'number';
97
+ }
98
+ }
99
+
100
+ // Handle strings
101
+ if (stream.match(stringPrefixes)) {
102
+ state.tokenize = tokenStringFactory(stream.current());
103
+ return state.tokenize(stream, state);
104
+ }
105
+
106
+ // Handle operators and delimiters
107
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
108
+ return 'punctuation';
109
+ }
110
+ if (stream.match(doubleOperators)
111
+ || stream.match(singleOperators)
112
+ || stream.match(wordOperators)) {
113
+ return 'operator';
114
+ }
115
+ if (stream.match(singleDelimiters)) {
116
+ return 'punctuation';
117
+ }
118
+
119
+ if (stream.match(constants)) {
120
+ return 'atom';
121
+ }
122
+
123
+ if (stream.match(keywords)) {
124
+ return 'keyword';
125
+ }
126
+
127
+ if (stream.match(identifiers)) {
128
+ return 'variable';
129
+ }
130
+
131
+ // Handle non-detected items
132
+ stream.next();
133
+ return ERRORCLASS;
134
+ }
135
+
136
+ function tokenStringFactory(delimiter) {
137
+ while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
138
+ delimiter = delimiter.substr(1);
139
+ }
140
+ var delim_re = new RegExp(delimiter);
141
+ var singleline = delimiter.length == 1;
142
+ var OUTCLASS = 'string';
143
+
144
+ return function tokenString(stream, state) {
145
+ while (!stream.eol()) {
146
+ stream.eatWhile(/[^'"\\]/);
147
+ if (stream.eat('\\')) {
148
+ stream.next();
149
+ if (singleline && stream.eol()) {
150
+ return OUTCLASS;
151
+ }
152
+ } else if (stream.match(delim_re)) {
153
+ state.tokenize = tokenBase;
154
+ return OUTCLASS;
155
+ } else {
156
+ stream.eat(/['"]/);
157
+ }
158
+ }
159
+ if (singleline) {
160
+ if (conf.mode.singleLineStringErrors) {
161
+ OUTCLASS = ERRORCLASS
162
+ } else {
163
+ state.tokenize = tokenBase;
164
+ }
165
+ }
166
+ return OUTCLASS;
167
+ };
168
+ }
169
+
170
+ function indent(stream, state, type) {
171
+ type = type || 'coffee';
172
+ var indentUnit = 0;
173
+ if (type === 'coffee') {
174
+ for (var i = 0; i < state.scopes.length; i++) {
175
+ if (state.scopes[i].type === 'coffee') {
176
+ indentUnit = state.scopes[i].offset + conf.indentUnit;
177
+ break;
178
+ }
179
+ }
180
+ } else {
181
+ indentUnit = stream.column() + stream.current().length;
182
+ }
183
+ state.scopes.unshift({
184
+ offset: indentUnit,
185
+ type: type
186
+ });
187
+ }
188
+
189
+ function dedent(stream, state) {
190
+ if (state.scopes.length == 1) return;
191
+ if (state.scopes[0].type === 'coffee') {
192
+ var _indent = stream.indentation();
193
+ var _indent_index = -1;
194
+ for (var i = 0; i < state.scopes.length; ++i) {
195
+ if (_indent === state.scopes[i].offset) {
196
+ _indent_index = i;
197
+ break;
198
+ }
199
+ }
200
+ if (_indent_index === -1) {
201
+ return true;
202
+ }
203
+ while (state.scopes[0].offset !== _indent) {
204
+ state.scopes.shift();
205
+ }
206
+ return false
207
+ } else {
208
+ state.scopes.shift();
209
+ return false;
210
+ }
211
+ }
212
+
213
+ function tokenLexer(stream, state) {
214
+ var style = state.tokenize(stream, state);
215
+ var current = stream.current();
216
+
217
+ // Handle '.' connected identifiers
218
+ if (current === '.') {
219
+ style = state.tokenize(stream, state);
220
+ current = stream.current();
221
+ if (style === 'variable') {
222
+ return 'variable';
223
+ } else {
224
+ return ERRORCLASS;
225
+ }
226
+ }
227
+
228
+ // Handle decorators
229
+ if (current === '@') {
230
+ style = state.tokenize(stream, state);
231
+ current = stream.current();
232
+ if (style === 'variable') {
233
+ return 'variable-2';
234
+ } else {
235
+ return ERRORCLASS;
236
+ }
237
+ }
238
+
239
+ // Handle scope changes.
240
+ if (current === 'pass' || current === 'return') {
241
+ state.dedent += 1;
242
+ }
243
+ if ((current === '->' &&
244
+ !state.lambda &&
245
+ state.scopes[0].type == 'coffee' &&
246
+ stream.peek() === '')
247
+ || style === 'indent') {
248
+ indent(stream, state);
249
+ }
250
+ var delimiter_index = '[({'.indexOf(current);
251
+ if (delimiter_index !== -1) {
252
+ indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
253
+ }
254
+ if (style === 'dedent') {
255
+ if (dedent(stream, state)) {
256
+ return ERRORCLASS;
257
+ }
258
+ }
259
+ delimiter_index = '])}'.indexOf(current);
260
+ if (delimiter_index !== -1) {
261
+ if (dedent(stream, state)) {
262
+ return ERRORCLASS;
263
+ }
264
+ }
265
+ if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
266
+ if (state.scopes.length > 1) state.scopes.shift();
267
+ state.dedent -= 1;
268
+ }
269
+
270
+ return style;
271
+ }
272
+
273
+ var external = {
274
+ startState: function(basecolumn) {
275
+ return {
276
+ tokenize: tokenBase,
277
+ scopes: [{offset:basecolumn || 0, type:'coffee'}],
278
+ lastToken: null,
279
+ lambda: false,
280
+ dedent: 0
281
+ };
282
+ },
283
+
284
+ token: function(stream, state) {
285
+ var style = tokenLexer(stream, state);
286
+
287
+ state.lastToken = {style:style, content: stream.current()};
288
+
289
+ if (stream.eol() && stream.lambda) {
290
+ state.lambda = false;
291
+ }
292
+
293
+ return style;
294
+ },
295
+
296
+ indent: function(state, textAfter) {
297
+ if (state.tokenize != tokenBase) {
298
+ return 0;
299
+ }
300
+
301
+ return state.scopes[0].offset;
302
+ }
303
+
304
+ };
305
+ return external;
306
+ });
307
+
308
+ CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');