gfm.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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("../markdown/markdown"), require("../../addon/mode/overlay"));
  6. else if (typeof define == "function" && define.amd) // AMD
  7. define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod);
  8. else // Plain browser env
  9. mod(CodeMirror);
  10. })(function(CodeMirror) {
  11. "use strict";
  12. CodeMirror.defineMode("gfm", function(config, modeConfig) {
  13. var codeDepth = 0;
  14. function blankLine(state) {
  15. state.code = false;
  16. return null;
  17. }
  18. var gfmOverlay = {
  19. startState: function() {
  20. return {
  21. code: false,
  22. codeBlock: false,
  23. ateSpace: false
  24. };
  25. },
  26. copyState: function(s) {
  27. return {
  28. code: s.code,
  29. codeBlock: s.codeBlock,
  30. ateSpace: s.ateSpace
  31. };
  32. },
  33. token: function(stream, state) {
  34. state.combineTokens = null;
  35. // Hack to prevent formatting override inside code blocks (block and inline)
  36. if (state.codeBlock) {
  37. if (stream.match(/^```/)) {
  38. state.codeBlock = false;
  39. return null;
  40. }
  41. stream.skipToEnd();
  42. return null;
  43. }
  44. if (stream.sol()) {
  45. state.code = false;
  46. }
  47. if (stream.sol() && stream.match(/^```/)) {
  48. stream.skipToEnd();
  49. state.codeBlock = true;
  50. return null;
  51. }
  52. // If this block is changed, it may need to be updated in Markdown mode
  53. if (stream.peek() === '`') {
  54. stream.next();
  55. var before = stream.pos;
  56. stream.eatWhile('`');
  57. var difference = 1 + stream.pos - before;
  58. if (!state.code) {
  59. codeDepth = difference;
  60. state.code = true;
  61. } else {
  62. if (difference === codeDepth) { // Must be exact
  63. state.code = false;
  64. }
  65. }
  66. return null;
  67. } else if (state.code) {
  68. stream.next();
  69. return null;
  70. }
  71. // Check if space. If so, links can be formatted later on
  72. if (stream.eatSpace()) {
  73. state.ateSpace = true;
  74. return null;
  75. }
  76. if (stream.sol() || state.ateSpace) {
  77. state.ateSpace = false;
  78. // by vfleaking. forbid this feature
  79. /*
  80. if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
  81. // User/Project@SHA
  82. // User@SHA
  83. // SHA
  84. state.combineTokens = true;
  85. return "link";
  86. } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
  87. // User/Project#Num
  88. // User#Num
  89. // #Num
  90. state.combineTokens = true;
  91. return "link";
  92. }*/
  93. }
  94. if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i) &&
  95. stream.string.slice(stream.start - 2, stream.start) != "](") {
  96. // URLs
  97. // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
  98. // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
  99. state.combineTokens = true;
  100. return "link";
  101. }
  102. stream.next();
  103. return null;
  104. },
  105. blankLine: blankLine
  106. };
  107. var markdownConfig = {
  108. underscoresBreakWords: false,
  109. taskLists: true,
  110. fencedCodeBlocks: true
  111. };
  112. for (var attr in modeConfig) {
  113. markdownConfig[attr] = modeConfig[attr];
  114. }
  115. markdownConfig.name = "markdown";
  116. CodeMirror.defineMIME("gfmBase", markdownConfig);
  117. return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay);
  118. }, "markdown");
  119. });