diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyLiteralSelectioner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyLiteralSelectioner.java index 8771c7d6b6ff..3ee29f9cf451 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyLiteralSelectioner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyLiteralSelectioner.java @@ -23,6 +23,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrRegex; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; import java.util.List; @@ -39,30 +40,29 @@ public class GroovyLiteralSelectioner extends GroovyBasicSelectioner { } private static boolean isLiteral(PsiElement element) { - if (element instanceof GrListOrMap) { - return true; - } + if (element instanceof GrListOrMap) return true; if (!(element instanceof GrLiteral)) return false; + if (element instanceof GrRegex && ((GrRegex)element).getInjections().length == 0) return true; + ASTNode node = element.getNode(); if (node == null) return false; ASTNode firstNode = node.getFirstChildNode(); final IElementType type = firstNode.getElementType(); - return firstNode == node.getLastChildNode() && (type == mSTRING_LITERAL || type == mGSTRING_LITERAL || type == mREGEX_LITERAL); + return firstNode == node.getLastChildNode() && (type == mSTRING_LITERAL || type == mGSTRING_LITERAL); } public List select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { List result = super.select(e, editorText, cursorOffset, editor); - if (e instanceof GrListOrMap) { - return result; - } + if (e instanceof GrListOrMap) return result; int startOffset = -1; int endOffset = -1; final String text = e.getText(); final int stringOffset = e.getTextOffset(); - if (e.getNode().getElementType() == mGSTRING_CONTENT) { + final IElementType elementType = e.getNode().getElementType(); + if (elementType == mGSTRING_CONTENT || elementType == mREGEX_CONTENT || elementType == mDOLLAR_SLASH_REGEX_CONTENT) { int cur; int index = -1; while (true) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyWordSelectionFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyWordSelectionFilter.java index a37e1a998e2e..a9e0530ebbe1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyWordSelectionFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/selection/GroovyWordSelectionFilter.java @@ -46,7 +46,10 @@ public class GroovyWordSelectionFilter implements Condition { type == mGDOC_TAG_VALUE_TOKEN || type == mREGEX_BEGIN || type == mREGEX_CONTENT || - type == mREGEX_END) { + type == mREGEX_END || + type == mDOLLAR_SLASH_REGEX_BEGIN || + type == mDOLLAR_SLASH_REGEX_CONTENT || + type == mDOLLAR_SLASH_REGEX_END) { return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java index ff566957102b..4fe8253617cd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java @@ -49,8 +49,6 @@ public class DefaultHighlighter { @NonNls static final String STRING_ID = "String"; @NonNls - static final String REGEXP_ID = "Regular expression"; - @NonNls static final String BRACES_ID = "Braces"; @NonNls static final String BRACKETS_ID = "Brackets"; @@ -150,9 +148,6 @@ public class DefaultHighlighter { public static TextAttributesKey STRING = TextAttributesKey.createTextAttributesKey(STRING_ID, SyntaxHighlighterColors.STRING.getDefaultAttributes()); - public static TextAttributesKey REGEXP = TextAttributesKey.createTextAttributesKey(REGEXP_ID, - SyntaxHighlighterColors.VALID_STRING_ESCAPE.getDefaultAttributes()); - public static TextAttributesKey BRACES = TextAttributesKey.createTextAttributesKey(BRACES_ID, SyntaxHighlighterColors.BRACES.getDefaultAttributes()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyBraceMatcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyBraceMatcher.java index afb6fb98d793..b00587a4cc70 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyBraceMatcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyBraceMatcher.java @@ -19,14 +19,18 @@ package org.jetbrains.plugins.groovy.highlighter; import com.intellij.lang.BracePair; import com.intellij.lang.PairedBraceMatcher; import com.intellij.psi.PsiFile; -import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; + +import static com.intellij.psi.TokenType.WHITE_SPACE; +import static org.jetbrains.plugins.groovy.GroovyFileType.GROOVY_LANGUAGE; +import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_INLINE_TAG_END; +import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_INLINE_TAG_START; +import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_TAG_VALUE_LPAREN; +import static org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes.mGDOC_TAG_VALUE_RPAREN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.COMMENT_SET; /** * Brace matcher for Groovy language @@ -36,32 +40,35 @@ import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; public class GroovyBraceMatcher implements PairedBraceMatcher { private static final BracePair[] PAIRS = { - new BracePair(GroovyTokenTypes.mLPAREN, GroovyTokenTypes.mRPAREN, false), - new BracePair(GroovyTokenTypes.mLBRACK, GroovyTokenTypes.mRBRACK, false), - new BracePair(GroovyTokenTypes.mLCURLY, GroovyTokenTypes.mRCURLY, true), + new BracePair(mLPAREN, mRPAREN, false), + new BracePair(mLBRACK, mRBRACK, false), + new BracePair(mLCURLY, mRCURLY, true), - new BracePair(GroovyDocTokenTypes.mGDOC_INLINE_TAG_START, GroovyDocTokenTypes.mGDOC_INLINE_TAG_END, true), - new BracePair(GroovyDocTokenTypes.mGDOC_TAG_VALUE_LPAREN, GroovyDocTokenTypes.mGDOC_TAG_VALUE_RPAREN, false), + new BracePair(mGDOC_INLINE_TAG_START, mGDOC_INLINE_TAG_END, true), + new BracePair(mGDOC_TAG_VALUE_LPAREN, mGDOC_TAG_VALUE_RPAREN, false), - new BracePair(GroovyTokenTypes.mGSTRING_BEGIN, GroovyTokenTypes.mGSTRING_END, false), - new BracePair(GroovyTokenTypes.mREGEX_BEGIN, GroovyTokenTypes.mREGEX_END, false) + new BracePair(mGSTRING_BEGIN, mGSTRING_END, false), + new BracePair(mREGEX_BEGIN, mREGEX_END, false), + new BracePair(mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_END, false), }; public BracePair[] getPairs() { return PAIRS; } - public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType ibraceType, @Nullable IElementType tokenType) { + public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType braceType, @Nullable IElementType tokenType) { return tokenType == null - || TokenType.WHITE_SPACE == tokenType - || TokenSets.COMMENT_SET.contains(tokenType) - || tokenType == GroovyTokenTypes.mSEMI - || tokenType == GroovyTokenTypes.mCOMMA - || tokenType == GroovyTokenTypes.mRPAREN - || tokenType == GroovyTokenTypes.mRBRACK - || tokenType == GroovyTokenTypes.mRCURLY - || tokenType == GroovyTokenTypes.mGSTRING_BEGIN - || tokenType.getLanguage() != GroovyFileType.GROOVY_LANGUAGE; + || tokenType == WHITE_SPACE + || tokenType == mSEMI + || tokenType == mCOMMA + || tokenType == mRPAREN + || tokenType == mRBRACK + || tokenType == mRCURLY + || tokenType == mGSTRING_BEGIN + || tokenType == mREGEX_BEGIN + || tokenType == mDOLLAR_SLASH_REGEX_BEGIN + || COMMENT_SET.contains(tokenType) + || tokenType.getLanguage() != GROOVY_LANGUAGE; } public int getCodeConstructStart(PsiFile file, int openingBraceOffset) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java index 358a9c072016..bd6bbb63d9ab 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java @@ -58,7 +58,6 @@ public class GroovyColorsAndFontsPage implements ColorSettingsPage { new AttributesDescriptor("Number", DefaultHighlighter.NUMBER), new AttributesDescriptor("GString", DefaultHighlighter.GSTRING), new AttributesDescriptor("String", DefaultHighlighter.STRING), - new AttributesDescriptor("Regular expression", DefaultHighlighter.REGEXP), new AttributesDescriptor("Braces", DefaultHighlighter.BRACES), new AttributesDescriptor("Brackets", DefaultHighlighter.BRACKETS), new AttributesDescriptor("Parentheses", DefaultHighlighter.PARENTHESES), diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySlashyStringLexer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySlashyStringLexer.java new file mode 100644 index 000000000000..82ef61fa447b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySlashyStringLexer.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2011 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 org.jetbrains.plugins.groovy.highlighter; + +import com.intellij.lexer.LexerBase; +import com.intellij.psi.StringEscapesTokenTypes; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; + +/** + * @author Max Medvedev + */ +public class GroovySlashyStringLexer extends LexerBase { + private CharSequence myBuffer; + private int myStart; + private int myBufferEnd; + private IElementType myTokenType; + private int myEnd; + + + public GroovySlashyStringLexer() { + } + + @Override + public void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { + myBuffer = buffer; + myEnd = startOffset; + myBufferEnd = endOffset; + myTokenType = locateToken(); + } + + @Nullable + private IElementType locateToken() { + if (myEnd >= myBufferEnd) return null; + + myStart = myEnd; + if (checkForEscape(myStart)) { + myEnd = myStart + 2; + return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; + } + + while (myEnd < myBufferEnd && !checkForEscape(myEnd)) myEnd++; + return GroovyTokenTypes.mREGEX_CONTENT; + } + + private boolean checkForEscape(int start) { + return myBuffer.charAt(start) == '\\' && start + 1 < myBufferEnd && myBuffer.charAt(start + 1) == '/'; + } + + @Override + public int getState() { + return 0; + } + + @Override + public IElementType getTokenType() { + return myTokenType; + } + + @Override + public int getTokenStart() { + return myStart; + } + + @Override + public int getTokenEnd() { + return myEnd; + } + + @Override + public void advance() { + myTokenType = locateToken(); + } + + @Override + public CharSequence getBufferSequence() { + return myBuffer; + } + + @Override + public int getBufferEnd() { + return myBufferEnd; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySyntaxHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySyntaxHighlighter.java index fea08fc87d88..98c94e263715 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySyntaxHighlighter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovySyntaxHighlighter.java @@ -62,10 +62,6 @@ public class GroovySyntaxHighlighter extends SyntaxHighlighterBase implements Gr mWRONG ); - static final TokenSet tWRONG_REGEX = TokenSet.create( - mWRONG_REGEX_LITERAL - ); - static final TokenSet tGSTRINGS = TokenSet.create( mGSTRING_BEGIN, mGSTRING_CONTENT, @@ -77,15 +73,6 @@ public class GroovySyntaxHighlighter extends SyntaxHighlighterBase implements Gr mSTRING_LITERAL ); - static final TokenSet tREGEXP = TokenSet.create( - mREGEX_LITERAL, - - mREGEX_BEGIN, - mREGEX_CONTENT, - mREGEX_END - - ); - static final TokenSet tBRACES = TokenSet.create( mLCURLY, mRCURLY @@ -210,8 +197,7 @@ public class GroovySyntaxHighlighter extends SyntaxHighlighterBase implements Gr fillMap(ATTRIBUTES, tNUMBERS, DefaultHighlighter.NUMBER); fillMap(ATTRIBUTES, tGSTRINGS, DefaultHighlighter.GSTRING); fillMap(ATTRIBUTES, tSTRINGS, DefaultHighlighter.STRING); - fillMap(ATTRIBUTES, tREGEXP, DefaultHighlighter.REGEXP); - fillMap(ATTRIBUTES, tWRONG_REGEX, DefaultHighlighter.REGEXP); + fillMap(ATTRIBUTES, DefaultHighlighter.STRING, mREGEX_BEGIN, mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END); fillMap(ATTRIBUTES, tBRACES, DefaultHighlighter.BRACES); fillMap(ATTRIBUTES, tBRACKETS, DefaultHighlighter.BRACKETS); fillMap(ATTRIBUTES, tPARENTHESES, DefaultHighlighter.PARENTHESES); @@ -234,6 +220,8 @@ public class GroovySyntaxHighlighter extends SyntaxHighlighterBase implements Gr new IElementType[]{GroovyTokenTypes.mGSTRING_LITERAL}, IElementType.EMPTY_ARRAY); registerSelfStoppingLayer(new StringLiteralLexer(StringLiteralLexer.NO_QUOTE_CHAR, GroovyTokenTypes.mGSTRING_CONTENT, true, "$"), new IElementType[]{GroovyTokenTypes.mGSTRING_CONTENT}, IElementType.EMPTY_ARRAY); + registerSelfStoppingLayer(new GroovySlashyStringLexer(), new IElementType[]{GroovyTokenTypes.mREGEX_CONTENT}, + IElementType.EMPTY_ARRAY); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java index 015a357c4cdf..db50abfabe87 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java @@ -111,10 +111,7 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce protected String escapeCharCharacters(@NotNull String s, @NotNull PsiElement token, boolean escapeSlashes) { IElementType tokenType = token.getNode().getElementType(); - if (tokenType == mREGEX_CONTENT || - tokenType == mREGEX_LITERAL || - tokenType == mDOLLAR_SLASH_REGEX_CONTENT || - tokenType == mDOLLAR_SLASH_REGEX_LITERAL) { + if (tokenType == mREGEX_CONTENT || tokenType == mDOLLAR_SLASH_REGEX_CONTENT) { if (escapeSlashes) { return StringUtil.escapeSlashes(s); } @@ -149,10 +146,7 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce protected String unescape(String text, PsiElement token) { final IElementType tokenType = token.getNode().getElementType(); - if (tokenType == mREGEX_CONTENT || - tokenType == mREGEX_LITERAL || - tokenType == mDOLLAR_SLASH_REGEX_CONTENT || - tokenType == mDOLLAR_SLASH_REGEX_LITERAL) { + if (tokenType == mREGEX_CONTENT || tokenType == mDOLLAR_SLASH_REGEX_CONTENT) { return StringUtil.unescapeSlashes(text); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/GroovyTokenTypes.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/GroovyTokenTypes.java index 79abfd2f091a..65489558aed4 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/GroovyTokenTypes.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/GroovyTokenTypes.java @@ -73,9 +73,6 @@ public interface GroovyTokenTypes extends GroovyDocElementTypes { IElementType mGSTRING_CONTENT = new GroovyElementType("Gstring content"); IElementType mGSTRING_END = new GroovyElementType("Gstring end"); - IElementType mREGEX_LITERAL = new GroovyElementType("regexp"); - IElementType mDOLLAR_SLASH_REGEX_LITERAL = new GroovyElementType("$/ regexp"); - IElementType mREGEX_BEGIN = new GroovyElementType("regex begin"); IElementType mREGEX_CONTENT = new GroovyElementType("regex content"); IElementType mREGEX_END = new GroovyElementType("regex end"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java index 93710d76d299..623b870704e7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java @@ -68,9 +68,7 @@ public abstract class TokenSets { kFALSE, kNULL, mSTRING_LITERAL, - mGSTRING_LITERAL, - mREGEX_LITERAL, - mDOLLAR_SLASH_REGEX_LITERAL + mGSTRING_LITERAL ); public static final TokenSet BUILT_IN_TYPE = TokenSet.create( @@ -123,10 +121,8 @@ public abstract class TokenSets { public static TokenSet STRING_LITERALS = TokenSet.create( mSTRING_LITERAL, - mREGEX_LITERAL, mREGEX_CONTENT, mDOLLAR_SLASH_REGEX_CONTENT, - mDOLLAR_SLASH_REGEX_LITERAL, mGSTRING_LITERAL, mGSTRING_CONTENT, mGSTRING_BEGIN,