GPQAPP

Форк
0
469 строк · 13.5 Кб
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: https://codemirror.net/LICENSE
3

4
(function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") { // CommonJS
6
    mod(require("../../lib/codemirror"));
7
  } else if (typeof define == "function" && define.amd) { // AMD
8
    define(["../../lib/codemirror"], mod);
9
  } else { // Plain browser env
10
    mod(CodeMirror);
11
  }
12
})(function(CodeMirror) {
13
  "use strict";
14

15
  var TOKEN_STYLES = {
16
    addition: "positive",
17
    attributes: "attribute",
18
    bold: "strong",
19
    cite: "keyword",
20
    code: "atom",
21
    definitionList: "number",
22
    deletion: "negative",
23
    div: "punctuation",
24
    em: "em",
25
    footnote: "variable",
26
    footCite: "qualifier",
27
    header: "header",
28
    html: "comment",
29
    image: "string",
30
    italic: "em",
31
    link: "link",
32
    linkDefinition: "link",
33
    list1: "variable-2",
34
    list2: "variable-3",
35
    list3: "keyword",
36
    notextile: "string-2",
37
    pre: "operator",
38
    p: "property",
39
    quote: "bracket",
40
    span: "quote",
41
    specialChar: "tag",
42
    strong: "strong",
43
    sub: "builtin",
44
    sup: "builtin",
45
    table: "variable-3",
46
    tableHeading: "operator"
47
  };
48

49
  function startNewLine(stream, state) {
50
    state.mode = Modes.newLayout;
51
    state.tableHeading = false;
52

53
    if (state.layoutType === "definitionList" && state.spanningLayout &&
54
        stream.match(RE("definitionListEnd"), false))
55
      state.spanningLayout = false;
56
  }
57

58
  function handlePhraseModifier(stream, state, ch) {
59
    if (ch === "_") {
60
      if (stream.eat("_"))
61
        return togglePhraseModifier(stream, state, "italic", /__/, 2);
62
      else
63
        return togglePhraseModifier(stream, state, "em", /_/, 1);
64
    }
65

66
    if (ch === "*") {
67
      if (stream.eat("*")) {
68
        return togglePhraseModifier(stream, state, "bold", /\*\*/, 2);
69
      }
70
      return togglePhraseModifier(stream, state, "strong", /\*/, 1);
71
    }
72

73
    if (ch === "[") {
74
      if (stream.match(/\d+\]/)) state.footCite = true;
75
      return tokenStyles(state);
76
    }
77

78
    if (ch === "(") {
79
      var spec = stream.match(/^(r|tm|c)\)/);
80
      if (spec)
81
        return tokenStylesWith(state, TOKEN_STYLES.specialChar);
82
    }
83

84
    if (ch === "<" && stream.match(/(\w+)[^>]+>[^<]+<\/\1>/))
85
      return tokenStylesWith(state, TOKEN_STYLES.html);
86

87
    if (ch === "?" && stream.eat("?"))
88
      return togglePhraseModifier(stream, state, "cite", /\?\?/, 2);
89

90
    if (ch === "=" && stream.eat("="))
91
      return togglePhraseModifier(stream, state, "notextile", /==/, 2);
92

93
    if (ch === "-" && !stream.eat("-"))
94
      return togglePhraseModifier(stream, state, "deletion", /-/, 1);
95

96
    if (ch === "+")
97
      return togglePhraseModifier(stream, state, "addition", /\+/, 1);
98

99
    if (ch === "~")
100
      return togglePhraseModifier(stream, state, "sub", /~/, 1);
101

102
    if (ch === "^")
103
      return togglePhraseModifier(stream, state, "sup", /\^/, 1);
104

105
    if (ch === "%")
106
      return togglePhraseModifier(stream, state, "span", /%/, 1);
107

108
    if (ch === "@")
109
      return togglePhraseModifier(stream, state, "code", /@/, 1);
110

111
    if (ch === "!") {
112
      var type = togglePhraseModifier(stream, state, "image", /(?:\([^\)]+\))?!/, 1);
113
      stream.match(/^:\S+/); // optional Url portion
114
      return type;
115
    }
116
    return tokenStyles(state);
117
  }
118

