diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java index 1ae7a5e18634..3272fd5d8b92 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovyIndentProcessor.java @@ -22,10 +22,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.formatter.GroovyBlock; -import org.jetbrains.plugins.groovy.lang.editor.actions.GroovyEditorActionUtil; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocTag; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -50,6 +50,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe */ public abstract class GroovyIndentProcessor implements GroovyElementTypes { public static final int GDOC_COMMENT_INDENT = 1; + private static TokenSet GSTRING_TOKENS_INNER = TokenSet.create(mGSTRING_BEGIN,mGSTRING_CONTENT,mGSTRING_END,mDOLLAR); /** * Calculates indent, based on code style, between parent block and child node @@ -72,14 +73,12 @@ public abstract class GroovyIndentProcessor implements GroovyElementTypes { return Indent.getContinuationIndent(); } - if (GroovyEditorActionUtil.GSTRING_TOKENS_INNER.contains(child.getElementType()) && - mGSTRING_BEGIN != child.getElementType()) { + if (GSTRING_TOKENS_INNER.contains(child.getElementType()) && mGSTRING_BEGIN != child.getElementType()) { return Indent.getAbsoluteNoneIndent(); } if (psiParent instanceof GrListOrMap) { - if (mLBRACK.equals(child.getElementType()) || - mRBRACK.equals(child.getElementType())) { + if (mLBRACK.equals(child.getElementType()) || mRBRACK.equals(child.getElementType())) { return Indent.getNoneIndent(); } else { return Indent.getContinuationWithoutFirstIndent(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java index 0af2055bc353..9cb94a190826 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEditorActionUtil.java @@ -23,12 +23,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.tree.TokenSet; import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSTRING_LITERAL; + /** * @author ilyas */ @@ -66,7 +67,7 @@ public class GroovyEditorActionUtil { if (child != null && child.getNode() != null) { ASTNode node = child.getNode(); assert node != null; - return node.getElementType() == GroovyTokenTypes.mSTRING_LITERAL; + return node.getElementType() == mSTRING_LITERAL; } return false; } @@ -76,23 +77,8 @@ public class GroovyEditorActionUtil { if (child != null && child.getNode() != null) { ASTNode node = child.getNode(); assert node != null; - return node.getElementType() == GroovyTokenTypes.mGSTRING_LITERAL; + return node.getElementType() == mGSTRING_LITERAL; } return false; } - - public static TokenSet GSTRING_TOKENS = TokenSet.create( - GroovyTokenTypes.mGSTRING_BEGIN, - GroovyTokenTypes.mGSTRING_CONTENT, - GroovyTokenTypes.mGSTRING_END, - GroovyTokenTypes.mGSTRING_LITERAL, - GroovyTokenTypes.mDOLLAR - ); - - public static TokenSet GSTRING_TOKENS_INNER = TokenSet.create( - GroovyTokenTypes.mGSTRING_BEGIN, - GroovyTokenTypes.mGSTRING_CONTENT, - GroovyTokenTypes.mGSTRING_END, - GroovyTokenTypes.mDOLLAR - ); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java index b7df458df553..d615a8774470 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java @@ -50,13 +50,64 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringInjection; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCLOSABLE_BLOCK_OP; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mGSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mIDENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLBRACK; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLCURLY; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mNLS; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mRBRACK; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mRCURLY; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_BEGIN; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_CONTENT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_END; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mREGEX_LITERAL; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSTRING_LITERAL; +import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*; /** * @author ilyas */ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { + private static final TokenSet GSTRING_TOKENS = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mGSTRING_END, mGSTRING_LITERAL); + + private static final TokenSet REGEX_TOKENS = TokenSet.create(mREGEX_BEGIN, mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, + mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END); + + private static final TokenSet AFTER_DOLLAR = TokenSet.create(mLCURLY, mIDENT, mGSTRING_CONTENT, mDOLLAR, mGSTRING_END, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_END); + + private static final TokenSet ALL_STRINGS = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_BEGIN, mGSTRING_END, + mGSTRING_CONTENT, mRCURLY, mIDENT, mDOLLAR, mREGEX_BEGIN, mREGEX_CONTENT, + mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT, + mDOLLAR_SLASH_REGEX_END, mREGEX_LITERAL, mDOLLAR_SLASH_REGEX_LITERAL); + + private static final TokenSet BEFORE_DOLLAR =TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mREGEX_BEGIN, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT); + + private static final TokenSet EXPR_END = TokenSet.create(mRCURLY, mIDENT); + + private static final TokenSet AFTER_EXPR_END = TokenSet.create(mGSTRING_END, mGSTRING_CONTENT, mDOLLAR, mREGEX_END, mREGEX_CONTENT, + mDOLLAR_SLASH_REGEX_END, mDOLLAR_SLASH_REGEX_CONTENT); + + private static final TokenSet STRING_END = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_END, mREGEX_END, + mDOLLAR_SLASH_REGEX_END, mREGEX_LITERAL, mDOLLAR_SLASH_REGEX_LITERAL); + + private static final TokenSet INNER_STRING_TOKENS = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT, mGSTRING_END, mREGEX_BEGIN, + mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, + mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END, + GSTRING_INJECTION); + + public Result preprocessEnter(@NotNull PsiFile file, @NotNull Editor editor, @NotNull Ref caretOffset, @@ -204,22 +255,6 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { return false; } - private static final TokenSet AFTER_DOLLAR = TokenSet.create(mLCURLY, mIDENT, mGSTRING_CONTENT, mDOLLAR, mGSTRING_END); - - private static final TokenSet ALL_STRINGS = TokenSet - .create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_BEGIN, mGSTRING_END, mGSTRING_CONTENT, mRCURLY, mIDENT, mDOLLAR, mREGEX_BEGIN, - mREGEX_CONTENT, mREGEX_END, mDOLLAR_SLASH_REGEX_BEGIN, mDOLLAR_SLASH_REGEX_CONTENT, mDOLLAR_SLASH_REGEX_END, mREGEX_LITERAL, - mDOLLAR_SLASH_REGEX_LITERAL); - - private static final TokenSet BEFORE_DOLLAR = TokenSet.create(mGSTRING_BEGIN, mGSTRING_CONTENT); - - private static final TokenSet EXPR_END = TokenSet.create(mRCURLY, mIDENT); - - private static final TokenSet AFTER_EXPR_END = TokenSet.create(mGSTRING_END, mGSTRING_CONTENT, mDOLLAR); - - private static final TokenSet STRING_END = TokenSet.create(mSTRING_LITERAL, mGSTRING_LITERAL, mGSTRING_END); - - private static boolean handleInString(Editor editor, int caretOffset, DataContext dataContext, EditorActionHandler originalHandler) { Project project = PlatformDataKeys.PROJECT.getData(dataContext); if (project == null) return false; @@ -241,6 +276,16 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { ASTNode node = stringElement.getNode(); if (node == null) return false; + // For expression injection in GString like "abc ${} abc" + if (!INNER_STRING_TOKENS.contains(node.getElementType()) && checkGStringInjection(stringElement)) { + stringElement = stringElement.getParent().getParent().getNextSibling(); + if (stringElement == null) return false; + node = stringElement.getNode(); + if (node == null) return false; + } + + boolean isInsertIndent = isInsertIndent(caretOffset, stringElement.getTextRange().getStartOffset(), fileText); + // For simple String literals like 'abcdef' if (mSTRING_LITERAL == node.getElementType()) { if (GroovyEditorActionUtil.isPlainStringLiteral(node)) { @@ -258,20 +303,13 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { EditorModificationUtil.insertStringAtCaret(editor, "\n"); } else { - originalHandler.execute(editor, dataContext); + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); } return true; } - // For expression injection in GString like "abc ${} abc" - if (!GroovyEditorActionUtil.GSTRING_TOKENS.contains(node.getElementType()) && checkGStringInnerExpression(stringElement)) { - stringElement = stringElement.getParent().getParent().getNextSibling(); - if (stringElement == null) return false; - node = stringElement.getNode(); - if (node == null) return false; - } - - if (GroovyEditorActionUtil.GSTRING_TOKENS.contains(node.getElementType())) { + if (GSTRING_TOKENS.contains(node.getElementType()) || + node.getElementType() == mDOLLAR && node.getTreeParent().getTreeParent().getElementType() == GSTRING) { PsiElement parent = stringElement.getParent(); if (node.getElementType() == mGSTRING_LITERAL) { parent = stringElement; @@ -296,13 +334,55 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { } } else { - originalHandler.execute(editor, dataContext); + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); } return true; } + + if (REGEX_TOKENS.contains(node.getElementType()) || + node.getElementType() == mDOLLAR && node.getTreeParent().getTreeParent().getElementType() == REGEX) { + PsiElement parent = stringElement.getParent(); + if (node.getElementType() == mREGEX_LITERAL || node.getElementType() == mDOLLAR_SLASH_REGEX_LITERAL) { + parent = stringElement; + } + else { + while (parent != null && !(parent instanceof GrLiteral)) { + parent = parent.getParent(); + } + } + if (parent == null || parent.getLastChild() instanceof PsiErrorElement) return false; + PsiElement exprSibling = stringElement.getNextSibling(); + boolean rightFromDollar = exprSibling instanceof GrExpression && exprSibling.getTextRange().getStartOffset() == caretOffset; + if (rightFromDollar) { + editor.getCaretModel().moveToOffset(caretOffset - 1); + } + insertLineFeedInString(editor, dataContext, originalHandler, isInsertIndent); + if (rightFromDollar) { + editor.getCaretModel().moveCaretRelatively(1, 0, false, false, true); + } + return true; + } + return false; } + private static void insertLineFeedInString(Editor editor, + DataContext dataContext, + EditorActionHandler originalHandler, + boolean isInsertIndent) { + if (isInsertIndent) { + originalHandler.execute(editor, dataContext); + } + else { + EditorModificationUtil.insertStringAtCaret(editor, "\n"); + } + } + + private static boolean isInsertIndent(int caret, int stringOffset, String text) { + final int i = text.indexOf('\n', stringOffset); + return stringOffset < i && i < caret; + } + private static void convertEndToMultiline(int caretOffset, Document document, String fileText) { if (caretOffset < fileText.length() && fileText.charAt(caretOffset) == '\'' || caretOffset > 0 && fileText.charAt(caretOffset - 1) == '\'') { @@ -339,13 +419,13 @@ public class GroovyEnterHandler extends EnterHandlerDelegateAdapter { return true; } - private static boolean checkGStringInnerExpression(PsiElement element) { + private static boolean checkGStringInjection(PsiElement element) { if (element != null && (element.getParent() instanceof GrReferenceExpression || element.getParent() instanceof GrClosableBlock)) { final PsiElement parent = element.getParent().getParent(); if (!(parent instanceof GrStringInjection)) return false; PsiElement nextSibling = parent.getNextSibling(); if (nextSibling == null) return false; - return GroovyEditorActionUtil.GSTRING_TOKENS_INNER.contains(nextSibling.getNode().getElementType()); + return INNER_STRING_TOKENS.contains(nextSibling.getNode().getElementType()); } return false; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy index f6ac881554e1..7403202ad786 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy @@ -81,6 +81,7 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testGstring8() throws Throwable { doTest(); } public void testGstring9() throws Throwable { doTest(); } public void testMultilineIndent() throws Throwable { doTest(); } + public void testMultilineIndent2() throws Throwable { doTest(); } public void testSpaces1() throws Throwable { doTest(); } public void testString1() throws Throwable { doTest(); } public void testString2() throws Throwable { doTest(); } @@ -92,6 +93,16 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testString8() throws Throwable { doTest(); } public void testString9() throws Throwable { doTest(); } public void testString10() throws Throwable { doTest(); } + public void testRegex1() {doTest()} + public void testRegex2() {doTest()} + public void testRegex3() {doTest()} + public void testRegex4() {doTest()} + public void testRegex5() {doTest()} + public void testRegex6() {doTest()} + public void testRegex7() {doTest()} + public void testRegex8() {doTest()} + public void testRegex9() {doTest()} + public void testRegex10() {doTest()} def doTest(String before, String after) { myFixture.configureByText("a.groovy", before) diff --git a/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test b/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test new file mode 100644 index 000000000000..e4504d8a5828 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/multilineIndent2.test @@ -0,0 +1,16 @@ +def foo() { + ''' +class Foo { + void foo() {} +} +''' +} +----- +def foo() { + ''' + +class Foo { + void foo() {} +} +''' +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex1.test b/plugins/groovy/testdata/groovy/enterAction/regex1.test new file mode 100644 index 000000000000..ce149fef825a --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex1.test @@ -0,0 +1,8 @@ +cl { + /abc/ +} +----- +cl { + /a +bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex10.test b/plugins/groovy/testdata/groovy/enterAction/regex10.test new file mode 100644 index 000000000000..20bd1f184d11 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex10.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a +${}bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex2.test b/plugins/groovy/testdata/groovy/enterAction/regex2.test new file mode 100644 index 000000000000..582ae04d4943 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex2.test @@ -0,0 +1,10 @@ +cl { + /a + bbc/ +} +----- +cl { + /a + b + bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex3.test b/plugins/groovy/testdata/groovy/enterAction/regex3.test new file mode 100644 index 000000000000..8229dff4652c --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex3.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a${} +bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex4.test b/plugins/groovy/testdata/groovy/enterAction/regex4.test new file mode 100644 index 000000000000..639854265834 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex4.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a +${}bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex5.test b/plugins/groovy/testdata/groovy/enterAction/regex5.test new file mode 100644 index 000000000000..858a5220a76c --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex5.test @@ -0,0 +1,8 @@ +cl { + /a${}bc/ +} +----- +cl { + /a +${}bc/ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex6.test b/plugins/groovy/testdata/groovy/enterAction/regex6.test new file mode 100644 index 000000000000..cc1d0448e268 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex6.test @@ -0,0 +1,8 @@ +cl { + $/abc/$ +} +----- +cl { + $/a +bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex7.test b/plugins/groovy/testdata/groovy/enterAction/regex7.test new file mode 100644 index 000000000000..5697e7e7a742 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex7.test @@ -0,0 +1,10 @@ +cl { + $/a + bbc/$ +} +----- +cl { + $/a + b + bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex8.test b/plugins/groovy/testdata/groovy/enterAction/regex8.test new file mode 100644 index 000000000000..5b2bfc9de036 --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex8.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a${} +bc/$ +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/enterAction/regex9.test b/plugins/groovy/testdata/groovy/enterAction/regex9.test new file mode 100644 index 000000000000..7c61b1a3a30f --- /dev/null +++ b/plugins/groovy/testdata/groovy/enterAction/regex9.test @@ -0,0 +1,8 @@ +cl { + $/a${}bc/$ +} +----- +cl { + $/a +${}bc/$ +} \ No newline at end of file