CodeMirror.defineMode('rst-base', function (config) { /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function format(string) { var args = Array.prototype.slice.call(arguments, 1); return string.replace(/{(\d+)}/g, function (match, n) { return typeof args[n] != 'undefined' ? args[n] : match; }); } function AssertException(message) { this.message = message; } AssertException.prototype.toString = function () { return 'AssertException: ' + this.message; }; function assert(expression, message) { if (!expression) throw new AssertException(message); return expression; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// var mode_python = CodeMirror.getMode(config, 'python'); var mode_stex = CodeMirror.getMode(config, 'stex'); /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// var SEPA = "\\s+"; var TAIL = "(?:\\s*|\\W|$)", rx_TAIL = new RegExp(format('^{0}', TAIL)); var NAME = "(?:[^\\W\\d_](?:[\\w\\+\\.\\-:]*[^\\W_])?)", rx_NAME = new RegExp(format('^{0}', NAME)); var NAME_WWS = "(?:[^\\W\\d_](?:[\\w\\s\\+\\.\\-:]*[^\\W_])?)"; var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS); var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)"; var TEXT2 = "(?:[^\\`]+)", rx_TEXT2 = new RegExp(format('^{0}', TEXT2)); var rx_section = new RegExp( "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$"); var rx_explicit = new RegExp( format('^\\.\\.{0}', SEPA)); var rx_link = new RegExp( format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL)); var rx_directive = new RegExp( format('^{0}::{1}', REF_NAME, TAIL)); var rx_substitution = new RegExp( format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL)); var rx_footnote = new RegExp( format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL)); var rx_citation = new RegExp( format('^\\[{0}\\]{1}', REF_NAME, TAIL)); var rx_substitution_ref = new RegExp( format('^\\|{0}\\|', TEXT1)); var rx_footnote_ref = new RegExp( format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME)); var rx_citation_ref = new RegExp( format('^\\[{0}\\]_', REF_NAME)); var rx_link_ref1 = new RegExp( format('^{0}__?', REF_NAME)); var rx_link_ref2 = new RegExp( format('^`{0}`_', TEXT2)); var rx_role_pre = new RegExp( format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL)); var rx_role_suf = new RegExp( format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL)); var rx_role = new RegExp( format('^:{0}:{1}', NAME, TAIL)); var rx_directive_name = new RegExp(format('^{0}', REF_NAME)); var rx_directive_tail = new RegExp(format('^::{0}', TAIL)); var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1)); var rx_substitution_sepa = new RegExp(format('^{0}', SEPA)); var rx_substitution_name = new RegExp(format('^{0}', REF_NAME)); var rx_substitution_tail = new RegExp(format('^::{0}', TAIL)); var rx_link_head = new RegExp("^_"); var rx_link_name = new RegExp(format('^{0}|_', REF_NAME)); var rx_link_tail = new RegExp(format('^:{0}', TAIL)); var rx_verbatim = new RegExp('^::\\s*$'); var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s'); /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function to_normal(stream, state) { var token = null; if (stream.sol() && stream.match(rx_examples, false)) { change(state, to_mode, { mode: mode_python, local: mode_python.startState() }); } else if (stream.sol() && stream.match(rx_explicit)) { change(state, to_explicit); token = 'meta'; } else if (stream.sol() && stream.match(rx_section)) { change(state, to_normal); token = 'header'; } else if (phase(state) == rx_role_pre || stream.match(rx_role_pre, false)) { switch (stage(state)) { case 0: change(state, to_normal, context(rx_role_pre, 1)); assert(stream.match(/^:/)); token = 'meta'; break; case 1: change(state, to_normal, context(rx_role_pre, 2)); assert(stream.match(rx_NAME)); token = 'keyword'; if (stream.current().match(/^(?:math|latex)/)) { state.tmp = { mode: mode_stex, local: mode_stex.startState() }; } break; case 2: change(state, to_normal, context(rx_role_pre, 3)); assert(stream.match(/^:`/)); token = 'meta'; break; case 3: if (state.tmp) { if (stream.peek() == '`') { change(state, to_normal, context(rx_role_pre, 4)); state.tmp = undefined; break; } token = state.tmp.mode.token(stream, state.tmp.local); break; } change(state, to_normal, context(rx_role_pre, 4)); assert(stream.match(rx_TEXT2)); token = 'string'; break; case 4: change(state, to_normal, context(rx_role_pre, 5)); assert(stream.match(/^`/)); token = 'meta'; break; case 5: change(state, to_normal, context(rx_role_pre, 6)); assert(stream.match(rx_TAIL)); break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (phase(state) == rx_role_suf || stream.match(rx_role_suf, false)) { switch (stage(state)) { case 0: change(state, to_normal, context(rx_role_suf, 1)); assert(stream.match(/^`/)); token = 'meta'; break; case 1: change(state, to_normal, context(rx_role_suf, 2)); assert(stream.match(rx_TEXT2)); token = 'string'; break; case 2: change(state, to_normal, context(rx_role_suf, 3)); assert(stream.match(/^`:/)); token = 'meta'; break; case 3: change(state, to_normal, context(rx_role_suf, 4)); assert(stream.match(rx_NAME)); token = 'keyword'; break; case 4: change(state, to_normal, context(rx_role_suf, 5)); assert(stream.match(/^:/)); token = 'meta'; break; case 5: change(state, to_normal, context(rx_role_suf, 6)); assert(stream.match(rx_TAIL)); break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (phase(state) == rx_role || stream.match(rx_role, false)) { switch (stage(state)) { case 0: change(state, to_normal, context(rx_role, 1)); assert(stream.match(/^:/)); token = 'meta'; break; case 1: change(state, to_normal, context(rx_role, 2)); assert(stream.match(rx_NAME)); token = 'keyword'; break; case 2: change(state, to_normal, context(rx_role, 3)); assert(stream.match(/^:/)); token = 'meta'; break; case 3: change(state, to_normal, context(rx_role, 4)); assert(stream.match(rx_TAIL)); break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (phase(state) == rx_substitution_ref || stream.match(rx_substitution_ref, false)) { switch (stage(state)) { case 0: change(state, to_normal, context(rx_substitution_ref, 1)); assert(stream.match(rx_substitution_text)); token = 'variable-2'; break; case 1: change(state, to_normal, context(rx_substitution_ref, 2)); if (stream.match(/^_?_?/)) token = 'link'; break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (stream.match(rx_footnote_ref)) { change(state, to_normal); token = 'quote'; } else if (stream.match(rx_citation_ref)) { change(state, to_normal); token = 'quote'; } else if (stream.match(rx_link_ref1)) { change(state, to_normal); if (!stream.peek() || stream.peek().match(/^\W$/)) { token = 'link'; } } else if (phase(state) == rx_link_ref2 || stream.match(rx_link_ref2, false)) { switch (stage(state)) { case 0: if (!stream.peek() || stream.peek().match(/^\W$/)) { change(state, to_normal, context(rx_link_ref2, 1)); } else { stream.match(rx_link_ref2); } break; case 1: change(state, to_normal, context(rx_link_ref2, 2)); assert(stream.match(/^`/)); token = 'link'; break; case 2: change(state, to_normal, context(rx_link_ref2, 3)); assert(stream.match(rx_TEXT2)); break; case 3: change(state, to_normal, context(rx_link_ref2, 4)); assert(stream.match(/^`_/)); token = 'link'; break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (stream.match(rx_verbatim)) { change(state, to_verbatim); } else { if (stream.next()) change(state, to_normal); } return token; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function to_explicit(stream, state) { var token = null; if (phase(state) == rx_substitution || stream.match(rx_substitution, false)) { switch (stage(state)) { case 0: change(state, to_explicit, context(rx_substitution, 1)); assert(stream.match(rx_substitution_text)); token = 'variable-2'; break; case 1: change(state, to_explicit, context(rx_substitution, 2)); assert(stream.match(rx_substitution_sepa)); break; case 2: change(state, to_explicit, context(rx_substitution, 3)); assert(stream.match(rx_substitution_name)); token = 'keyword'; break; case 3: change(state, to_explicit, context(rx_substitution, 4)); assert(stream.match(rx_substitution_tail)); token = 'meta'; break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (phase(state) == rx_directive || stream.match(rx_directive, false)) { switch (stage(state)) { case 0: change(state, to_explicit, context(rx_directive, 1)); assert(stream.match(rx_directive_name)); token = 'keyword'; if (stream.current().match(/^(?:math|latex)/)) state.tmp_stex = true; else if (stream.current().match(/^python/)) state.tmp_py = true; break; case 1: change(state, to_explicit, context(rx_directive, 2)); assert(stream.match(rx_directive_tail)); token = 'meta'; break; default: if (stream.match(/^latex\s*$/) || state.tmp_stex) { state.tmp_stex = undefined; change(state, to_mode, { mode: mode_stex, local: mode_stex.startState() }); } else if (stream.match(/^python\s*$/) || state.tmp_py) { state.tmp_py = undefined; change(state, to_mode, { mode: mode_python, local: mode_python.startState() }); } else { change(state, to_normal); assert(stream.current() == ''); } } } else if (phase(state) == rx_link || stream.match(rx_link, false)) { switch (stage(state)) { case 0: change(state, to_explicit, context(rx_link, 1)); assert(stream.match(rx_link_head)); assert(stream.match(rx_link_name)); token = 'link'; break; case 1: change(state, to_explicit, context(rx_link, 2)); assert(stream.match(rx_link_tail)); token = 'meta'; break; default: change(state, to_normal); assert(stream.current() == ''); } } else if (stream.match(rx_footnote)) { change(state, to_normal); token = 'quote'; } else if (stream.match(rx_citation)) { change(state, to_normal); token = 'quote'; } else { stream.eatSpace(); if (stream.eol()) { change(state, to_normal); } else { stream.skipToEnd(); change(state, to_comment); token = 'comment'; } } return token; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function to_comment(stream, state) { return as_block(stream, state, 'comment'); } function to_verbatim(stream, state) { return as_block(stream, state, 'meta'); } function as_block(stream, state, token) { if (stream.eol() || stream.eatSpace()) { stream.skipToEnd(); return token; } else { change(state, to_normal); return null; } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function to_mode(stream, state) { if (state.ctx.mode && state.ctx.local) { if (stream.sol()) { if (!stream.eatSpace()) change(state, to_normal); return null; } try { return state.ctx.mode.token(stream, state.ctx.local); } catch (ex) { change(state, to_normal); return null; } } change(state, to_normal); return null; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// function context(phase, stage, mode, local) { return {phase: phase, stage: stage, mode: mode, local: local}; } function change(state, tok, ctx) { state.tok = tok; state.ctx = ctx || {}; } function stage(state) { return state.ctx.stage || 0; } function phase(state) { return state.ctx.phase; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// return { startState: function () { return {tok: to_normal, ctx: context(undefined, 0)}; }, copyState: function (state) { return {tok: state.tok, ctx: state.ctx}; }, innerMode: function (state) { return {state: state.ctx.local, mode: state.ctx.mode}; }, token: function (stream, state) { return state.tok(stream, state); } }; }, 'python', 'stex'); /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// CodeMirror.defineMode('rst', function (config, options) { var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://"; var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})"; var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*"; var rx_uri = new RegExp("^" + rx_uri_protocol + rx_uri_domain + rx_uri_path ); var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*(\s+|$)/; var rx_emphasis = /^[^\*]\*[^\*\s](?:[^\*]*[^\*\s])?\*(\s+|$)/; var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``(\s+|$)/; var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/; var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/; var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/; var overlay = { token: function (stream) { if (stream.match(rx_uri)) return 'link'; if (stream.match(rx_strong)) return 'strong'; if (stream.match(rx_emphasis)) return 'em'; if (stream.match(rx_literal)) return 'string-2'; if (stream.match(rx_number)) return 'number'; if (stream.match(rx_positive)) return 'positive'; if (stream.match(rx_negative)) return 'negative'; while (stream.next() != null) { if (stream.match(rx_uri, false)) break; if (stream.match(rx_strong, false)) break; if (stream.match(rx_emphasis, false)) break; if (stream.match(rx_literal, false)) break; if (stream.match(rx_number, false)) break; if (stream.match(rx_positive, false)) break; if (stream.match(rx_negative, false)) break; } return null; } }; var mode = CodeMirror.getMode( config, options.backdrop || 'rst-base' ); return CodeMirror.overlayMode(mode, overlay, true); // combine }, 'python', 'stex'); /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// CodeMirror.defineMIME('text/x-rst', 'rst'); /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////