Move statement: Add or remove empty lines correctly

#KT-14946 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-08-05 19:18:34 +09:00
committed by klunnii
parent 73dec25eb1
commit 8a595ad165
38 changed files with 232 additions and 17 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.codeInsight.upDownMover;
import com.intellij.codeInsight.editorActions.moveUpDown.LineRange;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
@@ -36,6 +37,8 @@ import java.util.List;
public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
private boolean moveEnumConstant = false;
private boolean moveOutOfBlock = false;
private boolean moveIntoBlock = false;
private static int findNearestNonWhitespace(@NotNull CharSequence sequence, int index) {
char ch = sequence.charAt(--index);
@@ -48,8 +51,8 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
@Override
public void afterMove(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
super.afterMove(editor, file, info, down);
Document document = editor.getDocument();
if (moveEnumConstant) {
Document document = editor.getDocument();
CharSequence cs = document.getCharsSequence();
int end1 = findNearestNonWhitespace(cs, info.range1.getEndOffset());
char c1 = cs.charAt(end1);
@@ -72,6 +75,27 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
document.insertString(end1 + 1, ",");
}
}
if (moveIntoBlock || moveOutOfBlock) {
if (down) {
if (moveIntoBlock) {
document.deleteString(info.range1.getEndOffset(), info.range2.getStartOffset());
}
else {
int offset = info.range1.getEndOffset();
document.insertString(offset, "\n");
CaretModel caretModel = editor.getCaretModel();
if (document.getCharsSequence().charAt(caretModel.getOffset() - 1) == '\n') caretModel.moveToOffset(offset + 1);
}
}
else {
if (moveIntoBlock) {
document.deleteString(info.range2.getEndOffset(), info.range1.getStartOffset());
}
else {
document.insertString(info.range2.getEndOffset(), "\n");
}
}
}
}
@NotNull
@@ -228,7 +252,7 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
PsiElement nextParent = null;
// moving out of code block
if (sibling.getNode().getElementType() == (down ? KtTokens.RBRACE : KtTokens.LBRACE)) {
if (isMovingOutOfBlock(sibling, down)) {
// elements which aren't immediately placed in class body can't leave the block
PsiElement parent = sibling.getParent();
if (!(parent instanceof KtClassBody)) return null;
@@ -246,18 +270,14 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
// moving into code block
// element may move only into class body
else {
if (sibling instanceof KtClassOrObject) {
KtClassOrObject ktClassOrObject = (KtClassOrObject) sibling;
KtClassBody classBody = ktClassOrObject.getBody();
// confined elements can't leave their block
if (classBody != null) {
nextParent = classBody;
if (!down) {
start = classBody.getRBrace();
}
end = down ? classBody.getLBrace() : classBody.getRBrace();
KtClassBody classBody = getClassBody(sibling);
// confined elements can't leave their block
if (classBody != null) {
nextParent = classBody;
if (!down) {
start = classBody.getRBrace();
}
end = down ? classBody.getLBrace() : classBody.getRBrace();
}
}
@@ -279,6 +299,19 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
return start != null && end != null ? new LineRange(start, end, editor.getDocument()) : null;
}
private static boolean isMovingOutOfBlock(@NotNull PsiElement sibling, boolean down) {
return sibling.getNode().getElementType() == (down ? KtTokens.RBRACE : KtTokens.LBRACE);
}
@Nullable
private static KtClassBody getClassBody(PsiElement element) {
if (element instanceof KtClassOrObject) {
return ((KtClassOrObject) element).getBody();
} else {
return null;
}
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
if (!super.checkAvailable(editor, file, info, down)) return false;
@@ -306,6 +339,8 @@ public class KotlinDeclarationMover extends AbstractKotlinUpDownMover {
info.toMove2 = null;
return true;
}
moveOutOfBlock = isMovingOutOfBlock(sibling, down);
moveIntoBlock = getClassBody(sibling) != null;
info.toMove = sourceRange;
info.toMove2 = getTargetRange(editor, sibling, down, sourceRange.firstElement);
@@ -5,6 +5,7 @@ class A {
val x = ""
}
// class B
<caret>class B {
@@ -2,6 +2,7 @@
<caret>class B {
}
// MOVE: up
// class A
class A {
@@ -4,6 +4,7 @@ class A {
// class B
class B {
}
// class C
<caret>class C {
@@ -5,6 +5,7 @@ class A {
<caret>class C {
}
// class B
class B {
}
@@ -4,6 +4,7 @@ fun foo() {
// class A
class A {
}
// class B
<caret>class B {
@@ -5,6 +5,7 @@ fun foo() {
<caret>class B {
}
// class A
class A {
}
@@ -1,6 +1,5 @@
// class D
class D {
// MOVE: down
// class A
<caret>class A
@@ -3,7 +3,6 @@
class D {
// class A
<caret>class A
}
// class C
@@ -1,6 +1,5 @@
// class D
class D {
// MOVE: down
// class A
<caret>class A
@@ -3,5 +3,4 @@
class D {
// class A
<caret>class A
}
@@ -0,0 +1,10 @@
// MOVE: down
class Outer {
<caret>class N1 {
fun foo1() {}
}
class N2 {
fun foo2() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class Outer {
class N2 {
<caret>class N1 {
fun foo1() {}
}
fun foo2() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class Outer {
class N2 {
<caret>class N1 {
fun foo1() {}
}
fun foo2() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class Outer {
class N2 {
fun foo2() {}
<caret>class N1 {
fun foo1() {}
}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class Outer {
class N2 {
fun foo2() {}
<caret>class N1 {
fun foo1() {}
}
}
}
@@ -0,0 +1,10 @@
// MOVE: down
class Outer {
class N2 {
fun foo2() {}
}
<caret>class N1 {
fun foo1() {}
}
}
@@ -0,0 +1,10 @@
// MOVE: up
class Outer {
class N2 {
fun foo2() {}
}
<caret>class N1 {
fun foo1() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: up
class Outer {
class N2 {
fun foo2() {}
<caret>class N1 {
fun foo1() {}
}
}
}
@@ -0,0 +1,9 @@
// MOVE: up
class Outer {
class N2 {
fun foo2() {}
<caret>class N1 {
fun foo1() {}
}
}
}
@@ -0,0 +1,9 @@
// MOVE: up
class Outer {
class N2 {
<caret>class N1 {
fun foo1() {}
}
fun foo2() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: up
class Outer {
class N2 {
<caret>class N1 {
fun foo1() {}
}
fun foo2() {}
}
}
@@ -0,0 +1,10 @@
// MOVE: up
class Outer {
<caret>class N1 {
fun foo1() {}
}
class N2 {
fun foo2() {}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class Outer {
class N2 {
fun foo2() {}
<caret> class N1 {
fun foo1() {}
}
}
}
@@ -0,0 +1,10 @@
// MOVE: down
class Outer {
class N2 {
fun foo2() {}
}
<caret> class N1 {
fun foo1() {}
}
}
@@ -5,6 +5,7 @@ class A {
val x = ""
}
// fun foo
<caret>fun foo() {
@@ -2,6 +2,7 @@
<caret>fun foo() {
}
// MOVE: up
// class A
class A {
@@ -4,6 +4,7 @@ class A {
// class B
class B {
}
// fun foo
<caret>fun foo() {
@@ -5,6 +5,7 @@ class A {
<caret>fun foo() {
}
// class B
class B {
}
@@ -4,6 +4,7 @@ fun foo() {
// class B
class B {
}
// fun foo
<caret>fun foo() {
@@ -5,6 +5,7 @@ fun foo() {
<caret>fun foo() {
}
// class B
class B {
}
@@ -5,5 +5,6 @@ class A {
val x = ""
}
// val y
<caret>val y = ""
@@ -1,5 +1,6 @@
// val x
<caret>val x = ""
// MOVE: up
// class A
class A {
@@ -4,6 +4,7 @@ class A {
// class B
class B {
}
// val y
<caret>val y = ""
}
@@ -3,6 +3,7 @@
class A {
// val y
<caret>val y = ""
// class B
class B {
}
@@ -4,6 +4,7 @@ fun foo() {
// class B
class B {
}
// val y
<caret>val y = ""
}
@@ -3,6 +3,7 @@
fun foo() {
// val y
<caret>val y = ""
// class B
class B {
}
@@ -194,6 +194,41 @@ public class MoveStatementTestGenerated extends AbstractMoveStatementTest {
public void testClassWithoutBody4() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/classWithoutBody4.kt");
}
@TestMetadata("kt-14946-1.kt")
public void testKt_14946_1() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-1.kt");
}
@TestMetadata("kt-14946-2.kt")
public void testKt_14946_2() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-2.kt");
}
@TestMetadata("kt-14946-3.kt")
public void testKt_14946_3() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-3.kt");
}
@TestMetadata("kt-14946-4.kt")
public void testKt_14946_4() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-4.kt");
}
@TestMetadata("kt-14946-5.kt")
public void testKt_14946_5() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-5.kt");
}
@TestMetadata("kt-14946-6.kt")
public void testKt_14946_6() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-6.kt");
}
@TestMetadata("kt-14946-7.kt")
public void testKt_14946_7() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/class/kt-14946-7.kt");
}
}
@TestMetadata("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/classInitializer")