codemirror-rails 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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');