From 24b68e7bdf10dac3f2eb51d96abb9bdfc2d258e6 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 19 Dec 2013 16:01:49 +0400 Subject: [PATCH] Completion: better replacement range calculation for both basic and smart completions --- .../completion/JetCompletionContributor.java | 28 +++++++++++-------- .../handlers/TabReplaceIdentifier.kt | 5 ++++ .../handlers/TabReplaceIdentifier.kt.after | 5 ++++ .../handlers/TabReplaceIdentifier2.kt | 5 ++++ .../handlers/TabReplaceIdentifier2.kt.after | 5 ++++ .../completion/handlers/TabReplaceNull.kt | 5 ++++ .../handlers/TabReplaceNull.kt.after | 5 ++++ .../completion/handlers/TabReplaceNumber.kt | 5 ++++ .../handlers/TabReplaceNumber.kt.after | 5 ++++ .../completion/handlers/TabReplaceThis.kt | 5 ++++ .../handlers/TabReplaceThis.kt.after | 5 ++++ .../completion/handlers/TabReplaceTrue.kt | 5 ++++ .../handlers/TabReplaceTrue.kt.after | 5 ++++ .../handlers/smart/TabReplaceExpression.kt | 5 ++++ .../smart/TabReplaceExpression.kt.after | 5 ++++ .../handlers/smart/TabReplaceExpression2.kt | 5 ++++ .../smart/TabReplaceExpression2.kt.after | 5 ++++ .../handlers/smart/TabReplaceExpression3.kt | 5 ++++ .../smart/TabReplaceExpression3.kt.after | 5 ++++ .../handlers/smart/TabReplaceIdentifier.kt | 5 ++++ .../smart/TabReplaceIdentifier.kt.after | 5 ++++ .../handlers/smart/TabReplaceOperand.kt | 8 ++++++ .../handlers/smart/TabReplaceOperand.kt.after | 8 ++++++ .../handlers/BasicCompletionHandlerTest.kt | 7 +++++ .../handlers/SmartCompletionHandlerTest.kt | 5 ++++ 25 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 idea/testData/completion/handlers/TabReplaceIdentifier.kt create mode 100644 idea/testData/completion/handlers/TabReplaceIdentifier.kt.after create mode 100644 idea/testData/completion/handlers/TabReplaceIdentifier2.kt create mode 100644 idea/testData/completion/handlers/TabReplaceIdentifier2.kt.after create mode 100644 idea/testData/completion/handlers/TabReplaceNull.kt create mode 100644 idea/testData/completion/handlers/TabReplaceNull.kt.after create mode 100644 idea/testData/completion/handlers/TabReplaceNumber.kt create mode 100644 idea/testData/completion/handlers/TabReplaceNumber.kt.after create mode 100644 idea/testData/completion/handlers/TabReplaceThis.kt create mode 100644 idea/testData/completion/handlers/TabReplaceThis.kt.after create mode 100644 idea/testData/completion/handlers/TabReplaceTrue.kt create mode 100644 idea/testData/completion/handlers/TabReplaceTrue.kt.after create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression.kt create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression.kt.after create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression2.kt create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression2.kt.after create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression3.kt create mode 100644 idea/testData/completion/handlers/smart/TabReplaceExpression3.kt.after create mode 100644 idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt create mode 100644 idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt.after create mode 100644 idea/testData/completion/handlers/smart/TabReplaceOperand.kt create mode 100644 idea/testData/completion/handlers/smart/TabReplaceOperand.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java index 6fea27158f9..10fcca395f0 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java @@ -20,13 +20,14 @@ import com.intellij.codeInsight.completion.*; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.tree.IElementType; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; -import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.plugin.references.JetSimpleNameReference; public class JetCompletionContributor extends CompletionContributor { @@ -117,17 +118,22 @@ public class JetCompletionContributor extends CompletionContributor { } } - if (!context.getEditor().getSelectionModel().hasSelection()) { - PsiReference reference = context.getFile().findReferenceAt(offset); - if (reference != null) { - PsiElement atElement = context.getFile().findElementAt(offset); - assert atElement != null : String.format("Element is not expected to be null: %d in file %s", - offset, context.getFile().getText()); + // this code will make replacement offset "modified" and prevents altering it by the code in CompletionProgressIndicator + context.setReplacementOffset(context.getReplacementOffset()); - IElementType parentElementType = atElement.getParent().getNode().getElementType(); - - if (!(reference instanceof JetSimpleNameReference) || parentElementType == JetNodeTypes.OPERATION_REFERENCE) { - context.setReplacementOffset(offset); + if (context.getCompletionType() == CompletionType.SMART) { + PsiElement tokenAt = context.getFile().findElementAt(Math.max(0, offset)); + if (tokenAt != null) { + PsiElement parent = tokenAt.getParent(); + if (parent instanceof JetExpression) { + // search expression to be replaced - go up while we are the first child of parent expression + JetExpression expression = (JetExpression) parent; + parent = expression.getParent(); + while (parent instanceof JetExpression && parent.getFirstChild() == expression) { + expression = (JetExpression) parent; + parent = expression.getParent(); + } + context.setReplacementOffset(expression.getTextRange().getEndOffset()); } } } diff --git a/idea/testData/completion/handlers/TabReplaceIdentifier.kt b/idea/testData/completion/handlers/TabReplaceIdentifier.kt new file mode 100644 index 00000000000..e396ccf8d66 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceIdentifier.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(xxx) +} diff --git a/idea/testData/completion/handlers/TabReplaceIdentifier.kt.after b/idea/testData/completion/handlers/TabReplaceIdentifier.kt.after new file mode 100644 index 00000000000..9bfee2b8268 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceIdentifier.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/TabReplaceIdentifier2.kt b/idea/testData/completion/handlers/TabReplaceIdentifier2.kt new file mode 100644 index 00000000000..9f105347112 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceIdentifier2.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(x.y()) +} diff --git a/idea/testData/completion/handlers/TabReplaceIdentifier2.kt.after b/idea/testData/completion/handlers/TabReplaceIdentifier2.kt.after new file mode 100644 index 00000000000..849adc1def4 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceIdentifier2.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(sss.y()) +} diff --git a/idea/testData/completion/handlers/TabReplaceNull.kt b/idea/testData/completion/handlers/TabReplaceNull.kt new file mode 100644 index 00000000000..efe834dce9c --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceNull.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(null) +} diff --git a/idea/testData/completion/handlers/TabReplaceNull.kt.after b/idea/testData/completion/handlers/TabReplaceNull.kt.after new file mode 100644 index 00000000000..828bf532aa3 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceNull.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/TabReplaceNumber.kt b/idea/testData/completion/handlers/TabReplaceNumber.kt new file mode 100644 index 00000000000..4daeaef43c8 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceNumber.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(123) +} diff --git a/idea/testData/completion/handlers/TabReplaceNumber.kt.after b/idea/testData/completion/handlers/TabReplaceNumber.kt.after new file mode 100644 index 00000000000..828bf532aa3 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceNumber.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/TabReplaceThis.kt b/idea/testData/completion/handlers/TabReplaceThis.kt new file mode 100644 index 00000000000..bbe4a26e7b9 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceThis.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(this) +} diff --git a/idea/testData/completion/handlers/TabReplaceThis.kt.after b/idea/testData/completion/handlers/TabReplaceThis.kt.after new file mode 100644 index 00000000000..828bf532aa3 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceThis.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/TabReplaceTrue.kt b/idea/testData/completion/handlers/TabReplaceTrue.kt new file mode 100644 index 00000000000..8f011614cec --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceTrue.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(true) +} diff --git a/idea/testData/completion/handlers/TabReplaceTrue.kt.after b/idea/testData/completion/handlers/TabReplaceTrue.kt.after new file mode 100644 index 00000000000..828bf532aa3 --- /dev/null +++ b/idea/testData/completion/handlers/TabReplaceTrue.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun String.bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression.kt b/idea/testData/completion/handlers/smart/TabReplaceExpression.kt new file mode 100644 index 00000000000..9f105347112 --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(x.y()) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression.kt.after b/idea/testData/completion/handlers/smart/TabReplaceExpression.kt.after new file mode 100644 index 00000000000..9bfee2b8268 --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt b/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt new file mode 100644 index 00000000000..46d56d72fbf --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(1 + x) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt.after b/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt.after new file mode 100644 index 00000000000..9bfee2b8268 --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression2.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt b/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt new file mode 100644 index 00000000000..62b624997cb --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(x().y.z()) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt.after b/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt.after new file mode 100644 index 00000000000..9bfee2b8268 --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceExpression3.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(sss: String) { + foo(sss) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt b/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt new file mode 100644 index 00000000000..f6688afec6f --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(ss: String) { + foo(xxx) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt.after b/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt.after new file mode 100644 index 00000000000..ec7e283ff0f --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceIdentifier.kt.after @@ -0,0 +1,5 @@ +fun foo(s: String){ } + +fun bar(ss: String) { + foo(ss) +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceOperand.kt b/idea/testData/completion/handlers/smart/TabReplaceOperand.kt new file mode 100644 index 00000000000..afbd9b2e9c5 --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceOperand.kt @@ -0,0 +1,8 @@ +var b1: Boolean = true +var b2: Boolean = true +var b3: Boolean = true +val c: String = "" + +fun bar() { + if (b1 && b2 && b3) {} +} diff --git a/idea/testData/completion/handlers/smart/TabReplaceOperand.kt.after b/idea/testData/completion/handlers/smart/TabReplaceOperand.kt.after new file mode 100644 index 00000000000..3f13f645f1a --- /dev/null +++ b/idea/testData/completion/handlers/smart/TabReplaceOperand.kt.after @@ -0,0 +1,8 @@ +var b1: Boolean = true +var b2: Boolean = true +var b3: Boolean = true +val c: String = "" + +fun bar() { + if (b1 && b3 && b3) {} +} diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt index 13b2c6e838d..7854263bf50 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt +++ b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt @@ -66,6 +66,13 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){ fun testInsertFunctionWithSingleParameterWithBrace() = doTest(0, "some", null, '{') + fun testTabReplaceIdentifier() = doTest(1, "sss", null, '\t') + fun testTabReplaceIdentifier2() = doTest(1, "sss", null, '\t') + fun testTabReplaceThis() = doTest(1, "sss", null, '\t') + fun testTabReplaceNull() = doTest(1, "sss", null, '\t') + fun testTabReplaceTrue() = doTest(1, "sss", null, '\t') + fun testTabReplaceNumber() = doTest(1, "sss", null, '\t') + fun testSingleBrackets() { fixture.configureByFile(fileName()) fixture.`type`('(') diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt index 79ec10c8eca..5e05779187d 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt +++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt @@ -46,4 +46,9 @@ public class SmartCompletionHandlerTest() : CompletionHandlerTestBase() { fun testClassObjectMethod1() = doTest(1, "K.bar", null, '\n') fun testClassObjectMethod2() = doTest(1, "K.bar", null, '\n') //fun testJavaStaticFieldInsertImport() = doTest(1, "Locale.ENGLISH", null, '\n') //TODO + fun testTabReplaceIdentifier() = doTest(1, "ss", null, '\t') + fun testTabReplaceExpression() = doTest(1, "sss", null, '\t') + fun testTabReplaceExpression2() = doTest(1, "sss", null, '\t') + fun testTabReplaceExpression3() = doTest(1, "sss", null, '\t') + fun testTabReplaceOperand() = doTest(1, "b3", null, '\t') }