119
  function togglePhraseModifier(stream, state, phraseModifier, closeRE, openSize) {
120
    var charBefore = stream.pos > openSize ? stream.string.charAt(stream.pos - openSize - 1) : null;
121
    var charAfter = stream.peek();
122
    if (state[phraseModifier]) {
123
      if ((!charAfter || /\W/.test(charAfter)) && charBefore && /\S/.test(charBefore)) {
124
        var type = tokenStyles(state);
125
        state[phraseModifier] = false;
126
        return type;
127
      }
128
    } else if ((!charBefore || /\W/.test(charBefore)) && charAfter && /\S/.test(charAfter) &&
129
               stream.match(new RegExp("^.*\\S" + closeRE.source + "(?:\\W|$)"), false)) {
130
      state[phraseModifier] = true;
131
      state.mode = Modes.attributes;
132
    }
133
    return tokenStyles(state);
134
  };
135

136
  function tokenStyles(state) {
137
    var disabled = textileDisabled(state);
138
    if (disabled) return disabled;
139

140
    var styles = [];
141
    if (state.layoutType) styles.push(TOKEN_STYLES[state.layoutType]);
142

143
    styles = styles.concat(activeStyles(
144
      state, "addition", "bold", "cite", "code", "deletion", "em", "footCite",
145
      "image", "italic", "link", "span", "strong", "sub", "sup", "table", "tableHeading"));
146

147
    if (state.layoutType === "header")
148
      styles.push(TOKEN_STYLES.header + "-" + state.header);
149

150
    return styles.length ? styles.join(" ") : null;
151
  }
152

153
  function textileDisabled(state) {
154
    var type = state.layoutType;
155

156
    switch(type) {
157
    case "notextile":
158
    case "code":
159
    case "pre":
160
      return TOKEN_STYLES[type];
161
    default:
162
      if (state.notextile)
163
        return TOKEN_STYLES.notextile + (type ? (" " + TOKEN_STYLES[type]) : "");
164
      return null;
165
    }
166
  }
167

168
  function tokenStylesWith(state, extraStyles) {
169
    var disabled = textileDisabled(state);
170
    if (disabled) return disabled;
171

172
    var type = tokenStyles(state);
173
    if (extraStyles)
174
      return type ? (type + " " + extraStyles) : extraStyles;
175
    else
176
      return type;
177
  }
178

179
  function activeStyles(state) {
180
    var styles = [];
181
    for (var i = 1; i < arguments.length; ++i) {
182
      if (state[arguments[i]])
183
        styles.push(TOKEN_STYLES[arguments[i]]);
184
    }
185
    return styles;
186
  }
187

188
  function blankLine(state) {
189
    var spanningLayout = state.spanningLayout, type = state.layoutType;
190

191
    for (var key in state) if (state.hasOwnProperty(key))
192
      delete state[key];
193

194
    state.mode = Modes.newLayout;
195
    if (spanningLayout) {
196
      state.layoutType = type;
197
      state.spanningLayout = true;
198
    }
199
  }
200

