508896d25b3cd4fbd1e8ddb5539fbb90c6f5ed8c
[myslice.git] / third-party / codemirror-3.15 / mode / rst / rst.js
1 CodeMirror.defineMode('rst-base', function (config) {
2
3     ///////////////////////////////////////////////////////////////////////////
4     ///////////////////////////////////////////////////////////////////////////
5
6     function format(string) {
7         var args = Array.prototype.slice.call(arguments, 1);
8         return string.replace(/{(\d+)}/g, function (match, n) {
9             return typeof args[n] != 'undefined' ? args[n] : match;
10         });
11     }
12
13     function AssertException(message) {
14         this.message = message;
15     }
16
17     AssertException.prototype.toString = function () {
18         return 'AssertException: ' + this.message;
19     };
20
21     function assert(expression, message) {
22         if (!expression) throw new AssertException(message);
23         return expression;
24     }
25
26     ///////////////////////////////////////////////////////////////////////////
27     ///////////////////////////////////////////////////////////////////////////
28
29     var mode_python = CodeMirror.getMode(config, 'python');
30     var mode_stex = CodeMirror.getMode(config, 'stex');
31
32     ///////////////////////////////////////////////////////////////////////////
33     ///////////////////////////////////////////////////////////////////////////
34
35     var SEPA = "\\s+";
36     var TAIL = "(?:\\s*|\\W|$)",
37         rx_TAIL = new RegExp(format('^{0}', TAIL));
38
39     var NAME =
40         "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)",
41         rx_NAME = new RegExp(format('^{0}', NAME));
42     var NAME_WWS =
43         "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)";
44     var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);
45
46     var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)";
47     var TEXT2 = "(?:[^\\`]+)",
48         rx_TEXT2 = new RegExp(format('^{0}', TEXT2));
49
50     var rx_section = new RegExp(
51         "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$");
52     var rx_explicit = new RegExp(
53         format('^\\.\\.{0}', SEPA));
54     var rx_link = new RegExp(
55         format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL));
56     var rx_directive = new RegExp(
57         format('^{0}::{1}', REF_NAME, TAIL));
58     var rx_substitution = new RegExp(
59         format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL));
60     var rx_footnote = new RegExp(
61         format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL));
62     var rx_citation = new RegExp(
63         format('^\\[{0}\\]{1}', REF_NAME, TAIL));
64
65     var rx_substitution_ref = new RegExp(
66         format('^\\|{0}\\|', TEXT1));
67     var rx_footnote_ref = new RegExp(
68         format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME));
69     var rx_citation_ref = new RegExp(
70         format('^\\[{0}\\]_', REF_NAME));
71     var rx_link_ref1 = new RegExp(
72         format('^{0}__?', REF_NAME));
73     var rx_link_ref2 = new RegExp(
74         format('^`{0}`_', TEXT2));
75
76     var rx_role_pre = new RegExp(
77         format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL));
78     var rx_role_suf = new RegExp(
79         format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL));
80     var rx_role = new RegExp(
81         format('^:{0}:{1}', NAME, TAIL));
82
83     var rx_directive_name = new RegExp(format('^{0}', REF_NAME));
84     var rx_directive_tail = new RegExp(format('^::{0}', TAIL));
85     var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1));
86     var rx_substitution_sepa = new RegExp(format('^{0}', SEPA));
87     var rx_substitution_name = new RegExp(format('^{0}', REF_NAME));
88     var rx_substitution_tail = new RegExp(format('^::{0}', TAIL));
89     var rx_link_head = new RegExp("^_");
90     var rx_link_name = new RegExp(format('^{0}|_', REF_NAME));
91     var rx_link_tail = new RegExp(format('^:{0}', TAIL));
92
93     var rx_verbatim = new RegExp('^::\\s*$');
94     var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s');
95
96     ///////////////////////////////////////////////////////////////////////////
97     ///////////////////////////////////////////////////////////////////////////
98
99     function to_normal(stream, state) {
100         var token = null;
101
102         if (stream.sol() && stream.match(rx_examples, false)) {
103             change(state, to_mode, {
104                 mode: mode_python, local: mode_python.startState()
105             });
106         } else if (stream.sol() && stream.match(rx_explicit)) {
107             change(state, to_explicit);
108             token = 'meta';
109         } else if (stream.sol() && stream.match(rx_section)) {
110             change(state, to_normal);
111             token = 'header';
112         } else if (phase(state) == rx_role_pre ||
113             stream.match(rx_role_pre, false)) {
114
115             switch (stage(state)) {
116                 case 0:
117                     change(state, to_normal, context(rx_role_pre, 1));
118                     assert(stream.match(/^:/));
119                     token = 'meta';
120                     break;
121                 case 1:
122                     change(state, to_normal, context(rx_role_pre, 2));
123                     assert(stream.match(rx_NAME));
124                     token = 'keyword';
125
126                     if (stream.current().match(/^(?:math|latex)/)) {
127                         state.tmp = {
128                             mode: mode_stex, local: mode_stex.startState()
129                         };
130                     }
131                     break;
132                 case 2:
133                     change(state, to_normal, context(rx_role_pre, 3));
134                     assert(stream.match(/^:`/));
135                     token = 'meta';
136                     break;
137                 case 3:
138                     if (state.tmp) {
139                         if (stream.peek() == '`') {
140                             change(state, to_normal, context(rx_role_pre, 4));
141                             state.tmp = undefined;
142                             break;
143                         }
144
145                         token = state.tmp.mode.token(stream, state.tmp.local);
146                         break;
147                     }
148
149                     change(state, to_normal, context(rx_role_pre, 4));
150                     assert(stream.match(rx_TEXT2));
151                     token = 'string';
152                     break;
153                 case 4:
154                     change(state, to_normal, context(rx_role_pre, 5));
155                     assert(stream.match(/^`/));
156                     token = 'meta';
157                     break;
158                 case 5:
159                     change(state, to_normal, context(rx_role_pre, 6));
160                     assert(stream.match(rx_TAIL));
161                     break;
162                 default:
163                     change(state, to_normal);
164                     assert(stream.current() == '');
165             }
166         } else if (phase(state) == rx_role_suf ||
167             stream.match(rx_role_suf, false)) {
168
169             switch (stage(state)) {
170                 case 0:
171                     change(state, to_normal, context(rx_role_suf, 1));
172                     assert(stream.match(/^`/));
173                     token = 'meta';
174                     break;
175                 case 1:
176                     change(state, to_normal, context(rx_role_suf, 2));
177                     assert(stream.match(rx_TEXT2));
178                     token = 'string';
179                     break;
180                 case 2:
181                     change(state, to_normal, context(rx_role_suf, 3));
182                     assert(stream.match(/^`:/));
183                     token = 'meta';
184                     break;
185                 case 3:
186                     change(state, to_normal, context(rx_role_suf, 4));
187                     assert(stream.match(rx_NAME));
188                     token = 'keyword';
189                     break;
190                 case 4:
191                     change(state, to_normal, context(rx_role_suf, 5));
192                     assert(stream.match(/^:/));
193                     token = 'meta';
194                     break;
195                 case 5:
196                     change(state, to_normal, context(rx_role_suf, 6));
197                     assert(stream.match(rx_TAIL));
198                     break;
199                 default:
200                     change(state, to_normal);
201                     assert(stream.current() == '');
202             }
203         } else if (phase(state) == rx_role || stream.match(rx_role, false)) {
204
205             switch (stage(state)) {
206                 case 0:
207                     change(state, to_normal, context(rx_role, 1));
208                     assert(stream.match(/^:/));
209                     token = 'meta';
210                     break;
211                 case 1:
212                     change(state, to_normal, context(rx_role, 2));
213                     assert(stream.match(rx_NAME));
214                     token = 'keyword';
215                     break;
216                 case 2:
217                     change(state, to_normal, context(rx_role, 3));
218                     assert(stream.match(/^:/));
219                     token = 'meta';
220                     break;
221                 case 3:
222                     change(state, to_normal, context(rx_role, 4));
223                     assert(stream.match(rx_TAIL));
224                     break;
225                 default:
226                     change(state, to_normal);
227                     assert(stream.current() == '');
228             }
229         } else if (phase(state) == rx_substitution_ref ||
230             stream.match(rx_substitution_ref, false)) {
231
232             switch (stage(state)) {
233                 case 0:
234                     change(state, to_normal, context(rx_substitution_ref, 1));
235                     assert(stream.match(rx_substitution_text));
236                     token = 'variable-2';
237                     break;
238                 case 1:
239                     change(state, to_normal, context(rx_substitution_ref, 2));
240                     if (stream.match(/^_?_?/)) token = 'link';
241                     break;
242                 default:
243                     change(state, to_normal);
244                     assert(stream.current() == '');
245             }
246         } else if (stream.match(rx_footnote_ref)) {
247             change(state, to_normal);
248             token = 'quote';
249         } else if (stream.match(rx_citation_ref)) {
250             change(state, to_normal);
251             token = 'quote';
252         } else if (stream.match(rx_link_ref1)) {
253             change(state, to_normal);
254             if (!stream.peek() || stream.peek().match(/^\W$/)) {
255                 token = 'link';
256             }
257         } else if (phase(state) == rx_link_ref2 ||
258             stream.match(rx_link_ref2, false)) {
259
260             switch (stage(state)) {
261                 case 0:
262                     if (!stream.peek() || stream.peek().match(/^\W$/)) {
263                         change(state, to_normal, context(rx_link_ref2, 1));
264                     } else {
265                         stream.match(rx_link_ref2);
266                     }
267                     break;
268                 case 1:
269                     change(state, to_normal, context(rx_link_ref2, 2));
270                     assert(stream.match(/^`/));
271                     token = 'link';
272                     break;
273                 case 2:
274                     change(state, to_normal, context(rx_link_ref2, 3));
275                     assert(stream.match(rx_TEXT2));
276                     break;
277                 case 3:
278                     change(state, to_normal, context(rx_link_ref2, 4));
279                     assert(stream.match(/^`_/));
280                     token = 'link';
281                     break;
282                 default:
283                     change(state, to_normal);
284                     assert(stream.current() == '');
285             }
286         } else if (stream.match(rx_verbatim)) {
287             change(state, to_verbatim);
288         }
289
290         else {
291             if (stream.next()) change(state, to_normal);
292         }
293
294         return token;
295     }
296
297     ///////////////////////////////////////////////////////////////////////////
298     ///////////////////////////////////////////////////////////////////////////
299
300     function to_explicit(stream, state) {
301         var token = null;
302
303         if (phase(state) == rx_substitution ||
304             stream.match(rx_substitution, false)) {
305
306             switch (stage(state)) {
307                 case 0:
308                     change(state, to_explicit, context(rx_substitution, 1));
309                     assert(stream.match(rx_substitution_text));
310                     token = 'variable-2';
311                     break;
312                 case 1:
313                     change(state, to_explicit, context(rx_substitution, 2));
314                     assert(stream.match(rx_substitution_sepa));
315                     break;
316                 case 2:
317                     change(state, to_explicit, context(rx_substitution, 3));
318                     assert(stream.match(rx_substitution_name));
319                     token = 'keyword';
320                     break;
321                 case 3:
322                     change(state, to_explicit, context(rx_substitution, 4));
323                     assert(stream.match(rx_substitution_tail));
324                     token = 'meta';
325                     break;
326                 default:
327                     change(state, to_normal);
328                     assert(stream.current() == '');
329             }
330         } else if (phase(state) == rx_directive ||
331             stream.match(rx_directive, false)) {
332
333             switch (stage(state)) {
334                 case 0:
335                     change(state, to_explicit, context(rx_directive, 1));
336                     assert(stream.match(rx_directive_name));
337                     token = 'keyword';
338
339                     if (stream.current().match(/^(?:math|latex)/))
340                         state.tmp_stex = true;
341                     else if (stream.current().match(/^python/))
342                         state.tmp_py = true;
343                     break;
344                 case 1:
345                     change(state, to_explicit, context(rx_directive, 2));
346                     assert(stream.match(rx_directive_tail));
347                     token = 'meta';
348                     break;
349                 default:
350                     if (stream.match(/^latex\s*$/) || state.tmp_stex) {
351                         state.tmp_stex = undefined;
352                         change(state, to_mode, {
353                             mode: mode_stex, local: mode_stex.startState()
354                         });
355                     } else if (stream.match(/^python\s*$/) || state.tmp_py) {
356                         state.tmp_py = undefined;
357                         change(state, to_mode, {
358                             mode: mode_python, local: mode_python.startState()
359                         });
360                     }
361
362                     else {
363                         change(state, to_normal);
364                         assert(stream.current() == '');
365                     }
366             }
367         } else if (phase(state) == rx_link || stream.match(rx_link, false)) {
368
369             switch (stage(state)) {
370                 case 0:
371                     change(state, to_explicit, context(rx_link, 1));
372                     assert(stream.match(rx_link_head));
373                     assert(stream.match(rx_link_name));
374                     token = 'link';
375                     break;
376                 case 1:
377                     change(state, to_explicit, context(rx_link, 2));
378                     assert(stream.match(rx_link_tail));
379                     token = 'meta';
380                     break;
381                 default:
382                     change(state, to_normal);
383                     assert(stream.current() == '');
384             }
385         } else if (stream.match(rx_footnote)) {
386             change(state, to_normal);
387             token = 'quote';
388         } else if (stream.match(rx_citation)) {
389             change(state, to_normal);
390             token = 'quote';
391         }
392
393         else {
394             stream.eatSpace();
395             if (stream.eol()) {
396                 change(state, to_normal);
397             } else {
398                 stream.skipToEnd();
399                 change(state, to_comment);
400                 token = 'comment';
401             }
402         }
403
404         return token;
405     }
406
407     ///////////////////////////////////////////////////////////////////////////
408     ///////////////////////////////////////////////////////////////////////////
409
410     function to_comment(stream, state) {
411         return as_block(stream, state, 'comment');
412     }
413
414     function to_verbatim(stream, state) {
415         return as_block(stream, state, 'meta');
416     }
417
418     function as_block(stream, state, token) {
419         if (stream.eol() || stream.eatSpace()) {
420             stream.skipToEnd();
421             return token;
422         } else {
423             change(state, to_normal);
424             return null;
425         }
426     }
427
428     ///////////////////////////////////////////////////////////////////////////
429     ///////////////////////////////////////////////////////////////////////////
430
431     function to_mode(stream, state) {
432
433         if (state.ctx.mode && state.ctx.local) {
434
435             if (stream.sol()) {
436                 if (!stream.eatSpace()) change(state, to_normal);
437                 return null;
438             }
439
440             try {
441                 return state.ctx.mode.token(stream, state.ctx.local);
442             } catch (ex) {
443                 change(state, to_normal);
444                 return null;
445             }
446         }
447
448         change(state, to_normal);
449         return null;
450     }
451
452     ///////////////////////////////////////////////////////////////////////////
453     ///////////////////////////////////////////////////////////////////////////
454
455     function context(phase, stage, mode, local) {
456         return {phase: phase, stage: stage, mode: mode, local: local};
457     }
458
459     function change(state, tok, ctx) {
460         state.tok = tok;
461         state.ctx = ctx || {};
462     }
463
464     function stage(state) {
465         return state.ctx.stage || 0;
466     }
467
468     function phase(state) {
469         return state.ctx.phase;
470     }
471
472     ///////////////////////////////////////////////////////////////////////////
473     ///////////////////////////////////////////////////////////////////////////
474
475     return {
476         startState: function () {
477             return {tok: to_normal, ctx: context(undefined, 0)};
478         },
479
480         copyState: function (state) {
481             return {tok: state.tok, ctx: state.ctx};
482         },
483
484         innerMode: function (state) {
485             return state.tmp ? {state: state.tmp.local, mode: state.tmp.mode}
486                  : state.ctx ? {state: state.ctx.local, mode: state.ctx.mode}
487                              : null;
488         },
489
490         token: function (stream, state) {
491             return state.tok(stream, state);
492         }
493     };
494 }, 'python', 'stex');
495
496 ///////////////////////////////////////////////////////////////////////////////
497 ///////////////////////////////////////////////////////////////////////////////
498
499 CodeMirror.defineMode('rst', function (config, options) {
500
501     var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
502     var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/;
503     var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/;
504
505     var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/;
506     var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
507     var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
508
509     var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://";
510     var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})";
511     var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*";
512     var rx_uri = new RegExp("^" +
513         rx_uri_protocol + rx_uri_domain + rx_uri_path
514     );
515
516     var overlay = {
517         token: function (stream) {
518
519             if (stream.match(rx_strong) && stream.match (/\W+|$/, false))
520                 return 'strong';
521             if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false))
522                 return 'em';
523             if (stream.match(rx_literal) && stream.match (/\W+|$/, false))
524                 return 'string-2';
525             if (stream.match(rx_number))
526                 return 'number';
527             if (stream.match(rx_positive))
528                 return 'positive';
529             if (stream.match(rx_negative))
530                 return 'negative';
531             if (stream.match(rx_uri))
532                 return 'link';
533
534             while (stream.next() != null) {
535                 if (stream.match(rx_strong, false)) break;
536                 if (stream.match(rx_emphasis, false)) break;
537                 if (stream.match(rx_literal, false)) break;
538                 if (stream.match(rx_number, false)) break;
539                 if (stream.match(rx_positive, false)) break;
540                 if (stream.match(rx_negative, false)) break;
541                 if (stream.match(rx_uri, false)) break;
542             }
543
544             return null;
545         }
546     };
547
548     var mode = CodeMirror.getMode(
549         config, options.backdrop || 'rst-base'
550     );
551
552     return CodeMirror.overlayMode(mode, overlay, true); // combine
553 }, 'python', 'stex');
554
555 ///////////////////////////////////////////////////////////////////////////////
556 ///////////////////////////////////////////////////////////////////////////////
557
558 CodeMirror.defineMIME('text/x-rst', 'rst');
559
560 ///////////////////////////////////////////////////////////////////////////////
561 ///////////////////////////////////////////////////////////////////////////////