瀏覽代碼

Add HTML rules w/ substate

Marco Petersen 5 年之前
父節點
當前提交
63e076eb1f
共有 1 個文件被更改,包括 142 次插入7 次删除
  1. 142 7
      src/twig/twig.ts

+ 142 - 7
src/twig/twig.ts

@@ -5,8 +5,6 @@
 
 'use strict';
 
-import { conf as htmlConf, language as htmlLanguage } from '../html/html';
-
 import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration;
 import ILanguage = monaco.languages.IMonarchLanguage;
 
@@ -23,7 +21,10 @@ export const conf: IRichLanguageConfiguration = {
 		['{{', '}}'],
 		['(', ')'],
 		['[', ']'],
-		...htmlConf.brackets,
+
+		// HTML
+		['<!--', '-->'],
+		['<', '>'],
 	],
 
 	autoClosingPairs: [
@@ -39,7 +40,9 @@ export const conf: IRichLanguageConfiguration = {
 	surroundingPairs: [
 		{ open: '"', close: '"' },
 		{ open: '\'', close: '\'' },
-		...htmlConf.surroundingPairs,
+
+		// HTML
+		{ open: '<', close: '>' },
 	],
 }
 
@@ -61,13 +64,25 @@ export const language = <ILanguage>{
 	],
 
 	tokenizer: {
-		...htmlLanguage.tokenizer,
-
 		root: [
+			// whitespace
+			[/\s+/],
+
+			// Twig Tag Delimiters
 			[/{#/, 'comment.twig', '@commentState'],
 			[/{%[-~]?/, 'delimiter.twig', '@blockState'],
 			[/{{[-~]?/, 'delimiter.twig', '@variableState'],
-			...htmlLanguage.tokenizer.root,
+
+			// HTML
+			[/<!DOCTYPE/, 'metatag.html', '@doctype'],
+			[/<!--/, 'comment.html', '@comment'],
+			[/(<)((?:[\w\-]+:)?[\w\-]+)(\s*)(\/>)/, ['delimiter.html', 'tag.html', '', 'delimiter.html']],
+			[/(<)(script)/, ['delimiter.html', { token: 'tag.html', next: '@script' }]],
+			[/(<)(style)/, ['delimiter.html', { token: 'tag.html', next: '@style' }]],
+			[/(<)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]],
+			[/(<\/)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter.html', { token: 'tag.html', next: '@otherTag' }]],
+			[/</, 'delimiter.html'],
+			[/[^<]+/], // text
 		],
 
 		/**
@@ -175,5 +190,125 @@ export const language = <ILanguage>{
 			// assignment
 			[/=/, 'operators.twig'],
 		],
+
+		/**
+		 * HTML
+		 */
+		doctype: [
+			[/[^>]+/, 'metatag.content.html'],
+			[/>/, 'metatag.html', '@pop'],
+		],
+
+		comment: [
+			[/-->/, 'comment.html', '@pop'],
+			[/[^-]+/, 'comment.content.html'],
+			[/./, 'comment.content.html']
+		],
+
+		otherTag: [
+			[/\/?>/, 'delimiter.html', '@pop'],
+			[/"([^"]*)"/, 'attribute.value.html'],
+			[/'([^']*)'/, 'attribute.value.html'],
+			[/[\w\-]+/, 'attribute.name.html'],
+			[/=/, 'delimiter.html'],
+			[/[ \t\r\n]+/], // whitespace
+		],
+
+		// -- BEGIN <script> tags handling
+
+		// After <script
+		script: [
+			[/type/, 'attribute.name.html', '@scriptAfterType'],
+			[/"([^"]*)"/, 'attribute.value.html'],
+			[/'([^']*)'/, 'attribute.value.html'],
+			[/[\w\-]+/, 'attribute.name.html'],
+			[/=/, 'delimiter.html'],
+			[/>/, { token: 'delimiter.html', next: '@scriptEmbedded', nextEmbedded: 'text/javascript' }],
+			[/[ \t\r\n]+/], // whitespace
+			[/(<\/)(script\s*)(>)/, ['delimiter.html', 'tag.html', { token: 'delimiter.html', next: '@pop' }]]
+		],
+
+		// After <script ... type
+		scriptAfterType: [
+			[/=/, 'delimiter.html', '@scriptAfterTypeEquals'],
+			[/>/, { token: 'delimiter.html', next: '@scriptEmbedded', nextEmbedded: 'text/javascript' }], // cover invalid e.g. <script type>
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		// After <script ... type =
+		scriptAfterTypeEquals: [
+			[/"([^"]*)"/, { token: 'attribute.value.html', switchTo: '@scriptWithCustomType.$1' }],
+			[/'([^']*)'/, { token: 'attribute.value.html', switchTo: '@scriptWithCustomType.$1' }],
+			[/>/, { token: 'delimiter.html', next: '@scriptEmbedded', nextEmbedded: 'text/javascript' }], // cover invalid e.g. <script type=>
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		// After <script ... type = $S2
+		scriptWithCustomType: [
+			[/>/, { token: 'delimiter.html', next: '@scriptEmbedded.$S2', nextEmbedded: '$S2' }],
+			[/"([^"]*)"/, 'attribute.value.html'],
+			[/'([^']*)'/, 'attribute.value.html'],
+			[/[\w\-]+/, 'attribute.name.html'],
+			[/=/, 'delimiter.html'],
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/script\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		scriptEmbedded: [
+			[/<\/script/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
+			[/[^<]+/, '']
+		],
+
+		// -- END <script> tags handling
+
+
+		// -- BEGIN <style> tags handling
+
+		// After <style
+		style: [
+			[/type/, 'attribute.name.html', '@styleAfterType'],
+			[/"([^"]*)"/, 'attribute.value.html'],
+			[/'([^']*)'/, 'attribute.value.html'],
+			[/[\w\-]+/, 'attribute.name.html'],
+			[/=/, 'delimiter.html'],
+			[/>/, { token: 'delimiter.html', next: '@styleEmbedded', nextEmbedded: 'text/css' }],
+			[/[ \t\r\n]+/], // whitespace
+			[/(<\/)(style\s*)(>)/, ['delimiter.html', 'tag.html', { token: 'delimiter.html', next: '@pop' }]]
+		],
+
+		// After <style ... type
+		styleAfterType: [
+			[/=/, 'delimiter.html', '@styleAfterTypeEquals'],
+			[/>/, { token: 'delimiter.html', next: '@styleEmbedded', nextEmbedded: 'text/css' }], // cover invalid e.g. <style type>
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		// After <style ... type =
+		styleAfterTypeEquals: [
+			[/"([^"]*)"/, { token: 'attribute.value.html', switchTo: '@styleWithCustomType.$1' }],
+			[/'([^']*)'/, { token: 'attribute.value.html', switchTo: '@styleWithCustomType.$1' }],
+			[/>/, { token: 'delimiter.html', next: '@styleEmbedded', nextEmbedded: 'text/css' }], // cover invalid e.g. <style type=>
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		// After <style ... type = $S2
+		styleWithCustomType: [
+			[/>/, { token: 'delimiter.html', next: '@styleEmbedded.$S2', nextEmbedded: '$S2' }],
+			[/"([^"]*)"/, 'attribute.value.html'],
+			[/'([^']*)'/, 'attribute.value.html'],
+			[/[\w\-]+/, 'attribute.name.html'],
+			[/=/, 'delimiter.html'],
+			[/[ \t\r\n]+/], // whitespace
+			[/<\/style\s*>/, { token: '@rematch', next: '@pop' }]
+		],
+
+		styleEmbedded: [
+			[/<\/style/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
+			[/[^<]+/, '']
+		],
 	}
 };