201
  var REs = {
202
    cache: {},
203
    single: {
204
      bc: "bc",
205
      bq: "bq",
206
      definitionList: /- .*?:=+/,
207
      definitionListEnd: /.*=:\s*$/,
208
      div: "div",
209
      drawTable: /\|.*\|/,
210
      foot: /fn\d+/,
211
      header: /h[1-6]/,
212
      html: /\s*<(?:\/)?(\w+)(?:[^>]+)?>(?:[^<]+<\/\1>)?/,
213
      link: /[^"]+":\S/,
214
      linkDefinition: /\[[^\s\]]+\]\S+/,
215
      list: /(?:#+|\*+)/,
216
      notextile: "notextile",
217
      para: "p",
218
      pre: "pre",
219
      table: "table",
220
      tableCellAttributes: /[\/\\]\d+/,
221
      tableHeading: /\|_\./,
222
      tableText: /[^"_\*\[\(\?\+~\^%@|-]+/,
223
      text: /[^!"_=\*\[\(<\?\+~\^%@-]+/
224
    },
225
    attributes: {
226
      align: /(?:<>|<|>|=)/,
227
      selector: /\([^\(][^\)]+\)/,
228
      lang: /\[[^\[\]]+\]/,
229
      pad: /(?:\(+|\)+){1,2}/,
230
      css: /\{[^\}]+\}/
231
    },
232
    createRe: function(name) {
233
      switch (name) {
234
      case "drawTable":
235
        return REs.makeRe("^", REs.single.drawTable, "$");
236
      case "html":
237
        return REs.makeRe("^", REs.single.html, "(?:", REs.single.html, ")*", "$");
238
      case "linkDefinition":
239
        return REs.makeRe("^", REs.single.linkDefinition, "$");
240
      case "listLayout":
241
        return REs.makeRe("^", REs.single.list, RE("allAttributes"), "*\\s+");
242
      case "tableCellAttributes":
243
        return REs.makeRe("^", REs.choiceRe(REs.single.tableCellAttributes,
244
                                            RE("allAttributes")), "+\\.");
245
      case "type":
246
        return REs.makeRe("^", RE("allTypes"));
247
      case "typeLayout":
248
        return REs.makeRe("^", RE("allTypes"), RE("allAttributes"),
249
                          "*\\.\\.?", "(\\s+|$)");
250
      case "attributes":
251
        return REs.makeRe("^", RE("allAttributes"), "+");
252

253
      case "allTypes":
254
        return REs.choiceRe(REs.single.div, REs.single.foot,
255
                            REs.single.header, REs.single.bc, REs.single.bq,
256
                            REs.single.notextile, REs.single.pre, REs.single.table,
257
                            REs.single.para);
258

259
      case "allAttributes":
260
        return REs.choiceRe(REs.attributes.selector, REs.attributes.css,
261
                            REs.attributes.lang, REs.attributes.align, REs.attributes.pad);
262

263
      default:
264
        return REs.makeRe("^", REs.single[name]);
265
      }
266
    },
267
    makeRe: function() {
268
      var pattern = "";
269
      for (var i = 0; i < arguments.length; ++i) {
270
        var arg = arguments[i];
271
        pattern += (typeof arg === "string") ? arg : arg.source;
272
      }
273
      return new RegExp(pattern);
274
    },
275
    choiceRe: function() {
276
      var parts = [arguments[0]];
277
      for (var i = 1; i < arguments.length; ++i) {
278
        parts[i * 2 - 1] = "|";
279
        parts[i * 2] = arguments[i];
280
      }
281

282
      parts.unshift("(?:");
283
      parts.push(")");
284
      return REs.makeRe.apply(null, parts);
285
    }
286
  };
287

288
  function RE(name) {
289
    return (REs.cache[name] || (REs.cache[name] = REs.createRe(name)));
290
  }
291

292
  var Modes = {
293
    newLayout: function(stream, state) {
294
      if (stream.match(RE("typeLayout"), false)) {
295
        state.spanningLayout = false;
296
        return (state.mode = Modes.blockType)(stream, state);
297
      }
298
      var newMode;
299
      if (!textileDisabled(state)) {
300
        if (stream.match(RE("listLayout"), false))
301
          newMode = Modes.list;
302
        else if (stream.match(RE("drawTable"), false))
303
          newMode = Modes.table;
304
        else if (stream.match(RE("linkDefinition"), false))
305
          newMode = Modes.linkDefinition;
306
        else if (stream.match(RE("definitionList")))
307
          newMode = Modes.definitionList;
308
        else if (stream.match(RE("html"), false))
309
          newMode = Modes.html;
310
      }
311
      return (state.mode = (newMode || Modes.text))(stream, state);
312
    },
313

314
    blockType: function(stream, state) {
315
      var match, type;
316
      state.layoutType = null;
317

318
      if (match = stream.match(RE("type")))
319
        type = match[0];
320
      else
321
        return (state.mode = Modes.text)(stream, state);
322

323
      if (match = type.match(RE("header"))) {
324
        state.layoutType = "header";
325
        state.header = parseInt(match[0][1]);
326
      } else if (type.match(RE("bq"))) {
327
        state.layoutType = "quote";
328
      } else if (type.match(RE("bc"))) {
329
        state.layoutType = "code";
330
      } else if (type.match(RE("foot"))) {
331
        state.layoutType = "footnote";
332
      } else if (type.match(RE("notextile"))) {
333
        state.layoutType = "notextile";
334
      } else if (type.match(RE("pre"))) {
335
        state.layoutType = "pre";
336
      } else if (type.match(RE("div"))) {
337
        state.layoutType = "div";
338
      } else if (type.match(RE("table"))) {
339
        state.layoutType = "table";
340
      }
341

342
      state.mode = Modes.attributes;
343
      return tokenStyles(state);
344
    },
345

346
    text: function(stream, state) {
347
      if (stream.match(RE("text"))) return tokenStyles(state);
348

349
      var ch = stream.next();
350
      if (ch === '"')
351
        return (state.mode = Modes.link)(stream, state);
352
      return handlePhraseModifier(stream, state, ch);
353
    },
354

355
    attributes: function(stream, state) {
356
      state.mode = Modes.layoutLength;
357

358
      if (stream.match(RE("attributes")))
359
        return tokenStylesWith(state, TOKEN_STYLES.attributes);
360
      else
361
        return tokenStyles(state);
362
    },
363

364
    layoutLength: function(stream, state) {
365
      if (stream.eat(".") && stream.eat("."))
366
        state.spanningLayout = true;
367

368
      state.mode = Modes.text;
369
      return tokenStyles(state);
370
    },
371

372
    list: function(stream, state) {
373
      var match = stream.match(RE("list"));
374
      state.listDepth = match[0].length;
375
      var listMod = (state.listDepth - 1) % 3;
376
      if (!listMod)
377
        state.layoutType = "list1";
378
      else if (listMod === 1)
379
        state.layoutType = "list2";
380
      else
381
        state.layoutType = "list3";
382

383
      state.mode = Modes.attributes;
384
      return tokenStyles(state);
385
    },
386

387
    link: function(stream, state) {
388
      state.mode = Modes.text;
389
      if (stream.match(RE("link"))) {
390
        stream.match(/\S+/);
391
        return tokenStylesWith(state, TOKEN_STYLES.link);
392
      }
393
      return tokenStyles(state);
394
    },
395

396
    linkDefinition: function(stream, state) {
397
      stream.skipToEnd();
398
      return tokenStylesWith(state, TOKEN_STYLES.linkDefinition);
399
    },
400

401
    definitionList: function(stream, state) {
402
      stream.match(RE("definitionList"));
403

404
      state.layoutType = "definitionList";
405

406
      if (stream.match(/\s*$/))
407
        state.spanningLayout = true;
408
      else
409
        state.mode = Modes.attributes;
410

411
      return tokenStyles(state);
412
    },
413

414
    html: function(stream, state) {
415
      stream.skipToEnd();
416
      return tokenStylesWith(state, TOKEN_STYLES.html);
417
    },
418

419
    table: function(stream, state) {
420
      state.layoutType = "table";
421
      return (state.mode = Modes.tableCell)(stream, state);
422
    },
423

424
    tableCell: function(stream, state) {
425
      if (stream.match(RE("tableHeading")))
426
        state.tableHeading = true;
427
      else
428
        stream.eat("|");
429

430
      state.mode = Modes.tableCellAttributes;
431
      return tokenStyles(state);
432
    },
433

434
    tableCellAttributes: function(stream, state) {
435
      state.mode = Modes.tableText;
436

437
      if (stream.match(RE("tableCellAttributes")))
438
        return tokenStylesWith(state, TOKEN_STYLES.attributes);
439
      else
440
        return tokenStyles(state);
441
    },
442

443
    tableText: function(stream, state) {
444
      if (stream.match(RE("tableText")))
445
        return tokenStyles(state);
446

447
      if (stream.peek() === "|") { // end of cell
448
        state.mode = Modes.tableCell;
449
        return tokenStyles(state);
450
      }
451
      return handlePhraseModifier(stream, state, stream.next());
452
    }
453
  };
454

455
  CodeMirror.defineMode("textile", function() {
456
    return {
457
      startState: function() {
458
        return { mode: Modes.newLayout };
459
      },
460
      token: function(stream, state) {
461
        if (stream.sol()) startNewLine(stream, state);
462
        return state.mode(stream, state);
463
      },
464
      blankLine: blankLine
465
    };
466
  });
467

468
  CodeMirror.defineMIME("text/x-textile", "textile");
469
});
470

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

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

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

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