mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
parsing of JS in HTML
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user