From 6defec933bd29bdec665bcee97962b31099eaf7b Mon Sep 17 00:00:00 2001 From: Fedor Korotkov Date: Wed, 5 Dec 2012 11:35:23 +0400 Subject: [PATCH] HTML: mimeType support in the script tag. --- .../src/com/intellij/lang/Language.java | 36 +++++++++- .../src/META-INF/LangExtensionPoints.xml | 13 ++-- .../HtmlInlineScriptTokenTypesProvider.java | 25 +++++++ .../lang/HtmlScriptContentProvider.java | 33 +++++++++ ...ageHtmlInlineScriptTokenTypesProvider.java | 31 +++++++++ .../LanguageHtmlScriptContentProvider.java | 30 ++++++++ .../src/com/intellij/lexer/BaseHtmlLexer.java | 49 +++++++++++-- .../intellij/lexer/HtmlHighlightingLexer.java | 37 +++++++--- .../src/com/intellij/lexer/HtmlLexer.java | 18 ++--- .../intellij/codeInsight/XmlParsingTest.java | 69 ++++++++++++++----- xml/tests/testData/psi/testCustomMimeType.txt | 21 ++++++ 11 files changed, 315 insertions(+), 47 deletions(-) create mode 100644 xml/impl/src/com/intellij/lang/HtmlInlineScriptTokenTypesProvider.java create mode 100644 xml/impl/src/com/intellij/lang/HtmlScriptContentProvider.java create mode 100644 xml/impl/src/com/intellij/lang/LanguageHtmlInlineScriptTokenTypesProvider.java create mode 100644 xml/impl/src/com/intellij/lang/LanguageHtmlScriptContentProvider.java create mode 100644 xml/tests/testData/psi/testCustomMimeType.txt diff --git a/platform/core-api/src/com/intellij/lang/Language.java b/platform/core-api/src/com/intellij/lang/Language.java index ce492fe1a63e..21f961031f93 100644 --- a/platform/core-api/src/com/intellij/lang/Language.java +++ b/platform/core-api/src/com/intellij/lang/Language.java @@ -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, Language> ourRegisteredLanguages = Collections.synchronizedMap(new THashMap, Language>()); + private static final Map, Language> ourRegisteredLanguages = + Collections.synchronizedMap(new THashMap, Language>()); + private static final Map> ourRegisteredMimeTypes = + Collections.synchronizedMap(new THashMap>()); private static final Map ourRegisteredIDs = new THashMap(); private final Language myBaseLanguage; private final String myID; @@ -69,12 +73,28 @@ public abstract class Language extends UserDataHolderBase { Class 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 languagesByMimeType = ourRegisteredMimeTypes.get(mimeType); + if (languagesByMimeType == null) { + synchronized (ourRegisteredMimeTypes) { + languagesByMimeType = ourRegisteredMimeTypes.get(mimeType); + if (languagesByMimeType == null) { + languagesByMimeType = Collections.synchronizedList(new ArrayList()); + 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 mimeType. + */ + @NotNull + public static Collection findInstancesByMimeType(@Nullable String mimeType) { + List result = mimeType != null ? ourRegisteredMimeTypes.get(mimeType) : null; + return result != null ? Collections.unmodifiableCollection(result) : Collections.emptyList(); + } + public String toString() { //noinspection HardCodedStringLiteral diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index cd3494f4c2c2..ba68c2430b74 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -34,7 +34,7 @@ - + @@ -237,7 +237,7 @@ - + @@ -311,7 +311,7 @@ - + @@ -548,7 +548,7 @@ - + + + + diff --git a/xml/impl/src/com/intellij/lang/HtmlInlineScriptTokenTypesProvider.java b/xml/impl/src/com/intellij/lang/HtmlInlineScriptTokenTypesProvider.java new file mode 100644 index 000000000000..b72c2e7cf1f7 --- /dev/null +++ b/xml/impl/src/com/intellij/lang/HtmlInlineScriptTokenTypesProvider.java @@ -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(); +} diff --git a/xml/impl/src/com/intellij/lang/HtmlScriptContentProvider.java b/xml/impl/src/com/intellij/lang/HtmlScriptContentProvider.java new file mode 100644 index 000000000000..92bf64473fdb --- /dev/null +++ b/xml/impl/src/com/intellij/lang/HtmlScriptContentProvider.java @@ -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 com.intellij.psi.tree.IElementType to use in html script tag + */ + IElementType getScriptElementType(); + + /** + * @return highlighting lexer to use in html script tag + */ + @Nullable + Lexer getHighlightingLexer(); +} diff --git a/xml/impl/src/com/intellij/lang/LanguageHtmlInlineScriptTokenTypesProvider.java b/xml/impl/src/com/intellij/lang/LanguageHtmlInlineScriptTokenTypesProvider.java new file mode 100644 index 000000000000..8b8c5575dbc8 --- /dev/null +++ b/xml/impl/src/com/intellij/lang/LanguageHtmlInlineScriptTokenTypesProvider.java @@ -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 { + 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); + } +} diff --git a/xml/impl/src/com/intellij/lang/LanguageHtmlScriptContentProvider.java b/xml/impl/src/com/intellij/lang/LanguageHtmlScriptContentProvider.java new file mode 100644 index 000000000000..77676490e023 --- /dev/null +++ b/xml/impl/src/com/intellij/lang/LanguageHtmlScriptContentProvider.java @@ -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 { + 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); + } +} diff --git a/xml/impl/src/com/intellij/lexer/BaseHtmlLexer.java b/xml/impl/src/com/intellij/lexer/BaseHtmlLexer.java index 5580746f3c12..0a896be3922d 100644 --- a/xml/impl/src/com/intellij/lexer/BaseHtmlLexer.java +++ b/xml/impl/src/com/intellij/lexer/BaseHtmlLexer.java @@ -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 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; } } diff --git a/xml/impl/src/com/intellij/lexer/HtmlHighlightingLexer.java b/xml/impl/src/com/intellij/lexer/HtmlHighlightingLexer.java index df1134cecbc7..17d95dd8dadc 100644 --- a/xml/impl/src/com/intellij/lexer/HtmlHighlightingLexer.java +++ b/xml/impl/src/com/intellij/lexer/HtmlHighlightingLexer.java @@ -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; } diff --git a/xml/impl/src/com/intellij/lexer/HtmlLexer.java b/xml/impl/src/com/intellij/lexer/HtmlLexer.java index 753ce52fb90d..90b0e9af1bc1 100644 --- a/xml/impl/src/com/intellij/lexer/HtmlLexer.java +++ b/xml/impl/src/com/intellij/lexer/HtmlLexer.java @@ -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; - } } diff --git a/xml/tests/src/com/intellij/codeInsight/XmlParsingTest.java b/xml/tests/src/com/intellij/codeInsight/XmlParsingTest.java index 9c80b9ef90be..acb90d91a0ac 100644 --- a/xml/tests/src/com/intellij/codeInsight/XmlParsingTest.java +++ b/xml/tests/src/com/intellij/codeInsight/XmlParsingTest.java @@ -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("]>"); } + 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("com.intellij.html.embeddedTokenTypesProvider"), + HtmlEmbeddedTokenTypesProvider.class); + myLanguage = HTMLLanguage.INSTANCE; + doTest("", "test.html"); + } + + static class MyLanguage extends Language { + protected MyLanguage() { + super("MyLanguage", "application/custom"); + } + } } diff --git a/xml/tests/testData/psi/testCustomMimeType.txt b/xml/tests/testData/psi/testCustomMimeType.txt new file mode 100644 index 000000000000..e4f4e61ff7fa --- /dev/null +++ b/xml/tests/testData/psi/testCustomMimeType.txt @@ -0,0 +1,21 @@ +HtmlFile:test.html + PsiElement(HTML_DOCUMENT) + PsiElement(XML_PROLOG) + + 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('') \ No newline at end of file