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.
- data/codemirror-rails-0.2.1.gem +0 -0
- data/lib/codemirror/rails/version.rb +2 -2
- data/upgrade_codemirror_stable.rb +36 -0
- data/vendor/assets/javascripts/codemirror.js +45 -32
- data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +308 -0
- data/vendor/assets/javascripts/codemirror/modes/php.js +6 -1
- data/vendor/assets/javascripts/codemirror/modes/python.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/r.js +134 -0
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +182 -0
- data/vendor/assets/javascripts/codemirror/modes/scheme.js +182 -181
- data/vendor/assets/javascripts/codemirror/modes/velocity.js +146 -0
- data/vendor/assets/javascripts/codemirror/modes/xmlpure.js +481 -0
- data/vendor/assets/stylesheets/codemirror/themes/default.css +1 -0
- data/vendor/assets/stylesheets/codemirror/themes/elegant.css +9 -0
- data/vendor/assets/stylesheets/codemirror/themes/neat.css +8 -0
- data/vendor/assets/stylesheets/codemirror/themes/night.css +20 -0
- metadata +12 -4
- data/codemirror-rails-0.1.2.gem +0 -0
- data/codemirror-rails-0.2.0.gem +0 -0
Binary file
|
@@ -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) {
|
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
|
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
|
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)
|
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 =
|
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: " + (
|
1194
|
-
"px; left: " + (
|
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.
|
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
|
1773
|
-
//
|
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');
|