Completion: better replacement range calculation for both basic and smart completions
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(<caret>xxx)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(<caret>x.y())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(sss<caret>.y())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(<caret>null)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(<caret>123)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(<caret>this)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(<caret>true)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun String.bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(<caret>x.y())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(<caret>1 + x)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(<caret>x().y.z())
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(sss: String) {
|
||||
foo(sss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(ss: String) {
|
||||
foo(<caret>xxx)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(s: String){ }
|
||||
|
||||
fun bar(ss: String) {
|
||||
foo(ss<caret>)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
var b1: Boolean = true
|
||||
var b2: Boolean = true
|
||||
var b3: Boolean = true
|
||||
val c: String = ""
|
||||
|
||||
fun bar() {
|
||||
if (b1 && <caret>b2 && b3) {}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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`('(')
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user