1 CodeMirror.defineMode('rst-base', function (config) {
3 ///////////////////////////////////////////////////////////////////////////
4 ///////////////////////////////////////////////////////////////////////////
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;
13 function AssertException(message) {
14 this.message = message;
17 AssertException.prototype.toString = function () {
18 return 'AssertException: ' + this.message;
21 function assert(expression, message) {
22 if (!expression) throw new AssertException(message);
26 ///////////////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////////////
29 var mode_python = CodeMirror.getMode(config, 'python');
30 var mode_stex = CodeMirror.getMode(config, 'stex');
32 ///////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////
36 var TAIL = "(?:\\s*|\\W|$)",
37 rx_TAIL = new RegExp(format('^{0}', TAIL));
40 "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)",
41 rx_NAME = new RegExp(format('^{0}', NAME));
43 "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)";
44 var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);
46 var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)";
47 var TEXT2 = "(?:[^\\`]+)",
48 rx_TEXT2 = new RegExp(format('^{0}', TEXT2));
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));
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));
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));
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));
93 var rx_verbatim = new RegExp('^::\\s*$');
94 var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s');
96 ///////////////////////////////////////////////////////////////////////////
97 ///////////////////////////////////////////////////////////////////////////
99 function to_normal(stream, state) {
102 if (stream.sol() && stream.match(rx_examples, false)) {
103 change(state, to_mode, {
104 mode: mode_python, local: mode_python.startState()
106 } else if (stream.sol() && stream.match(rx_explicit)) {
107 change(state, to_explicit);
109 } else if (stream.sol() && stream.match(rx_section)) {
110 change(state, to_normal);
112 } else if (phase(state) == rx_role_pre ||
113 stream.match(rx_role_pre, false)) {
115 switch (stage(state)) {
117 change(state, to_normal, context(rx_role_pre, 1));
118 assert(stream.match(/^:/));
122 change(state, to_normal, context(rx_role_pre, 2));
123 assert(stream.match(rx_NAME));
126 if (stream.current().match(/^(?:math|latex)/)) {
128 mode: mode_stex, local: mode_stex.startState()
133 change(state, to_normal, context(rx_role_pre, 3));
134 assert(stream.match(/^:`/));
139 if (stream.peek() == '`') {
140 change(state, to_normal, context(rx_role_pre, 4));
141 state.tmp = undefined;
145 token = state.tmp.mode.token(stream, state.tmp.local);
149 change(state, to_normal, context(rx_role_pre, 4));
150 assert(stream.match(rx_TEXT2));
154 change(state, to_normal, context(rx_role_pre, 5));
155 assert(stream.match(/^`/));
159 change(state, to_normal, context(rx_role_pre, 6));
160 assert(stream.match(rx_TAIL));
163 change(state, to_normal);
164 assert(stream.current() == '');
166 } else if (phase(state) == rx_role_suf ||
167 stream.match(rx_role_suf, false)) {
169 switch (stage(state)) {
171 change(state, to_normal, context(rx_role_suf, 1));
172 assert(stream.match(/^`/));
176 change(state, to_normal, context(rx_role_suf, 2));
177 assert(stream.match(rx_TEXT2));
181 change(state, to_normal, context(rx_role_suf, 3));
182 assert(stream.match(/^`:/));
186 change(state, to_normal, context(rx_role_suf, 4));
187 assert(stream.match(rx_NAME));
191 change(state, to_normal, context(rx_role_suf, 5));
192 assert(stream.match(/^:/));
196 change(state, to_normal, context(rx_role_suf, 6));
197 assert(stream.match(rx_TAIL));
200 change(state, to_normal);
201 assert(stream.current() == '');
203 } else if (phase(state) == rx_role || stream.match(rx_role, false)) {
205 switch (stage(state)) {
207 change(state, to_normal, context(rx_role, 1));
208 assert(stream.match(/^:/));
212 change(state, to_normal, context(rx_role, 2));
213 assert(stream.match(rx_NAME));
217 change(state, to_normal, context(rx_role, 3));
218 assert(stream.match(/^:/));
222 change(state, to_normal, context(rx_role, 4));
223 assert(stream.match(rx_TAIL));
226 change(state, to_normal);
227 assert(stream.current() == '');
229 } else if (phase(state) == rx_substitution_ref ||
230 stream.match(rx_substitution_ref, false)) {
232 switch (stage(state)) {
234 change(state, to_normal, context(rx_substitution_ref, 1));
235 assert(stream.match(rx_substitution_text));
236 token = 'variable-2';
239 change(state, to_normal, context(rx_substitution_ref, 2));
240 if (stream.match(/^_?_?/)) token = 'link';
243 change(state, to_normal);
244 assert(stream.current() == '');
246 } else if (stream.match(rx_footnote_ref)) {
247 change(state, to_normal);
249 } else if (stream.match(rx_citation_ref)) {
250 change(state, to_normal);
252 } else if (stream.match(rx_link_ref1)) {
253 change(state, to_normal);
254 if (!stream.peek() || stream.peek().match(/^\W$/)) {
257 } else if (phase(state) == rx_link_ref2 ||
258 stream.match(rx_link_ref2, false)) {
260 switch (stage(state)) {
262 if (!stream.peek() || stream.peek().match(/^\W$/)) {
263 change(state, to_normal, context(rx_link_ref2, 1));
265 stream.match(rx_link_ref2);
269 change(state, to_normal, context(rx_link_ref2, 2));
270 assert(stream.match(/^`/));
274 change(state, to_normal, context(rx_link_ref2, 3));
275 assert(stream.match(rx_TEXT2));
278 change(state, to_normal, context(rx_link_ref2, 4));
279 assert(stream.match(/^`_/));
283 change(state, to_normal);
284 assert(stream.current() == '');
286 } else if (stream.match(rx_verbatim)) {
287 change(state, to_verbatim);
291 if (stream.next()) change(state, to_normal);
297 ///////////////////////////////////////////////////////////////////////////
298 ///////////////////////////////////////////////////////////////////////////
300 function to_explicit(stream, state) {
303 if (phase(state) == rx_substitution ||
304 stream.match(rx_substitution, false)) {
306 switch (stage(state)) {
308 change(state, to_explicit, context(rx_substitution, 1));
309 assert(stream.match(rx_substitution_text));
310 token = 'variable-2';
313 change(state, to_explicit, context(rx_substitution, 2));
314 assert(stream.match(rx_substitution_sepa));
317 change(state, to_explicit, context(rx_substitution, 3));
318 assert(stream.match(rx_substitution_name));
322 change(state, to_explicit, context(rx_substitution, 4));
323 assert(stream.match(rx_substitution_tail));
327 change(state, to_normal);
328 assert(stream.current() == '');
330 } else if (phase(state) == rx_directive ||
331 stream.match(rx_directive, false)) {
333 switch (stage(state)) {
335 change(state, to_explicit, context(rx_directive, 1));
336 assert(stream.match(rx_directive_name));
339 if (stream.current().match(/^(?:math|latex)/))
340 state.tmp_stex = true;
341 else if (stream.current().match(/^python/))
345 change(state, to_explicit, context(rx_directive, 2));
346 assert(stream.match(rx_directive_tail));
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()
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()
363 change(state, to_normal);
364 assert(stream.current() == '');
367 } else if (phase(state) == rx_link || stream.match(rx_link, false)) {
369 switch (stage(state)) {
371 change(state, to_explicit, context(rx_link, 1));
372 assert(stream.match(rx_link_head));
373 assert(stream.match(rx_link_name));
377 change(state, to_explicit, context(rx_link, 2));
378 assert(stream.match(rx_link_tail));
382 change(state, to_normal);
383 assert(stream.current() == '');
385 } else if (stream.match(rx_footnote)) {
386 change(state, to_normal);
388 } else if (stream.match(rx_citation)) {
389 change(state, to_normal);
396 change(state, to_normal);
399 change(state, to_comment);
407 ///////////////////////////////////////////////////////////////////////////
408 ///////////////////////////////////////////////////////////////////////////
410 function to_comment(stream, state) {
411 return as_block(stream, state, 'comment');
414 function to_verbatim(stream, state) {
415 return as_block(stream, state, 'meta');
418 function as_block(stream, state, token) {
419 if (stream.eol() || stream.eatSpace()) {
423 change(state, to_normal);
428 ///////////////////////////////////////////////////////////////////////////
429 ///////////////////////////////////////////////////////////////////////////
431 function to_mode(stream, state) {
433 if (state.ctx.mode && state.ctx.local) {
436 if (!stream.eatSpace()) change(state, to_normal);
441 return state.ctx.mode.token(stream, state.ctx.local);
443 change(state, to_normal);
448 change(state, to_normal);
452 ///////////////////////////////////////////////////////////////////////////
453 ///////////////////////////////////////////////////////////////////////////
455 function context(phase, stage, mode, local) {
456 return {phase: phase, stage: stage, mode: mode, local: local};
459 function change(state, tok, ctx) {
461 state.ctx = ctx || {};
464 function stage(state) {
465 return state.ctx.stage || 0;
468 function phase(state) {
469 return state.ctx.phase;
472 ///////////////////////////////////////////////////////////////////////////
473 ///////////////////////////////////////////////////////////////////////////
476 startState: function () {
477 return {tok: to_normal, ctx: context(undefined, 0)};
480 copyState: function (state) {
481 return {tok: state.tok, ctx: state.ctx};
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}
490 token: function (stream, state) {
491 return state.tok(stream, state);
494 }, 'python', 'stex');
496 ///////////////////////////////////////////////////////////////////////////////
497 ///////////////////////////////////////////////////////////////////////////////
499 CodeMirror.defineMode('rst', function (config, options) {
501 var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
502 var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/;
503 var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/;
505 var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/;
506 var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
507 var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
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
517 token: function (stream) {
519 if (stream.match(rx_strong) && stream.match (/\W+|$/, false))
521 if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false))
523 if (stream.match(rx_literal) && stream.match (/\W+|$/, false))
525 if (stream.match(rx_number))
527 if (stream.match(rx_positive))
529 if (stream.match(rx_negative))
531 if (stream.match(rx_uri))
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;
548 var mode = CodeMirror.getMode(
549 config, options.backdrop || 'rst-base'
552 return CodeMirror.overlayMode(mode, overlay, true); // combine
553 }, 'python', 'stex');
555 ///////////////////////////////////////////////////////////////////////////////
556 ///////////////////////////////////////////////////////////////////////////////
558 CodeMirror.defineMIME('text/x-rst', 'rst');
560 ///////////////////////////////////////////////////////////////////////////////
561 ///////////////////////////////////////////////////////////////////////////////