html.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. import { languages } from '../fillers/monaco-editor-core.js';
  6. var EMPTY_ELEMENTS = [
  7. 'area',
  8. 'base',
  9. 'br',
  10. 'col',
  11. 'embed',
  12. 'hr',
  13. 'img',
  14. 'input',
  15. 'keygen',
  16. 'link',
  17. 'menuitem',
  18. 'meta',
  19. 'param',
  20. 'source',
  21. 'track',
  22. 'wbr'
  23. ];
  24. export var conf = {
  25. wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
  26. comments: {
  27. blockComment: ['<!--', '-->']
  28. },
  29. brackets: [
  30. ['<!--', '-->'],
  31. ['<', '>'],
  32. ['{', '}'],
  33. ['(', ')']
  34. ],
  35. autoClosingPairs: [
  36. { open: '{', close: '}' },
  37. { open: '[', close: ']' },
  38. { open: '(', close: ')' },
  39. { open: '"', close: '"' },
  40. { open: "'", close: "'" }
  41. ],
  42. surroundingPairs: [
  43. { open: '"', close: '"' },
  44. { open: "'", close: "'" },
  45. { open: '{', close: '}' },
  46. { open: '[', close: ']' },
  47. { open: '(', close: ')' },
  48. { open: '<', close: '>' }
  49. ],
  50. onEnterRules: [
  51. {
  52. beforeText: new RegExp("<(?!(?:" + EMPTY_ELEMENTS.join('|') + "))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$", 'i'),
  53. afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i,
  54. action: {
  55. indentAction: languages.IndentAction.IndentOutdent
  56. }
  57. },
  58. {
  59. beforeText: new RegExp("<(?!(?:" + EMPTY_ELEMENTS.join('|') + "))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$", 'i'),
  60. action: { indentAction: languages.IndentAction.Indent }
  61. }
  62. ],
  63. folding: {
  64. markers: {
  65. start: new RegExp('^\\s*<!--\\s*#region\\b.*-->'),
  66. end: new RegExp('^\\s*<!--\\s*#endregion\\b.*-->')
  67. }
  68. }
  69. };
  70. export var language = {
  71. defaultToken: '',
  72. tokenPostfix: '.html',
  73. ignoreCase: true,
  74. // The main tokenizer for our languages
  75. tokenizer: {
  76. root: [
  77. [/<!DOCTYPE/, 'metatag', '@doctype'],
  78. [/<!--/, 'comment', '@comment'],
  79. [/(<)((?:[\w\-]+:)?[\w\-]+)(\s*)(\/>)/, ['delimiter', 'tag', '', 'delimiter']],
  80. [/(<)(script)/, ['delimiter', { token: 'tag', next: '@script' }]],
  81. [/(<)(style)/, ['delimiter', { token: 'tag', next: '@style' }]],
  82. [/(<)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter', { token: 'tag', next: '@otherTag' }]],
  83. [/(<\/)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter', { token: 'tag', next: '@otherTag' }]],
  84. [/</, 'delimiter'],
  85. [/[^<]+/] // text
  86. ],
  87. doctype: [
  88. [/[^>]+/, 'metatag.content'],
  89. [/>/, 'metatag', '@pop']
  90. ],
  91. comment: [
  92. [/-->/, 'comment', '@pop'],
  93. [/[^-]+/, 'comment.content'],
  94. [/./, 'comment.content']
  95. ],
  96. otherTag: [
  97. [/\/?>/, 'delimiter', '@pop'],
  98. [/"([^"]*)"/, 'attribute.value'],
  99. [/'([^']*)'/, 'attribute.value'],
  100. [/[\w\-]+/, 'attribute.name'],
  101. [/=/, 'delimiter'],
  102. [/[ \t\r\n]+/] // whitespace
  103. ],
  104. // -- BEGIN <script> tags handling
  105. // After <script
  106. script: [
  107. [/type/, 'attribute.name', '@scriptAfterType'],
  108. [/"([^"]*)"/, 'attribute.value'],
  109. [/'([^']*)'/, 'attribute.value'],
  110. [/[\w\-]+/, 'attribute.name'],
  111. [/=/, 'delimiter'],
  112. [
  113. />/,
  114. {
  115. token: 'delimiter',
  116. next: '@scriptEmbedded',
  117. nextEmbedded: 'text/javascript'
  118. }
  119. ],
  120. [/[ \t\r\n]+/],
  121. [/(<\/)(script\s*)(>)/, ['delimiter', 'tag', { token: 'delimiter', next: '@pop' }]]
  122. ],
  123. // After <script ... type
  124. scriptAfterType: [
  125. [/=/, 'delimiter', '@scriptAfterTypeEquals'],
  126. [
  127. />/,
  128. {
  129. token: 'delimiter',
  130. next: '@scriptEmbedded',
  131. nextEmbedded: 'text/javascript'
  132. }
  133. ],
  134. [/[ \t\r\n]+/],
  135. [/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
  136. ],
  137. // After <script ... type =
  138. scriptAfterTypeEquals: [
  139. [
  140. /"([^"]*)"/,
  141. {
  142. token: 'attribute.value',
  143. switchTo: '@scriptWithCustomType.$1'
  144. }
  145. ],
  146. [
  147. /'([^']*)'/,
  148. {
  149. token: 'attribute.value',
  150. switchTo: '@scriptWithCustomType.$1'
  151. }
  152. ],
  153. [
  154. />/,
  155. {
  156. token: 'delimiter',
  157. next: '@scriptEmbedded',
  158. nextEmbedded: 'text/javascript'
  159. }
  160. ],
  161. [/[ \t\r\n]+/],
  162. [/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
  163. ],
  164. // After <script ... type = $S2
  165. scriptWithCustomType: [
  166. [
  167. />/,
  168. {
  169. token: 'delimiter',
  170. next: '@scriptEmbedded.$S2',
  171. nextEmbedded: '$S2'
  172. }
  173. ],
  174. [/"([^"]*)"/, 'attribute.value'],
  175. [/'([^']*)'/, 'attribute.value'],
  176. [/[\w\-]+/, 'attribute.name'],
  177. [/=/, 'delimiter'],
  178. [/[ \t\r\n]+/],
  179. [/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
  180. ],
  181. scriptEmbedded: [
  182. [/<\/script/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
  183. [/[^<]+/, '']
  184. ],
  185. // -- END <script> tags handling
  186. // -- BEGIN <style> tags handling
  187. // After <style
  188. style: [
  189. [/type/, 'attribute.name', '@styleAfterType'],
  190. [/"([^"]*)"/, 'attribute.value'],
  191. [/'([^']*)'/, 'attribute.value'],
  192. [/[\w\-]+/, 'attribute.name'],
  193. [/=/, 'delimiter'],
  194. [
  195. />/,
  196. {
  197. token: 'delimiter',
  198. next: '@styleEmbedded',
  199. nextEmbedded: 'text/css'
  200. }
  201. ],
  202. [/[ \t\r\n]+/],
  203. [/(<\/)(style\s*)(>)/, ['delimiter', 'tag', { token: 'delimiter', next: '@pop' }]]
  204. ],
  205. // After <style ... type
  206. styleAfterType: [
  207. [/=/, 'delimiter', '@styleAfterTypeEquals'],
  208. [
  209. />/,
  210. {
  211. token: 'delimiter',
  212. next: '@styleEmbedded',
  213. nextEmbedded: 'text/css'
  214. }
  215. ],
  216. [/[ \t\r\n]+/],
  217. [/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
  218. ],
  219. // After <style ... type =
  220. styleAfterTypeEquals: [
  221. [
  222. /"([^"]*)"/,
  223. {
  224. token: 'attribute.value',
  225. switchTo: '@styleWithCustomType.$1'
  226. }
  227. ],
  228. [
  229. /'([^']*)'/,
  230. {
  231. token: 'attribute.value',
  232. switchTo: '@styleWithCustomType.$1'
  233. }
  234. ],
  235. [
  236. />/,
  237. {
  238. token: 'delimiter',
  239. next: '@styleEmbedded',
  240. nextEmbedded: 'text/css'
  241. }
  242. ],
  243. [/[ \t\r\n]+/],
  244. [/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
  245. ],
  246. // After <style ... type = $S2
  247. styleWithCustomType: [
  248. [
  249. />/,
  250. {
  251. token: 'delimiter',
  252. next: '@styleEmbedded.$S2',
  253. nextEmbedded: '$S2'
  254. }
  255. ],
  256. [/"([^"]*)"/, 'attribute.value'],
  257. [/'([^']*)'/, 'attribute.value'],
  258. [/[\w\-]+/, 'attribute.name'],
  259. [/=/, 'delimiter'],
  260. [/[ \t\r\n]+/],
  261. [/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
  262. ],
  263. styleEmbedded: [
  264. [/<\/style/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
  265. [/[^<]+/, '']
  266. ]
  267. // -- END <style> tags handling
  268. }
  269. };
  270. // TESTED WITH:
  271. // <!DOCTYPE html>
  272. // <html>
  273. // <head>
  274. // <title>Monarch Workbench</title>
  275. // <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  276. // <!----
  277. // -- -- -- a comment -- -- --
  278. // ---->
  279. // <style bah="bah">
  280. // body { font-family: Consolas; } /* nice */
  281. // </style>
  282. // </head
  283. // >
  284. // a = "asd"
  285. // <body>
  286. // <br/>
  287. // <div
  288. // class
  289. // =
  290. // "test"
  291. // >
  292. // <script>
  293. // function() {
  294. // alert("hi </ script>"); // javascript
  295. // };
  296. // </script>
  297. // <script
  298. // bah="asdfg"
  299. // type="text/css"
  300. // >
  301. // .bar { text-decoration: underline; }
  302. // </script>
  303. // </div>
  304. // </body>
  305. // </html>