From 295a704f777dbe1d3d2858dd14c6f83e1eb3fb8b Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 14 Feb 2010 23:09:42 +0000 Subject: [PATCH] nicer enter key indentation handling after -> and before } in closures --- .../fixtures/CodeInsightTestFixture.java | 2 + .../fixtures/impl/CodeInsightTestFixtureImpl.java | 6 +- .../lang/editor/actions/GroovyEnterHandler.java | 81 +++++++++++++--------- ...EnterActionTest.java => EnterActionTest.groovy} | 64 ++++++++++++++++- 4 files changed, 117 insertions(+), 36 deletions(-) rename plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/{EnterActionTest.java => EnterActionTest.groovy} (75%) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index e61cb2610f..e58188cb71 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -293,6 +293,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { void checkResult(final String text) throws IOException; + void checkResult(final String text, boolean stripTrailingSpaces) throws IOException; + Document getDocument(PsiFile file); void setFileContext(@Nullable PsiElement context); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 42174f8acf..84fba5db90 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -740,9 +740,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } public void checkResult(final String text) throws IOException { + checkResult(text, false); + } + + public void checkResult(String text, boolean stripTrailingSpaces) throws IOException { PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); EditorUtil.fillVirtualSpaceUntilCaret(myEditor); - checkResult("TEXT", false, SelectionAndCaretMarkupLoader.fromText(text, getProject()), myFile.getText()); + checkResult("TEXT", stripTrailingSpaces, SelectionAndCaretMarkupLoader.fromText(text, getProject()), myFile.getText()); } public void checkResultByFile(final String expectedFile) throws Exception { 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 3a5dc50c20..7151cbe72b 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 @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.editor.actions; +import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate; import com.intellij.lang.ASTNode; import com.intellij.openapi.actionSystem.DataContext; @@ -31,17 +32,20 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.editor.HandlerUtils; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; 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.*; + /** * @author ilyas */ @@ -53,7 +57,46 @@ public class GroovyEnterHandler implements EnterHandlerDelegate { Ref caretAdvance, DataContext dataContext, EditorActionHandler originalHandler) { - if (handleEnter(editor, dataContext, file.getProject(), originalHandler)) { + String text = editor.getDocument().getText(); + if (StringUtil.isEmpty(text)) { + return Result.Continue; + } + + final int caret = editor.getCaretModel().getOffset(); + final EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter(); + if (caret >= 1 && caret < text.length() && CodeInsightSettings.getInstance().SMART_INDENT_ON_ENTER) { + HighlighterIterator iterator = highlighter.createIterator(caret); + iterator.retreat(); + while (!iterator.atEnd() && mWS == iterator.getTokenType()) { + iterator.retreat(); + } + boolean afterArrow = !iterator.atEnd() && iterator.getTokenType() == mCLOSABLE_BLOCK_OP; + if (afterArrow) { + originalHandler.execute(editor, dataContext); + PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); + CodeStyleManager.getInstance(file.getProject()).adjustLineIndent(file, editor.getCaretModel().getOffset()); + } + + iterator = highlighter.createIterator(editor.getCaretModel().getOffset()); + while (mWS == iterator.getTokenType() && !iterator.atEnd()) { + iterator.advance(); + } + if (!iterator.atEnd() && mRCURLY == iterator.getTokenType()) { + PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); + final PsiElement element = file.findElementAt(iterator.getStart()); + if (element != null && + element.getNode().getElementType() == mRCURLY && + element.getParent() instanceof GrClosableBlock && + text.length() > caret) { + return Result.DefaultForceIndent; + } + } + if (afterArrow) { + return Result.Stop; + } + } + + if (handleEnter(editor, dataContext, file.getProject(), originalHandler, file)) { return Result.Stop; } return Result.Continue; @@ -62,8 +105,8 @@ public class GroovyEnterHandler implements EnterHandlerDelegate { protected static boolean handleEnter(Editor editor, DataContext dataContext, @NotNull Project project, - EditorActionHandler originalHandler) { - if (!HandlerUtils.canBeInvoked(editor, project)) { + EditorActionHandler originalHandler, PsiFile file) { + if (HandlerUtils.isReadOnly(editor)) { return false; } int caretOffset = editor.getCaretModel().getOffset(); @@ -72,9 +115,6 @@ public class GroovyEnterHandler implements EnterHandlerDelegate { if (handleBetweenSquareBraces(editor, caretOffset, dataContext, project, originalHandler)) { return true; } - if (handleBeforeCurlyBrace(editor, caretOffset, dataContext, originalHandler)) { - return true; - } if (handleInString(editor, caretOffset, dataContext, originalHandler)) { return true; } @@ -108,33 +148,6 @@ public class GroovyEnterHandler implements EnterHandlerDelegate { return false; } - private static boolean handleBeforeCurlyBrace(Editor editor, int caret, DataContext context, EditorActionHandler originalHandler) { - String text = editor.getDocument().getText(); - if (text == null || text.length() == 0) return false; - final EditorHighlighter highlighter = ((EditorEx)editor).getHighlighter(); - if (caret < 1 || caret > text.length() - 1) { - return false; - } - HighlighterIterator iterator = highlighter.createIterator(caret); - if (mRCURLY == iterator.getTokenType()) { - PsiFile file = DataKeys.PSI_FILE.getData(context); - if (file != null) { - final PsiElement element = file.findElementAt(caret); - if (element != null && - element.getNode().getElementType() == mRCURLY && - element.getParent() instanceof GrClosableBlock && - text.length() > caret) { - iterator = highlighter.createIterator(caret); - if (mRCURLY == iterator.getTokenType()) { - originalHandler.execute(editor, context); - return true; - } - } - } - } - return false; - } - private static final TokenSet AFTER_DOLLAR = TokenSet.create(mLCURLY, mIDENT, mGSTRING_CONTENT, mDOLLAR, mGSTRING_END); private static final TokenSet ALL_STRINGS = diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy similarity index 75% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy index c09edd81c4..3999459350 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy @@ -35,10 +35,14 @@ public class EnterActionTest extends GroovyFormatterTestCase { private void doTest() throws Throwable { final List data = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test"); myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, data.get(0)); - myFixture.type('\n'); + doEnter(); myFixture.checkResult(data.get(1)); } + private def doEnter() { + myFixture.type((char)'\n') + } + public void testClos1() throws Throwable { doTest(); } public void testClos2() throws Throwable { doTest(); } public void testComment1() throws Throwable { doTest(); } @@ -80,5 +84,63 @@ public class EnterActionTest extends GroovyFormatterTestCase { public void testString5() throws Throwable { doTest(); } public void testString6() throws Throwable { doTest(); } + public void testAfterClosureArrow() throws Throwable { + myFixture.configureByText "a.groovy", """ +def c = { a -> } +""" + doEnter() + myFixture.checkResult """ +def c = { a -> + +} +""" + } + public void testAfterClosureArrowWithBody() throws Throwable { + myFixture.configureByText "a.groovy", """ +def c = { a -> zzz } +""" + doEnter() + myFixture.checkResult """ +def c = { a -> + zzz } +""" + } + public void testAfterClosureArrowWithBody2() throws Throwable { + myFixture.configureByText "a.groovy", """ +def c = { a -> zzz } +""" + doEnter() + myFixture.checkResult """ +def c = { a -> + zzz } +""", true + } + + public void testBeforeClosingClosureBrace() throws Throwable { + myFixture.configureByText "a.groovy", """ +def c = { a -> + zzz } +""" + doEnter() + myFixture.checkResult """ +def c = { a -> + zzz +} +""" + } + + public void testAlmostBeforeClosingClosureBrace() throws Throwable { + myFixture.configureByText "a.groovy", """ +def c = { a -> + zzz } +""" + doEnter() + myFixture.checkResult """ +def c = { a -> + zzz +} +""" + } + } -- 2.11.4.GIT