GPQAPP

Форк
0
359 строк · 9.8 Кб
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: https://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 atProp = /^@[_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

149

150
    // Handle operators and delimiters
151
    if (stream.match(operators) || stream.match(wordOperators)) {
152
      return "operator";
153
    }
154
    if (stream.match(delimiters)) {
155
      return "punctuation";
156
    }
157

158
    if (stream.match(constants)) {
159
      return "atom";
160
    }
161

162
    if (stream.match(atProp) || state.prop && stream.match(identifiers)) {
163
      return "property";
164
    }
165

166
    if (stream.match(keywords)) {
167
      return "keyword";
168
    }
169

170
    if (stream.match(identifiers)) {
171
      return "variable";
172
    }
173

174
    // Handle non-detected items
175
    stream.next();
176
    return ERRORCLASS;
177
  }
178

179
  function tokenFactory(delimiter, singleline, outclass) {
180
    return function(stream, state) {
181
      while (!stream.eol()) {
182
        stream.eatWhile(/[^'"\/\\]/);
183
        if (stream.eat("\\")) {
184
          stream.next();
185
          if (singleline && stream.eol()) {
186
            return outclass;
187
          }
188
        } else if (stream.match(delimiter)) {
189
          state.tokenize = tokenBase;
190
          return outclass;
191
        } else {
192
          stream.eat(/['"\/]/);
193
        }
194
      }
195
      if (singleline) {
196
        if (parserConf.singleLineStringErrors) {
197
          outclass = ERRORCLASS;
198
        } else {
199
          state.tokenize = tokenBase;
200
        }
201
      }
202
      return outclass;
203
    };
204
  }
205

206
  function longComment(stream, state) {
207
    while (!stream.eol()) {
208
      stream.eatWhile(/[^#]/);
209
      if (stream.match("###")) {
210
        state.tokenize = tokenBase;
211
        break;
212
      }
213
      stream.eatWhile("#");
214
    }
215
    return "comment";
216
  }
217

218
  function indent(stream, state, type) {
219
    type = type || "coffee";
220
    var offset = 0, align = false, alignOffset = null;
221
    for (var scope = state.scope; scope; scope = scope.prev) {
222
      if (scope.type === "coffee" || scope.type == "}") {
223
        offset = scope.offset + conf.indentUnit;
224
        break;
225
      }
226
    }
227
    if (type !== "coffee") {
228
      align = null;
229
      alignOffset = stream.column() + stream.current().length;
230
    } else if (state.scope.align) {
231
      state.scope.align = false;
232
    }
233
    state.scope = {
234
      offset: offset,
235
      type: type,
236
      prev: state.scope,
237
      align: align,
238
      alignOffset: alignOffset
239
    };
240
  }
241

242
  function dedent(stream, state) {
243
    if (!state.scope.prev) return;
244
    if (state.scope.type === "coffee") {
245
      var _indent = stream.indentation();
246
      var matched = false;
247
      for (var scope = state.scope; scope; scope = scope.prev) {
248
        if (_indent === scope.offset) {
249
          matched = true;
250
          break;
251
        }
252
      }
253
      if (!matched) {
254
        return true;
255
      }
256
      while (state.scope.prev && state.scope.offset !== _indent) {
257
        state.scope = state.scope.prev;
258
      }
259
      return false;
260
    } else {
261
      state.scope = state.scope.prev;
262
      return false;
263
    }
264
  }
265

266
  function tokenLexer(stream, state) {
267
    var style = state.tokenize(stream, state);
268
    var current = stream.current();
269

270
    // Handle scope changes.
271
    if (current === "return") {
272
      state.dedent = true;
273
    }
274
    if (((current === "->" || current === "=>") && stream.eol())
275
        || style === "indent") {
276
      indent(stream, state);
277
    }
278
    var delimiter_index = "[({".indexOf(current);
279
    if (delimiter_index !== -1) {
280
      indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
281
    }
282
    if (indentKeywords.exec(current)){
283
      indent(stream, state);
284
    }
285
    if (current == "then"){
286
      dedent(stream, state);
287
    }
288

289

290
    if (style === "dedent") {
291
      if (dedent(stream, state)) {
292
        return ERRORCLASS;
293
      }
294
    }
295
    delimiter_index = "])}".indexOf(current);
296
    if (delimiter_index !== -1) {
297
      while (state.scope.type == "coffee" && state.scope.prev)
298
        state.scope = state.scope.prev;
299
      if (state.scope.type == current)
300
        state.scope = state.scope.prev;
301
    }
302
    if (state.dedent && stream.eol()) {
303
      if (state.scope.type == "coffee" && state.scope.prev)
304
        state.scope = state.scope.prev;
305
      state.dedent = false;
306
    }
307

308
    return style;
309
  }
310

311
  var external = {
312
    startState: function(basecolumn) {
313
      return {
314
        tokenize: tokenBase,
315
        scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},
316
        prop: false,
317
        dedent: 0
318
      };
319
    },
320

321
    token: function(stream, state) {
322
      var fillAlign = state.scope.align === null && state.scope;
323
      if (fillAlign && stream.sol()) fillAlign.align = false;
324

325
      var style = tokenLexer(stream, state);
326
      if (style && style != "comment") {
327
        if (fillAlign) fillAlign.align = true;
328
        state.prop = style == "punctuation" && stream.current() == "."
329
      }
330

331
      return style;
332
    },
333

334
    indent: function(state, text) {
335
      if (state.tokenize != tokenBase) return 0;
336
      var scope = state.scope;
337
      var closer = text && "])}".indexOf(text.charAt(0)) > -1;
338
      if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev;
339
      var closes = closer && scope.type === text.charAt(0);
340
      if (scope.align)
341
        return scope.alignOffset - (closes ? 1 : 0);
342
      else
343
        return (closes ? scope.prev : scope).offset;
344
    },
345

346
    lineComment: "#",
347
    fold: "indent"
348
  };
349
  return external;
350
});
351

352
// IANA registered media type
353
// https://www.iana.org/assignments/media-types/
354
CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript");
355

356
CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
357
CodeMirror.defineMIME("text/coffeescript", "coffeescript");
358

359
});
360

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.