nicer enter key indentation handling after -> and before } in closures94.310
authorpeter <peter.gromov@jetbrains.com>
Sun, 14 Feb 2010 23:09:42 +0000 (14 23:09 +0000)
committerpeter <peter.gromov@jetbrains.com>
Sun, 14 Feb 2010 23:09:42 +0000 (14 23:09 +0000)
platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java
platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyEnterHandler.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.groovy [moved from plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/EnterActionTest.java with 75% similarity]

index e61cb26..e58188c 100644 (file)
@@ -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);
index 42174f8..84fba5d 100644 (file)
@@ -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 {
index 3a5dc50..7151cbe 100644 (file)
@@ -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<Integer> 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 =
@@ -35,10 +35,14 @@ public class EnterActionTest extends GroovyFormatterTestCase {
   private void doTest() throws Throwable {
     final List<String> 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 -><caret> }
+"""
+    doEnter()
+    myFixture.checkResult """
+def c = { a ->
+  <caret>
+}
+"""
+  }
+  public void testAfterClosureArrowWithBody() throws Throwable {
+    myFixture.configureByText "a.groovy", """
+def c = { a -><caret> zzz }
+"""
+    doEnter()
+    myFixture.checkResult """
+def c = { a ->
+<caret>  zzz }
+"""
+  }
+  public void testAfterClosureArrowWithBody2() throws Throwable {
+    myFixture.configureByText "a.groovy", """
+def c = { a -> <caret>zzz }
+"""
+    doEnter()
+    myFixture.checkResult """
+def c = { a ->
+  <caret>zzz }
+""", true
+  }
+
+  public void testBeforeClosingClosureBrace() throws Throwable {
+    myFixture.configureByText "a.groovy", """
+def c = { a ->
+  zzz <caret>}
+"""
+    doEnter()
+    myFixture.checkResult """
+def c = { a ->
+  zzz 
+<caret>}
+"""
+  }
+  
+  public void testAlmostBeforeClosingClosureBrace() throws Throwable {
+    myFixture.configureByText "a.groovy", """
+def c = { a ->
+  zzz<caret> }
+"""
+    doEnter()
+    myFixture.checkResult """
+def c = { a ->
+  zzz
+<caret>}
+"""
+  }
+
 }