markdown.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. export var conf = {
  6. comments: {
  7. blockComment: ['<!--', '-->']
  8. },
  9. brackets: [
  10. ['{', '}'],
  11. ['[', ']'],
  12. ['(', ')']
  13. ],
  14. autoClosingPairs: [
  15. { open: '{', close: '}' },
  16. { open: '[', close: ']' },
  17. { open: '(', close: ')' },
  18. { open: '<', close: '>', notIn: ['string'] }
  19. ],
  20. surroundingPairs: [
  21. { open: '(', close: ')' },
  22. { open: '[', close: ']' },
  23. { open: '`', close: '`' }
  24. ],
  25. folding: {
  26. markers: {
  27. start: new RegExp('^\\s*<!--\\s*#?region\\b.*-->'),
  28. end: new RegExp('^\\s*<!--\\s*#?endregion\\b.*-->')
  29. }
  30. }
  31. };
  32. export var language = {
  33. defaultToken: '',
  34. tokenPostfix: '.md',
  35. // escape codes
  36. control: /[\\`*_\[\]{}()#+\-\.!]/,
  37. noncontrol: /[^\\`*_\[\]{}()#+\-\.!]/,
  38. escapes: /\\(?:@control)/,
  39. // escape codes for javascript/CSS strings
  40. jsescapes: /\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/,
  41. // non matched elements
  42. empty: [
  43. 'area',
  44. 'base',
  45. 'basefont',
  46. 'br',
  47. 'col',
  48. 'frame',
  49. 'hr',
  50. 'img',
  51. 'input',
  52. 'isindex',
  53. 'link',
  54. 'meta',
  55. 'param'
  56. ],
  57. tokenizer: {
  58. root: [
  59. // markdown tables
  60. [/^\s*\|/, '@rematch', '@table_header'],
  61. // headers (with #)
  62. [
  63. /^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/,
  64. ['white', 'keyword', 'keyword', 'keyword']
  65. ],
  66. // headers (with =)
  67. [/^\s*(=+|\-+)\s*$/, 'keyword'],
  68. // headers (with ***)
  69. [/^\s*((\*[ ]?)+)\s*$/, 'meta.separator'],
  70. // quote
  71. [/^\s*>+/, 'comment'],
  72. // list (starting with * or number)
  73. [/^\s*([\*\-+:]|\d+\.)\s/, 'keyword'],
  74. // code block (4 spaces indent)
  75. [/^(\t|[ ]{4})[^ ].*$/, 'string'],
  76. // code block (3 tilde)
  77. [/^\s*~~~\s*((?:\w|[\/\-#])+)?\s*$/, { token: 'string', next: '@codeblock' }],
  78. // github style code blocks (with backticks and language)
  79. [
  80. /^\s*```\s*((?:\w|[\/\-#])+).*$/,
  81. { token: 'string', next: '@codeblockgh', nextEmbedded: '$1' }
  82. ],
  83. // github style code blocks (with backticks but no language)
  84. [/^\s*```\s*$/, { token: 'string', next: '@codeblock' }],
  85. // markup within lines
  86. { include: '@linecontent' }
  87. ],
  88. table_header: [
  89. { include: '@table_common' },
  90. [/[^\|]+/, 'keyword.table.header'] // table header
  91. ],
  92. table_body: [{ include: '@table_common' }, { include: '@linecontent' }],
  93. table_common: [
  94. [/\s*[\-:]+\s*/, { token: 'keyword', switchTo: 'table_body' }],
  95. [/^\s*\|/, 'keyword.table.left'],
  96. [/^\s*[^\|]/, '@rematch', '@pop'],
  97. [/^\s*$/, '@rematch', '@pop'],
  98. [
  99. /\|/,
  100. {
  101. cases: {
  102. '@eos': 'keyword.table.right',
  103. '@default': 'keyword.table.middle' // inner |
  104. }
  105. }
  106. ]
  107. ],
  108. codeblock: [
  109. [/^\s*~~~\s*$/, { token: 'string', next: '@pop' }],
  110. [/^\s*```\s*$/, { token: 'string', next: '@pop' }],
  111. [/.*$/, 'variable.source']
  112. ],
  113. // github style code blocks
  114. codeblockgh: [
  115. [/```\s*$/, { token: 'string', next: '@pop', nextEmbedded: '@pop' }],
  116. [/[^`]+/, 'variable.source']
  117. ],
  118. linecontent: [
  119. // escapes
  120. [/&\w+;/, 'string.escape'],
  121. [/@escapes/, 'escape'],
  122. // various markup
  123. [/\b__([^\\_]|@escapes|_(?!_))+__\b/, 'strong'],
  124. [/\*\*([^\\*]|@escapes|\*(?!\*))+\*\*/, 'strong'],
  125. [/\b_[^_]+_\b/, 'emphasis'],
  126. [/\*([^\\*]|@escapes)+\*/, 'emphasis'],
  127. [/`([^\\`]|@escapes)+`/, 'variable'],
  128. // links
  129. [/\{+[^}]+\}+/, 'string.target'],
  130. [/(!?\[)((?:[^\]\\]|@escapes)*)(\]\([^\)]+\))/, ['string.link', '', 'string.link']],
  131. [/(!?\[)((?:[^\]\\]|@escapes)*)(\])/, 'string.link'],
  132. // or html
  133. { include: 'html' }
  134. ],
  135. // Note: it is tempting to rather switch to the real HTML mode instead of building our own here
  136. // but currently there is a limitation in Monarch that prevents us from doing it: The opening
  137. // '<' would start the HTML mode, however there is no way to jump 1 character back to let the
  138. // HTML mode also tokenize the opening angle bracket. Thus, even though we could jump to HTML,
  139. // we cannot correctly tokenize it in that mode yet.
  140. html: [
  141. // html tags
  142. [/<(\w+)\/>/, 'tag'],
  143. [
  144. /<(\w+)/,
  145. {
  146. cases: {
  147. '@empty': { token: 'tag', next: '@tag.$1' },
  148. '@default': { token: 'tag', next: '@tag.$1' }
  149. }
  150. }
  151. ],
  152. [/<\/(\w+)\s*>/, { token: 'tag' }],
  153. [/<!--/, 'comment', '@comment']
  154. ],
  155. comment: [
  156. [/[^<\-]+/, 'comment.content'],
  157. [/-->/, 'comment', '@pop'],
  158. [/<!--/, 'comment.content.invalid'],
  159. [/[<\-]/, 'comment.content']
  160. ],
  161. // Almost full HTML tag matching, complete with embedded scripts & styles
  162. tag: [
  163. [/[ \t\r\n]+/, 'white'],
  164. [
  165. /(type)(\s*=\s*)(")([^"]+)(")/,
  166. [
  167. 'attribute.name.html',
  168. 'delimiter.html',
  169. 'string.html',
  170. { token: 'string.html', switchTo: '@tag.$S2.$4' },
  171. 'string.html'
  172. ]
  173. ],
  174. [
  175. /(type)(\s*=\s*)(')([^']+)(')/,
  176. [
  177. 'attribute.name.html',
  178. 'delimiter.html',
  179. 'string.html',
  180. { token: 'string.html', switchTo: '@tag.$S2.$4' },
  181. 'string.html'
  182. ]
  183. ],
  184. [
  185. /(\w+)(\s*=\s*)("[^"]*"|'[^']*')/,
  186. ['attribute.name.html', 'delimiter.html', 'string.html']
  187. ],
  188. [/\w+/, 'attribute.name.html'],
  189. [/\/>/, 'tag', '@pop'],
  190. [
  191. />/,
  192. {
  193. cases: {
  194. '$S2==style': {
  195. token: 'tag',
  196. switchTo: 'embeddedStyle',
  197. nextEmbedded: 'text/css'
  198. },
  199. '$S2==script': {
  200. cases: {
  201. $S3: {
  202. token: 'tag',
  203. switchTo: 'embeddedScript',
  204. nextEmbedded: '$S3'
  205. },
  206. '@default': {
  207. token: 'tag',
  208. switchTo: 'embeddedScript',
  209. nextEmbedded: 'text/javascript'
  210. }
  211. }
  212. },
  213. '@default': { token: 'tag', next: '@pop' }
  214. }
  215. }
  216. ]
  217. ],
  218. embeddedStyle: [
  219. [/[^<]+/, ''],
  220. [/<\/style\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
  221. [/</, '']
  222. ],
  223. embeddedScript: [
  224. [/[^<]+/, ''],
  225. [/<\/script\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
  226. [/</, '']
  227. ]
  228. }
  229. };