HTML: mimeType support in the script tag.

This commit is contained in:
Fedor Korotkov
2012-12-05 11:38:12 +04:00
parent 425e87f594
commit 6defec933b
11 changed files with 315 additions and 47 deletions
@@ -20,6 +20,7 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
@@ -40,7 +41,10 @@ import java.util.*;
public abstract class Language extends UserDataHolderBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.Language");
private static final Map<Class<? extends Language>, Language> ourRegisteredLanguages = Collections.synchronizedMap(new THashMap<Class<? extends Language>, Language>());
private static final Map<Class<? extends Language>, Language> ourRegisteredLanguages =
Collections.synchronizedMap(new THashMap<Class<? extends Language>, Language>());
private static final Map<String, List<Language>> ourRegisteredMimeTypes =
Collections.synchronizedMap(new THashMap<String, List<Language>>());
private static final Map<String, Language> ourRegisteredIDs = new THashMap<String, Language>();
private final Language myBaseLanguage;
private final String myID;
@@ -69,12 +73,28 @@ public abstract class Language extends UserDataHolderBase {
Class<? extends Language> langClass = getClass();
Language prev = ourRegisteredLanguages.put(langClass, this);
if (prev != null) {
LOG.error("Language of '" + langClass + "' is already registered: "+prev);
LOG.error("Language of '" + langClass + "' is already registered: " + prev);
return;
}
prev = ourRegisteredIDs.put(ID, this);
if (prev != null) {
LOG.error("Language with ID '" + ID + "' is already registered: "+prev.getClass());
LOG.error("Language with ID '" + ID + "' is already registered: " + prev.getClass());
}
for (String mimeType : mimeTypes) {
if (StringUtil.isEmpty(mimeType)) {
continue;
}
List<Language> languagesByMimeType = ourRegisteredMimeTypes.get(mimeType);
if (languagesByMimeType == null) {
synchronized (ourRegisteredMimeTypes) {
languagesByMimeType = ourRegisteredMimeTypes.get(mimeType);
if (languagesByMimeType == null) {
languagesByMimeType = Collections.synchronizedList(new ArrayList<Language>());
ourRegisteredMimeTypes.put(mimeType, languagesByMimeType);
}
}
}
languagesByMimeType.add(this);
}
if (baseLanguage != null) {
baseLanguage.myDialects.add(this);
@@ -98,6 +118,16 @@ public abstract class Language extends UserDataHolderBase {
return (T)ourRegisteredLanguages.get(klass);
}
/**
* @param mimeType of the particular language.
* @return collection of all languages for the given <code>mimeType</code>.
*/
@NotNull
public static Collection<Language> findInstancesByMimeType(@Nullable String mimeType) {
List<Language> result = mimeType != null ? ourRegisteredMimeTypes.get(mimeType) : null;
return result != null ? Collections.unmodifiableCollection(result) : Collections.<Language>emptyList();
}
public String toString() {
//noinspection HardCodedStringLiteral
@@ -34,7 +34,7 @@
<extensionPoint name="intentionAction"
beanClass="com.intellij.codeInsight.intention.IntentionActionBean"/>
<extensionPoint name="codeInsight.unresolvedReferenceQuickFixProvider"
interface="com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider"/>
@@ -237,7 +237,7 @@
<extensionPoint name="favoritesListProvider"
interface="com.intellij.ide.favoritesTreeView.FavoritesListProvider"
area="IDEA_PROJECT"/>
<extensionPoint name="lang.emacs" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<!-- File-Based Index-->
@@ -311,7 +311,7 @@
<extensionPoint name="psi.referenceContributor" beanClass="com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP"/>
<extensionPoint name="psi.referenceProvider" beanClass="com.intellij.psi.PsiReferenceProviderBean"/>
<extensionPoint name="patterns.patternClass" beanClass="com.intellij.patterns.compiler.PatternClassBean"/>
<extensionPoint name="patterns.patternClass" beanClass="com.intellij.patterns.compiler.PatternClassBean"/>
<extensionPoint name="pom.declarationSearcher" interface="com.intellij.pom.PomDeclarationSearcher"/>
@@ -548,7 +548,7 @@
<extensionPoint name="project.converterProvider"
interface="com.intellij.conversion.ConverterProvider"/>
<extensionPoint name="treeCopyHandler"
interface="com.intellij.psi.impl.source.tree.TreeCopyHandler"/>
<extensionPoint name="treeGenerator"
@@ -567,4 +567,9 @@
beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="moduleRendererFactory" interface="com.intellij.ide.util.ModuleRendererFactory"/>
<extensionPoint name="html.scriptContentProvider"
beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="html.inlineScriptTokenTypesProvider"
beanClass="com.intellij.lang.LanguageExtensionPoint"/>
</extensionPoints>
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.tree.IElementType;
public interface HtmlInlineScriptTokenTypesProvider {
IElementType getElementType();
FileType getFileType();
}
@@ -0,0 +1,33 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang;
import com.intellij.lexer.Lexer;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
public interface HtmlScriptContentProvider {
/**
* @return instance of the <code>com.intellij.psi.tree.IElementType</code> to use in html script tag
*/
IElementType getScriptElementType();
/**
* @return highlighting lexer to use in html script tag
*/
@Nullable
Lexer getHighlightingLexer();
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang;
import org.jetbrains.annotations.Nullable;
public class LanguageHtmlInlineScriptTokenTypesProvider extends LanguageExtension<HtmlInlineScriptTokenTypesProvider> {
public final static LanguageHtmlInlineScriptTokenTypesProvider INSTANCE = new LanguageHtmlInlineScriptTokenTypesProvider();
public LanguageHtmlInlineScriptTokenTypesProvider() {
super("com.intellij.html.inlineScriptTokenTypesProvider");
}
@Nullable
public static HtmlInlineScriptTokenTypesProvider getInlineScriptProvider(@Nullable Language language) {
return language == null ? null : INSTANCE.forLanguage(language);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang;
import org.jetbrains.annotations.NotNull;
public class LanguageHtmlScriptContentProvider extends LanguageExtension<HtmlScriptContentProvider> {
public final static LanguageHtmlScriptContentProvider INSTANCE = new LanguageHtmlScriptContentProvider();
public LanguageHtmlScriptContentProvider() {
super("com.intellij.html.scriptContentProvider");
}
public static HtmlScriptContentProvider getScriptContentProvider(@NotNull Language language) {
return INSTANCE.forLanguage(language);
}
}
@@ -16,13 +16,19 @@
package com.intellij.lexer;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.lang.HtmlScriptContentProvider;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageHtmlScriptContentProvider;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
/**
@@ -36,11 +42,17 @@ abstract class BaseHtmlLexer extends DelegateLexer {
private static final int SEEN_ATTRIBUTE = 0x200;
private static final int SEEN_CONTENT_TYPE = 0x400;
protected static final int BASE_STATE_SHIFT = 11;
@Nullable
protected static Language ourDefaultLanguage = Language.findLanguageByID("JavaScript");
private boolean seenTag;
private boolean seenAttribute;
private boolean seenStyle;
private boolean seenScript;
@Nullable
protected String scriptType = null;
private final boolean caseInsensitive;
private boolean seenContentType;
private CharSequence cachedBufferSequence;
@@ -96,7 +108,7 @@ abstract class BaseHtmlLexer extends DelegateLexer {
final boolean style = name.equals(TOKEN_STYLE);
final int state = getState() & BASE_STATE_MASK;
final boolean script = name.equals(TOKEN_SCRIPT) ||
final boolean script = name.equals(TOKEN_SCRIPT) ||
((name.startsWith(TOKEN_ON) && name.indexOf(':') == -1 && !isHtmlTagState(state)));
if (style || script) {
@@ -136,9 +148,12 @@ abstract class BaseHtmlLexer extends DelegateLexer {
return; // something invalid
}
@NonNls String name = TreeUtil.getTokenText(lexer);
if (caseInsensitive) name = name.toLowerCase();
if (name.indexOf("javascript") == -1 && name.indexOf("jscript") == -1) {
@NonNls String mimeType = TreeUtil.getTokenText(lexer);
if (caseInsensitive) mimeType = mimeType.toLowerCase();
if (supportMimeType(mimeType)) {
scriptType = mimeType;
}
else {
seenScript = false;
seenTag = true; // will be switched of on tag name in end
}
@@ -146,6 +161,31 @@ abstract class BaseHtmlLexer extends DelegateLexer {
}
}
private boolean supportMimeType(String mimeType) {
return findScriptContentProvider(mimeType) != null;
}
@Nullable
protected IElementType getCurrentScriptElementType() {
HtmlScriptContentProvider scriptContentProvider = findScriptContentProvider(scriptType);
return scriptContentProvider == null ? null : scriptContentProvider.getScriptElementType();
}
@Nullable
protected static HtmlScriptContentProvider findScriptContentProvider(@Nullable String mimeType) {
if (StringUtil.isEmpty(mimeType)) {
return ourDefaultLanguage != null ? LanguageHtmlScriptContentProvider.getScriptContentProvider(ourDefaultLanguage) : null;
}
Collection<Language> instancesByMimeType = Language.findInstancesByMimeType(mimeType);
for (Language language : instancesByMimeType) {
HtmlScriptContentProvider scriptContentProvider = LanguageHtmlScriptContentProvider.getScriptContentProvider(language);
if (scriptContentProvider != null) {
return scriptContentProvider;
}
}
return null;
}
class XmlTagClosedHandler implements TokenHandler {
public void handleElement(Lexer lexer) {
if (seenAttribute) {
@@ -167,6 +207,7 @@ abstract class BaseHtmlLexer extends DelegateLexer {
seenScript=false;
seenAttribute=false;
seenContentType=false;
scriptType = null;
}
}
@@ -15,9 +15,14 @@
*/
package com.intellij.lexer;
import com.intellij.lang.HtmlInlineScriptTokenTypesProvider;
import com.intellij.lang.HtmlScriptContentProvider;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageHtmlInlineScriptTokenTypesProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlTokenType;
@@ -35,7 +40,14 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
protected Lexer elLexer;
private boolean hasNoEmbeddments;
private final static FileType ourStyleFileType = FileTypeManager.getInstance().getStdFileType("CSS");
private static FileType ourScriptFileType;
private static FileType ourInlineScriptFileType = null;
static {
// At the moment only JS.
HtmlInlineScriptTokenTypesProvider provider =
LanguageHtmlInlineScriptTokenTypesProvider.getInlineScriptProvider(Language.findLanguageByID("JavaScript"));
ourInlineScriptFileType = provider != null ? provider.getFileType() : null;
}
public class XmlEmbeddmentHandler implements TokenHandler {
public void handleElement(Lexer lexer) {
@@ -109,11 +121,22 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
newLexer = styleLexer;
} else if (hasSeenScript()) {
if (scriptLexer==null) {
scriptLexer = (ourScriptFileType!=null)? SyntaxHighlighterFactory.getSyntaxHighlighter(ourScriptFileType, null, null).getHighlightingLexer():null;
if (scriptLexer == null) {
if (hasSeenTag()) {
HtmlScriptContentProvider provider = findScriptContentProvider(scriptType);
scriptLexer = provider != null ? provider.getHighlightingLexer() : null;
}
else if (hasSeenAttribute()) {
SyntaxHighlighter syntaxHighlighter =
(ourInlineScriptFileType != null) ? SyntaxHighlighterFactory.getSyntaxHighlighter(ourInlineScriptFileType, null, null) : null;
scriptLexer = syntaxHighlighter != null ? syntaxHighlighter.getHighlightingLexer() : null;
}
}
newLexer = scriptLexer;
} else newLexer = createELLexer(newLexer);
}
else {
newLexer = createELLexer(newLexer);
}
if (newLexer!=null) {
embeddedLexer = newLexer;
@@ -189,10 +212,6 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
}
}
public static void registerScriptFileType(FileType _scriptFileType) {
ourScriptFileType = _scriptFileType;
}
public int getState() {
int state = super.getState();
@@ -203,7 +222,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
}
protected boolean isHtmlTagState(int state) {
return state == _HtmlLexer.START_TAG_NAME || state == _HtmlLexer.END_TAG_NAME ||
return state == _HtmlLexer.START_TAG_NAME || state == _HtmlLexer.END_TAG_NAME ||
state == _HtmlLexer.START_TAG_NAME2 || state == _HtmlLexer.END_TAG_NAME2;
}
+10 -8
View File
@@ -15,6 +15,9 @@
*/
package com.intellij.lexer;
import com.intellij.lang.HtmlInlineScriptTokenTypesProvider;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageHtmlInlineScriptTokenTypesProvider;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
@@ -26,7 +29,6 @@ import com.intellij.psi.xml.XmlTokenType;
public class HtmlLexer extends BaseHtmlLexer {
private static IElementType ourStyleElementType;
private static IElementType ourInlineStyleElementType;
private static IElementType ourScriptElementType;
private static IElementType ourInlineScriptElementType;
static {
@@ -37,6 +39,10 @@ public class HtmlLexer extends BaseHtmlLexer {
ourInlineStyleElementType = extension.getInlineElementType();
}
}
// At the moment only JS.
HtmlInlineScriptTokenTypesProvider provider =
LanguageHtmlInlineScriptTokenTypesProvider.getInlineScriptProvider(ourDefaultLanguage);
ourInlineScriptElementType = provider != null ? provider.getElementType() : null;
}
private IElementType myTokenType;
@@ -69,9 +75,10 @@ public class HtmlLexer extends BaseHtmlLexer {
tokenType = ourInlineStyleElementType;
}
} else if (hasSeenScript()) {
if (hasSeenTag() && ourScriptElementType!=null && isStartOfEmbeddmentTagContent(tokenType)) {
IElementType currentScriptElementType = getCurrentScriptElementType();
if (hasSeenTag() && currentScriptElementType != null && isStartOfEmbeddmentTagContent(tokenType)) {
myTokenEnd = skipToTheEndOfTheEmbeddment();
tokenType = ourScriptElementType;
tokenType = currentScriptElementType;
} else if (hasSeenAttribute() && isStartOfEmbeddmentAttributeValue(tokenType) && ourInlineScriptElementType!=null) {
myTokenEnd = skipToTheEndOfTheEmbeddment();
tokenType = ourInlineScriptElementType;
@@ -118,9 +125,4 @@ public class HtmlLexer extends BaseHtmlLexer {
}
return super.getTokenEnd();
}
public static void setScriptElementTypes(final IElementType scriptElementType, final IElementType inlineScriptElementType) {
ourScriptElementType = scriptElementType;
ourInlineScriptElementType = inlineScriptElementType;
}
}
@@ -1,15 +1,15 @@
package com.intellij.codeInsight;
import com.intellij.lang.ASTFactory;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LanguageASTFactory;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.*;
import com.intellij.lang.dtd.DTDLanguage;
import com.intellij.lang.dtd.DTDParserDefinition;
import com.intellij.lang.html.HTMLLanguage;
import com.intellij.lang.html.HTMLParserDefinition;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.lang.xml.XMLParserDefinition;
import com.intellij.lang.xml.XmlASTFactory;
import com.intellij.lexer.FilterLexer;
import com.intellij.lexer.HtmlEmbeddedTokenTypesProvider;
import com.intellij.lexer.Lexer;
import com.intellij.lexer.XmlLexer;
import com.intellij.openapi.application.Result;
@@ -29,6 +29,7 @@ import com.intellij.testFramework.ParsingTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.ThrowableRunnable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.File;
@@ -167,24 +168,28 @@ public class XmlParsingTest extends ParsingTestCase {
doTestXml(loadFile("manyErrors.xml"));
}
public void _testLexerPerformance1() throws Exception{
public void _testLexerPerformance1() throws Exception {
final String text = loadFile("pallada.xml");
XmlLexer lexer = new XmlLexer();
doLex(lexer, text);
final FilterLexer filterLexer = new FilterLexer(new XmlLexer(),
new FilterLexer.SetFilter(LanguageParserDefinitions.INSTANCE.forLanguage(XMLLanguage.INSTANCE).getWhitespaceTokens()));
new FilterLexer.SetFilter(
LanguageParserDefinitions.INSTANCE.forLanguage(XMLLanguage.INSTANCE)
.getWhitespaceTokens()));
doLex(filterLexer, text);
doLex(lexer, text);
doLex(filterLexer, text);
doLex(filterLexer, text);
}
public void _testLexerPerformance2() throws Exception{
public void _testLexerPerformance2() throws Exception {
final String text = loadFile("performance2.xml");
XmlLexer lexer = new XmlLexer();
doLex(lexer, text);
final FilterLexer filterLexer = new FilterLexer(new XmlLexer(),
new FilterLexer.SetFilter(LanguageParserDefinitions.INSTANCE.forLanguage(XMLLanguage.INSTANCE).getWhitespaceTokens()));
new FilterLexer.SetFilter(
LanguageParserDefinitions.INSTANCE.forLanguage(XMLLanguage.INSTANCE)
.getWhitespaceTokens()));
doLex(filterLexer, text);
doLex(lexer, text);
for (int i = 0; i < 20; i++) {
@@ -196,7 +201,7 @@ public class XmlParsingTest extends ParsingTestCase {
lexer.start(text);
long time = System.currentTimeMillis();
int count = 0;
while(lexer.getTokenType() != null){
while (lexer.getTokenType() != null) {
lexer.advance();
count++;
}
@@ -210,22 +215,22 @@ public class XmlParsingTest extends ParsingTestCase {
}
public void _testPerformance1() throws Exception{
public void _testPerformance1() throws Exception {
final String text = loadFile("pallada.xml");
long time = System.currentTimeMillis();
final PsiFile file = createFile("test.xml", text);
transformAllChildren(file.getNode());
System.out.println("Old parsing took " + (System.currentTimeMillis() - time) + "ms");
int index = 0;
while(index++ < 10){
while (index++ < 10) {
newParsing(text);
}
LeafElement firstLeaf = TreeUtil.findFirstLeaf(file.getNode());
index = 0;
do{
do {
index++;
}
while((firstLeaf = TreeUtil.nextLeaf(firstLeaf, null)) != null);
while ((firstLeaf = TreeUtil.nextLeaf(firstLeaf, null)) != null);
System.out.println("For " + index + " lexems");
}
@@ -237,7 +242,7 @@ public class XmlParsingTest extends ParsingTestCase {
System.gc();
System.gc();
new WriteCommandAction(getProject(), file) {
@Override
protected void run(final Result result) throws Throwable {
@@ -256,22 +261,22 @@ public class XmlParsingTest extends ParsingTestCase {
}.execute();
}
public void _testPerformance2() throws Exception{
public void _testPerformance2() throws Exception {
final String text = loadFile("performance2.xml");
long time = System.currentTimeMillis();
final PsiFile file = createFile("test.xml", text);
transformAllChildren(file.getNode());
System.out.println("Old parsing took " + (System.currentTimeMillis() - time) + "ms");
int index = 0;
while(index++ < 10){
while (index++ < 10) {
newParsing(text);
}
LeafElement firstLeaf = TreeUtil.findFirstLeaf(file.getNode());
index = 0;
do{
do {
index++;
}
while((firstLeaf = TreeUtil.nextLeaf(firstLeaf, null)) != null);
while ((firstLeaf = TreeUtil.nextLeaf(firstLeaf, null)) != null);
System.out.println("For " + index + " lexems");
}
@@ -644,5 +649,31 @@ public class XmlParsingTest extends ParsingTestCase {
doTestXml("<!DOCTYPE x3 [<!NOTATION data-sources SYSTEM \"x3\">]>");
}
public void testCustomMimeType() throws Exception {
final Language language = new MyLanguage();
addExplicitExtension(LanguageHtmlScriptContentProvider.INSTANCE, language, new HtmlScriptContentProvider() {
@Override
public IElementType getScriptElementType() {
return new IElementType("MyElementType", language);
}
@Nullable
@Override
public Lexer getHighlightingLexer() {
return null;
}
});
addExplicitExtension(LanguageParserDefinitions.INSTANCE, HTMLLanguage.INSTANCE, new HTMLParserDefinition());
addExplicitExtension(LanguageASTFactory.INSTANCE, HTMLLanguage.INSTANCE, new XmlASTFactory());
registerExtensionPoint(new ExtensionPointName<HtmlEmbeddedTokenTypesProvider>("com.intellij.html.embeddedTokenTypesProvider"),
HtmlEmbeddedTokenTypesProvider.class);
myLanguage = HTMLLanguage.INSTANCE;
doTest("<script type=\"application/custom\">Custom Script</script>", "test.html");
}
static class MyLanguage extends Language {
protected MyLanguage() {
super("MyLanguage", "application/custom");
}
}
}
@@ -0,0 +1,21 @@
HtmlFile:test.html
PsiElement(HTML_DOCUMENT)
PsiElement(XML_PROLOG)
<empty list>
HtmlTag:script
XmlToken:XML_START_TAG_START('<')
XmlToken:XML_NAME('script')
PsiWhiteSpace(' ')
PsiElement(XML_ATTRIBUTE)
XmlToken:XML_NAME('type')
XmlToken:XML_EQ('=')
PsiElement(XML_ATTRIBUTE_VALUE)
XmlToken:XML_ATTRIBUTE_VALUE_START_DELIMITER('"')
XmlToken:XML_ATTRIBUTE_VALUE_TOKEN('application/custom')
XmlToken:XML_ATTRIBUTE_VALUE_END_DELIMITER('"')
XmlToken:XML_TAG_END('>')
XmlText
PsiElement(MyElementType)('Custom Script')
XmlToken:XML_END_TAG_START('</')
XmlToken:XML_NAME('script')
XmlToken:XML_TAG_END('>')