PY-18522 Better detection of empty statement blocks near whitespace
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Tue, 5 Apr 2016 11:40:47 +0000 (14:40 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Tue, 5 Apr 2016 14:04:18 +0000 (17:04 +0300)
Now it's able to find not only empty function/class bodies but also
empty blocks of other compound statements such as conditional
branches, loops, try/except/finally parts etc.

python/src/com/jetbrains/python/editor/PythonCopyPasteProcessor.java
python/testData/copyPaste/EmptyBranchBlock.after.py [new file with mode: 0644]
python/testData/copyPaste/EmptyBranchBlock.dst.py [new file with mode: 0644]
python/testData/copyPaste/EmptyBranchBlock.src.py [new file with mode: 0644]
python/testSrc/com/jetbrains/python/PyCopyPasteTest.java

index f6598fada58a2af5077b78b869581220b875de83..dfb1294427da51dae574807b14f59f75fd9ba785 100644 (file)
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.text.CharFilter;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiErrorElement;
 import com.intellij.psi.PsiFile;
 import com.intellij.psi.PsiWhiteSpace;
 import com.intellij.psi.codeStyle.CodeStyleSettings;
@@ -156,9 +157,7 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
     final PsiElement ws = file.findElementAt(lineStartOffset);
     final String userIndent = document.getText(TextRange.create(lineStartOffset, caretOffset));
     if (ws != null) {
-      // Beginning of empty definition, e.g. class or function header without the actual body
-      PyStatementList statementList = ObjectUtils.chooseNotNull(as(ws.getNextSibling(), PyStatementList.class),
-                                                                as(ws.getPrevSibling(), PyStatementList.class));
+      PyStatementList statementList = findEmptyStatementListNearby(ws);
 
       if (statementList != null && statementList.getStatements().length == 0) {
         return PyIndentUtil.getElementIndent(statementList);
@@ -184,6 +183,19 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
     return userIndent;
   }
 
+  @Nullable
+  private static PyStatementList findEmptyStatementListNearby(@NotNull PsiElement ws) {
+    PyStatementList statementList = ObjectUtils.chooseNotNull(as(ws.getNextSibling(), PyStatementList.class),
+                                                              as(ws.getPrevSibling(), PyStatementList.class));
+    if (statementList == null) {
+      final PsiElement prevLeaf = PsiTreeUtil.prevLeaf(ws, false);
+      if (prevLeaf instanceof PsiErrorElement) {
+        statementList = as(prevLeaf.getParent(), PyStatementList.class);
+      }
+    }
+    return statementList;
+  }
+
   @Nullable
   private static PyStatementListContainer getDeepestPossibleParentBlock(@NotNull PsiElement whitespace) {
     final PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(whitespace);
diff --git a/python/testData/copyPaste/EmptyBranchBlock.after.py b/python/testData/copyPaste/EmptyBranchBlock.after.py
new file mode 100644 (file)
index 0000000..0bcb782
--- /dev/null
@@ -0,0 +1,6 @@
+def f():
+    for i in []:
+        pass
+    else:
+        x = 1
+        y = 2
diff --git a/python/testData/copyPaste/EmptyBranchBlock.dst.py b/python/testData/copyPaste/EmptyBranchBlock.dst.py
new file mode 100644 (file)
index 0000000..7029cdb
--- /dev/null
@@ -0,0 +1,5 @@
+def f():
+    for i in []:
+        pass
+    else:
+<caret>
diff --git a/python/testData/copyPaste/EmptyBranchBlock.src.py b/python/testData/copyPaste/EmptyBranchBlock.src.py
new file mode 100644 (file)
index 0000000..e1719f7
--- /dev/null
@@ -0,0 +1,2 @@
+<selection>x = 1
+y = 2</selection>
\ No newline at end of file
index 12324afc0bbf015b29ee9401dc558cc3fc0f7c49..3f3231bde6348a39cc8d34b92f819ee30ca7b6f7 100644 (file)
@@ -397,6 +397,11 @@ public class PyCopyPasteTest extends PyTestCase {
     doTest();
   }
 
+  // PY-18522
+  public void testEmptyBranchBlock() {
+    doTest();
+  }
+
   // PY-19064
   public void testAmbiguousParentBlockSmallestIndent() {
     doTest();