diff --git a/openapi/src/com/intellij/psi/CustomHighlighterTokenType.java b/openapi/src/com/intellij/psi/CustomHighlighterTokenType.java index b530610139e9..821c5102f5c6 100644 --- a/openapi/src/com/intellij/psi/CustomHighlighterTokenType.java +++ b/openapi/src/com/intellij/psi/CustomHighlighterTokenType.java @@ -39,4 +39,5 @@ public interface CustomHighlighterTokenType { IElementType R_BRACKET = new CustomElementType("R_BRACKET"); IElementType L_PARENTH = new CustomElementType("L_PARENTH"); IElementType R_PARENTH = new CustomElementType("R_PARENTH"); + IElementType CUSTOM_CONTENT = new CustomElementType("CUSTOM_CONTENT"); } diff --git a/source/com/intellij/codeInsight/completion/SyntaxTableCompletionData.java b/source/com/intellij/codeInsight/completion/SyntaxTableCompletionData.java index 78bb1e011e4c..cb6cafbd16ea 100644 --- a/source/com/intellij/codeInsight/completion/SyntaxTableCompletionData.java +++ b/source/com/intellij/codeInsight/completion/SyntaxTableCompletionData.java @@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiPlainTextFile; import com.intellij.psi.PsiPlainText; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; @@ -28,6 +29,7 @@ public class SyntaxTableCompletionData extends WordCompletionData { final CompletionVariant variant = new CompletionVariant(TrueFilter.INSTANCE); variant.includeScopeClass(PsiPlainText.class, true); variant.includeScopeClass(XmlToken.class, true); // for embedding custom file types into xml + variant.includeScopeClass(LeafPsiElement.class, true); // for embedding custom file types into xml variant.addCompletionFilterOnElement(TrueFilter.INSTANCE); final String[] empty = {}; diff --git a/source/com/intellij/lexer/BaseHtmlLexer.java b/source/com/intellij/lexer/BaseHtmlLexer.java index cc50eedd2ba1..d29383b86805 100644 --- a/source/com/intellij/lexer/BaseHtmlLexer.java +++ b/source/com/intellij/lexer/BaseHtmlLexer.java @@ -138,9 +138,29 @@ abstract class BaseHtmlLexer implements Lexer { baseLexer.start(buffer, startOffset, endOffset, initialState & BASE_STATE_MASK); } + protected int skipToTheEndOfTheEmbeddment() { + int myTokenEnd = baseLexer.getTokenEnd(); + + if (seenTag) { + int lastState = 0; + int lastStart = 0; + while(baseLexer.getTokenType() != XmlTokenType.XML_END_TAG_START) { + lastState = baseLexer.getState(); + myTokenEnd = baseLexer.getTokenEnd(); + lastStart = baseLexer.getTokenStart(); + if (myTokenEnd == getBufferEnd()) break; + baseLexer.advance(); + } + + baseLexer.start(getBuffer(),lastStart,getBufferEnd(),lastState); + baseLexer.getTokenType(); + } + return myTokenEnd; + } + public void advance() { baseLexer.advance(); - IElementType type = getTokenType(); + IElementType type = baseLexer.getTokenType(); TokenHandler tokenHandler = tokenHandlers.get(type); if (tokenHandler!=null) tokenHandler.handleElement(this); } @@ -211,4 +231,8 @@ abstract class BaseHtmlLexer implements Lexer { } protected abstract boolean isHtmlTagState(int state); + + protected Lexer getBaseLexer() { + return baseLexer; + } } diff --git a/source/com/intellij/lexer/HtmlHighlightingLexer.java b/source/com/intellij/lexer/HtmlHighlightingLexer.java index 05eae1fe4fa3..adca4a387d5a 100644 --- a/source/com/intellij/lexer/HtmlHighlightingLexer.java +++ b/source/com/intellij/lexer/HtmlHighlightingLexer.java @@ -91,10 +91,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer { if (newLexer!=null) { embeddedLexer = newLexer; - embeddedLexer.start( - getBuffer(), - HtmlHighlightingLexer.super.getTokenStart(), - HtmlHighlightingLexer.super.getTokenEnd()); + embeddedLexer.start(getBuffer(),HtmlHighlightingLexer.super.getTokenStart(),skipToTheEndOfTheEmbeddment()); } } diff --git a/source/com/intellij/lexer/HtmlLexer.java b/source/com/intellij/lexer/HtmlLexer.java index 0604adcd955d..475d89d9b440 100644 --- a/source/com/intellij/lexer/HtmlLexer.java +++ b/source/com/intellij/lexer/HtmlLexer.java @@ -12,13 +12,14 @@ import com.intellij.psi.impl.source.tree.ElementType; * To change this template use File | Settings | File Templates. */ public class HtmlLexer extends BaseHtmlLexer { - private static IElementType styleElementType; - private static IElementType inlineStyleElementType; + private static IElementType ourStyleElementType; + private static IElementType ourInlineStyleElementType; + private static IElementType ourScriptElementType; + private static IElementType ourInlineScriptElementType; private IElementType myTokenType; private int myTokenStart; private int myTokenEnd; - private boolean mySkippingTokens; public void start(char[] buffer) { myTokenType = null; @@ -43,40 +44,41 @@ public class HtmlLexer extends BaseHtmlLexer { public IElementType getTokenType() { if (myTokenType!=null) return myTokenType; IElementType tokenType = super.getTokenType(); - if (mySkippingTokens) return tokenType; myTokenStart = super.getTokenStart(); myTokenEnd = super.getTokenEnd(); - if (hasSeenStyle() && hasSeenTag() && styleElementType!=null && - (tokenType == XmlTokenType.XML_DATA_CHARACTERS || - tokenType == XmlTokenType.XML_COMMENT_START || - tokenType == ElementType.WHITE_SPACE - )) { - assert hasSeenTag(); - - mySkippingTokens = true; - // we need to advance till the end of tag - int lastState = 0; - int lastStart = 0; - while(hasSeenStyle()) { - lastState = super.getState(); - myTokenEnd = super.getTokenEnd(); - lastStart = super.getTokenStart(); - if (myTokenEnd == getBufferEnd()) break; - super.advance(); + if (hasSeenStyle()) { + if (hasSeenTag() && ourStyleElementType!=null && isStartOfEmbeddmentTagContent(tokenType)) { + myTokenEnd = skipToTheEndOfTheEmbeddment(); + tokenType = ourStyleElementType; + } else if (ourInlineStyleElementType!=null && isStartOfEmbeddmentAttributeValue(tokenType) && hasSeenAttribute()) { + tokenType = ourInlineStyleElementType; + } + } else if (hasSeenScript()) { + if (hasSeenTag() && ourScriptElementType!=null && isStartOfEmbeddmentTagContent(tokenType)) { + myTokenEnd = skipToTheEndOfTheEmbeddment(); + tokenType = ourScriptElementType; + } else if (hasSeenAttribute() && isStartOfEmbeddmentAttributeValue(tokenType) && ourInlineScriptElementType!=null) { + myTokenEnd = skipToTheEndOfTheEmbeddment(); + tokenType = ourInlineScriptElementType; } - - super.start(getBuffer(),lastStart,getBufferEnd(),lastState); - super.getTokenType(); - mySkippingTokens = false; - tokenType = styleElementType; - } else if (inlineStyleElementType!=null && tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN && hasSeenStyle() && hasSeenAttribute()) { - tokenType = inlineStyleElementType; } + return myTokenType = tokenType; } + private boolean isStartOfEmbeddmentAttributeValue(final IElementType tokenType) { + return tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN; + } + + private boolean isStartOfEmbeddmentTagContent(final IElementType tokenType) { + return (tokenType == XmlTokenType.XML_DATA_CHARACTERS || + tokenType == XmlTokenType.XML_COMMENT_START || + tokenType == ElementType.WHITE_SPACE + ); + } + public HtmlLexer() { this(new _HtmlLexer(),true); } @@ -86,8 +88,8 @@ public class HtmlLexer extends BaseHtmlLexer { } public static final void setStyleElementTypes(IElementType _styleElementType,IElementType _inlineStyleElementType) { - styleElementType = _styleElementType; - inlineStyleElementType = _inlineStyleElementType; + ourStyleElementType = _styleElementType; + ourInlineStyleElementType = _inlineStyleElementType; } protected boolean isHtmlTagState(int state) { @@ -107,4 +109,9 @@ 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/source/com/intellij/psi/impl/source/parsing/ParseUtil.java b/source/com/intellij/psi/impl/source/parsing/ParseUtil.java index cefa063d9dc2..100ef6ab9ddb 100644 --- a/source/com/intellij/psi/impl/source/parsing/ParseUtil.java +++ b/source/com/intellij/psi/impl/source/parsing/ParseUtil.java @@ -106,6 +106,38 @@ public class ParseUtil implements Constants { boolean isTokenValid(IElementType tokenType); } + public static abstract class DefaultWhiteSpaceTokenProcessorImpl implements TokenProcessor { + public boolean isTokenValid(IElementType tokenType) { + return tokenType != null && isInSet(tokenType); + } + + public TreeElement process(Lexer lexer, ParsingContext context) { + TreeElement first = null; + TreeElement last = null; + while (isTokenValid(lexer.getTokenType())) { + TreeElement tokenElement = ParseUtil.createTokenElement(lexer, context.getCharTable()); + IElementType type = lexer.getTokenType(); + + if (!isInSet(type)) { + LOG.error("Missed token should be white space or comment:" + tokenElement); + throw new RuntimeException(); + } + if (last != null) { + last.setTreeNext(tokenElement); + tokenElement.setTreePrev(last); + last = tokenElement; + } + else { + first = last = tokenElement; + } + lexer.advance(); + } + return first; + } + + protected abstract boolean isInSet(final IElementType type); + } + public static class WhiteSpaceAndCommentsProcessor implements TokenProcessor { public static final TokenProcessor INSTANCE = new WhiteSpaceAndCommentsProcessor(); diff --git a/source/com/intellij/psi/impl/source/tree/Factory.java b/source/com/intellij/psi/impl/source/tree/Factory.java index 5703bd3579b2..be655ec61840 100644 --- a/source/com/intellij/psi/impl/source/tree/Factory.java +++ b/source/com/intellij/psi/impl/source/tree/Factory.java @@ -4,6 +4,7 @@ import com.intellij.aspects.psi.IAspectElementType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.JavaDocTokenType; import com.intellij.psi.PsiManager; +import com.intellij.psi.CustomHighlighterTokenType; import com.intellij.psi.impl.source.*; import com.intellij.psi.impl.source.html.HtmlDocumentImpl; import com.intellij.psi.impl.source.html.HtmlTagImpl; @@ -517,6 +518,8 @@ public class Factory implements Constants { } else if (type == ANNOTATION_PARAMETER_LIST) { element = new PsiAnnotationParameterListImpl(); + } else if (type == CustomHighlighterTokenType.CUSTOM_CONTENT) { + element = new CompositePsiElement(type) {}; } else { if (type instanceof IAspectElementType) {