index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict';
  2. module.exports = function ins_plugin(md) {
  3. // Insert each marker as a separate text token, and add it to delimiter list
  4. //
  5. function tokenize(state, silent) {
  6. var i, scanned, token, len, ch,
  7. start = state.pos,
  8. marker = state.src.charCodeAt(start);
  9. if (silent) { return false; }
  10. if (marker !== 0x3D/* = */) { return false; }
  11. scanned = state.scanDelims(state.pos, true);
  12. len = scanned.length;
  13. ch = String.fromCharCode(marker);
  14. if (len < 2) { return false; }
  15. if (len % 2) {
  16. token = state.push('text', '', 0);
  17. token.content = ch;
  18. len--;
  19. }
  20. for (i = 0; i < len; i += 2) {
  21. token = state.push('text', '', 0);
  22. token.content = ch + ch;
  23. if (!scanned.can_open && !scanned.can_close) { continue; }
  24. state.delimiters.push({
  25. marker: marker,
  26. length: 0, // disable "rule of 3" length checks meant for emphasis
  27. jump: i / 2, // 1 delimiter = 2 characters
  28. token: state.tokens.length - 1,
  29. end: -1,
  30. open: scanned.can_open,
  31. close: scanned.can_close
  32. });
  33. }
  34. state.pos += scanned.length;
  35. return true;
  36. }
  37. // Walk through delimiter list and replace text tokens with tags
  38. //
  39. function postProcess(state, delimiters) {
  40. var i, j,
  41. startDelim,
  42. endDelim,
  43. token,
  44. loneMarkers = [],
  45. max = delimiters.length;
  46. for (i = 0; i < max; i++) {
  47. startDelim = delimiters[i];
  48. if (startDelim.marker !== 0x3D/* = */) {
  49. continue;
  50. }
  51. if (startDelim.end === -1) {
  52. continue;
  53. }
  54. endDelim = delimiters[startDelim.end];
  55. token = state.tokens[startDelim.token];
  56. token.type = 'mark_open';
  57. token.tag = 'mark';
  58. token.nesting = 1;
  59. token.markup = '==';
  60. token.content = '';
  61. token = state.tokens[endDelim.token];
  62. token.type = 'mark_close';
  63. token.tag = 'mark';
  64. token.nesting = -1;
  65. token.markup = '==';
  66. token.content = '';
  67. if (state.tokens[endDelim.token - 1].type === 'text' &&
  68. state.tokens[endDelim.token - 1].content === '=') {
  69. loneMarkers.push(endDelim.token - 1);
  70. }
  71. }
  72. // If a marker sequence has an odd number of characters, it's splitted
  73. // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
  74. // start of the sequence.
  75. //
  76. // So, we have to move all those markers after subsequent s_close tags.
  77. //
  78. while (loneMarkers.length) {
  79. i = loneMarkers.pop();
  80. j = i + 1;
  81. while (j < state.tokens.length && state.tokens[j].type === 'mark_close') {
  82. j++;
  83. }
  84. j--;
  85. if (i !== j) {
  86. token = state.tokens[j];
  87. state.tokens[j] = state.tokens[i];
  88. state.tokens[i] = token;
  89. }
  90. }
  91. }
  92. md.inline.ruler.before('emphasis', 'mark', tokenize);
  93. md.inline.ruler2.before('emphasis', 'mark', function (state) {
  94. var curr,
  95. tokens_meta = state.tokens_meta,
  96. max = (state.tokens_meta || []).length;
  97. postProcess(state, state.delimiters);
  98. for (curr = 0; curr < max; curr++) {
  99. if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
  100. postProcess(state, tokens_meta[curr].delimiters);
  101. }
  102. }
  103. });
  104. };