Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Avatar for KuCalc : devops.
Download
50671 views
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4
/**
5
* Link to the project's GitHub page:
6
* https://github.com/pickhardt/coffeescript-codemirror-mode
7
*/
8
(function(mod) {
9
if (typeof exports == "object" && typeof module == "object") // CommonJS
10
mod(require("../../lib/codemirror"));
11
else if (typeof define == "function" && define.amd) // AMD
12
define(["../../lib/codemirror"], mod);
13
else // Plain browser env
14
mod(CodeMirror);
15
})(function(CodeMirror) {
16
"use strict";
17
18
CodeMirror.defineMode("coffeescript", function(conf, parserConf) {
19
var ERRORCLASS = "error";
20
21
function wordRegexp(words) {
22
return new RegExp("^((" + words.join(")|(") + "))\\b");
23
}
24
25
var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/;
26
var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;
27
var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;
28
var properties = /^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/;
29
30
var wordOperators = wordRegexp(["and", "or", "not",
31
"is", "isnt", "in",
32
"instanceof", "typeof"]);
33
var indentKeywords = ["for", "while", "loop", "if", "unless", "else",
34
"switch", "try", "catch", "finally", "class"];
35
var commonKeywords = ["break", "by", "continue", "debugger", "delete",
36
"do", "in", "of", "new", "return", "then",
37
"this", "@", "throw", "when", "until", "extends"];
38
39
var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
40
41
indentKeywords = wordRegexp(indentKeywords);
42
43
44
var stringPrefixes = /^('{3}|\"{3}|['\"])/;
45
var regexPrefixes = /^(\/{3}|\/)/;
46
var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"];
47
var constants = wordRegexp(commonConstants);
48
49
// Tokenizers
50
function tokenBase(stream, state) {
51
// Handle scope changes
52
if (stream.sol()) {
53
if (state.scope.align === null) state.scope.align = false;
54
var scopeOffset = state.scope.offset;
55
if (stream.eatSpace()) {
56
var lineOffset = stream.indentation();
57
if (lineOffset > scopeOffset && state.scope.type == "coffee") {
58
return "indent";
59
} else if (lineOffset < scopeOffset) {
60
return "dedent";
61
}
62
return null;
63
} else {
64
if (scopeOffset > 0) {
65
dedent(stream, state);
66
}
67
}
68
}
69
if (stream.eatSpace()) {
70
return null;
71
}
72
73
var ch = stream.peek();
74
75
// Handle docco title comment (single line)
76
if (stream.match("####")) {
77
stream.skipToEnd();
78
return "comment";
79
}
80
81
// Handle multi line comments
82
if (stream.match("###")) {
83
state.tokenize = longComment;
84
return state.tokenize(stream, state);
85
}
86
87
// Single line comment
88
if (ch === "#") {
89
stream.skipToEnd();
90
return "comment";
91
}
92
93
// Handle number literals
94
if (stream.match(/^-?[0-9\.]/, false)) {
95
var floatLiteral = false;
96
// Floats
97
if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
98
floatLiteral = true;
99
}
100
if (stream.match(/^-?\d+\.\d*/)) {
101
floatLiteral = true;
102
}
103
if (stream.match(/^-?\.\d+/)) {
104
floatLiteral = true;
105
}
106
107
if (floatLiteral) {
108
// prevent from getting extra . on 1..
109
if (stream.peek() == "."){
110
stream.backUp(1);
111
}
112
return "number";
113
}
114
// Integers
115
var intLiteral = false;
116
// Hex
117
if (stream.match(/^-?0x[0-9a-f]+/i)) {
118
intLiteral = true;
119
}
120
// Decimal
121
if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
122
intLiteral = true;
123
}
124
// Zero by itself with no other piece of number.
125
if (stream.match(/^-?0(?![\dx])/i)) {
126
intLiteral = true;
127
}
128
if (intLiteral) {
129
return "number";
130
}
131
}
132
133
// Handle strings
134
if (stream.match(stringPrefixes)) {
135
state.tokenize = tokenFactory(stream.current(), false, "string");
136
return state.tokenize(stream, state);
137
}
138
// Handle regex literals
139
if (stream.match(regexPrefixes)) {
140
if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division
141
state.tokenize = tokenFactory(stream.current(), true, "string-2");
142
return state.tokenize(stream, state);
143
} else {
144
stream.backUp(1);
145
}
146
}
147
148
// Handle operators and delimiters
149
if (stream.match(operators) || stream.match(wordOperators)) {
150
return "operator";
151
}
152
if (stream.match(delimiters)) {
153
return "punctuation";
154
}
155
156
if (stream.match(constants)) {
157
return "atom";
158
}
159
160
if (stream.match(keywords)) {
161
return "keyword";
162
}
163
164
if (stream.match(identifiers)) {
165
return "variable";
166
}
167
168
if (stream.match(properties)) {
169
return "property";
170
}
171
172
// Handle non-detected items
173
stream.next();
174
return ERRORCLASS;
175
}
176
177
function tokenFactory(delimiter, singleline, outclass) {
178
return function(stream, state) {
179
while (!stream.eol()) {
180
stream.eatWhile(/[^'"\/\\]/);
181
if (stream.eat("\\")) {
182
stream.next();
183
if (singleline && stream.eol()) {
184
return outclass;
185
}
186
} else if (stream.match(delimiter)) {
187
state.tokenize = tokenBase;
188
return outclass;
189
} else {
190
stream.eat(/['"\/]/);
191
}
192
}
193
if (singleline) {
194
if (parserConf.singleLineStringErrors) {
195
outclass = ERRORCLASS;
196
} else {
197
state.tokenize = tokenBase;
198
}
199
}
200
return outclass;
201
};
202
}
203
204
function longComment(stream, state) {
205
while (!stream.eol()) {
206
stream.eatWhile(/[^#]/);
207
if (stream.match("###")) {
208
state.tokenize = tokenBase;
209
break;
210
}
211
stream.eatWhile("#");
212
}
213
return "comment";
214
}
215
216
function indent(stream, state, type) {
217
type = type || "coffee";
218
var offset = 0, align = false, alignOffset = null;
219
for (var scope = state.scope; scope; scope = scope.prev) {
220
if (scope.type === "coffee" || scope.type == "}") {
221
offset = scope.offset + conf.indentUnit;
222
break;
223
}
224
}
225
if (type !== "coffee") {
226
align = null;
227
alignOffset = stream.column() + stream.current().length;
228
} else if (state.scope.align) {
229
state.scope.align = false;
230
}
231
state.scope = {
232
offset: offset,
233
type: type,
234
prev: state.scope,
235
align: align,
236
alignOffset: alignOffset
237
};
238
}
239
240
function dedent(stream, state) {
241
if (!state.scope.prev) return;
242
if (state.scope.type === "coffee") {
243
var _indent = stream.indentation();
244
var matched = false;
245
for (var scope = state.scope; scope; scope = scope.prev) {
246
if (_indent === scope.offset) {
247
matched = true;
248
break;
249
}
250
}
251
if (!matched) {
252
return true;
253
}
254
while (state.scope.prev && state.scope.offset !== _indent) {
255
state.scope = state.scope.prev;
256
}
257
return false;
258
} else {
259
state.scope = state.scope.prev;
260
return false;
261
}
262
}
263
264
function tokenLexer(stream, state) {
265
var style = state.tokenize(stream, state);
266
var current = stream.current();
267
268
// Handle "." connected identifiers
269
if (current === ".") {
270
style = state.tokenize(stream, state);
271
current = stream.current();
272
if (/^\.[\w$]+$/.test(current)) {
273
return "variable";
274
} else {
275
return ERRORCLASS;
276
}
277
}
278
279
// Handle scope changes.
280
if (current === "return") {
281
state.dedent = true;
282
}
283
if (((current === "->" || current === "=>") &&
284
!state.lambda &&
285
!stream.peek())
286
|| style === "indent") {
287
indent(stream, state);
288
}
289
var delimiter_index = "[({".indexOf(current);
290
if (delimiter_index !== -1) {
291
indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
292
}
293
if (indentKeywords.exec(current)){
294
indent(stream, state);
295
}
296
if (current == "then"){
297
dedent(stream, state);
298
}
299
300
301
if (style === "dedent") {
302
if (dedent(stream, state)) {
303
return ERRORCLASS;
304
}
305
}
306
delimiter_index = "])}".indexOf(current);
307
if (delimiter_index !== -1) {
308
while (state.scope.type == "coffee" && state.scope.prev)
309
state.scope = state.scope.prev;
310
if (state.scope.type == current)
311
state.scope = state.scope.prev;
312
}
313
if (state.dedent && stream.eol()) {
314
if (state.scope.type == "coffee" && state.scope.prev)
315
state.scope = state.scope.prev;
316
state.dedent = false;
317
}
318
319
return style;
320
}
321
322
var external = {
323
startState: function(basecolumn) {
324
return {
325
tokenize: tokenBase,
326
scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},
327
lastToken: null,
328
lambda: false,
329
dedent: 0
330
};
331
},
332
333
token: function(stream, state) {
334
var fillAlign = state.scope.align === null && state.scope;
335
if (fillAlign && stream.sol()) fillAlign.align = false;
336
337
var style = tokenLexer(stream, state);
338
if (fillAlign && style && style != "comment") fillAlign.align = true;
339
340
state.lastToken = {style:style, content: stream.current()};
341
342
if (stream.eol() && stream.lambda) {
343
state.lambda = false;
344
}
345
346
return style;
347
},
348
349
indent: function(state, text) {
350
if (state.tokenize != tokenBase) return 0;
351
var scope = state.scope;
352
var closer = text && "])}".indexOf(text.charAt(0)) > -1;
353
if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev;
354
var closes = closer && scope.type === text.charAt(0);
355
if (scope.align)
356
return scope.alignOffset - (closes ? 1 : 0);
357
else
358
return (closes ? scope.prev : scope).offset;
359
},
360
361
lineComment: "#",
362
fold: "indent"
363
};
364
return external;
365
});
366
367
CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
368
369
});
370
371