rst.js 17 KB

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