Completion auto-popup works at the start of function literal

This commit is contained in:
Valentin Kipyatkov
2015-01-13 19:33:58 +03:00
parent dc1d06db9c
commit eed0def1cb
12 changed files with 104 additions and 18 deletions
@@ -23,6 +23,10 @@ import org.jetbrains.kotlin.psi.JetFile
import com.intellij.openapi.util.Key
import com.intellij.codeInsight.completion.CompletionService
import com.intellij.codeInsight.completion.CompletionProgressIndicator
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.psiUtil.prevLeafSkipWhitespacesAndComments
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetFunctionLiteral
public class KotlinCompletionCharFilter() : CharFilter() {
class object {
@@ -36,9 +40,19 @@ public class KotlinCompletionCharFilter() : CharFilter() {
if (!lookup.isCompletion()) return null
// it does not work in tests, so we use other way
// val isAutopopup = CompletionService.getCompletionService().getCurrentCompletion().isAutopopupCompletion()
val isAutopopup = (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator).getParameters().getInvocationCount() == 0
val completionParameters = (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator).getParameters()
val isAutopopup = completionParameters.getInvocationCount() == 0
if (Character.isJavaIdentifierPart(c) || c == ':' /* used in '::xxx'*/ || c == '@') {
if (Character.isJavaIdentifierPart(c) || c == '@') {
return CharFilter.Result.ADD_TO_PREFIX
}
// do not accept items by special chars in the very beginning of function literal where name of the first parameter can be
if (isAutopopup && !lookup.isSelectionTouched() && isInFunctionLiteralStart(completionParameters.getPosition())) {
return Result.HIDE_LOOKUP
}
if (c == ':' /* used in '::xxx'*/) {
return CharFilter.Result.ADD_TO_PREFIX
}
@@ -70,4 +84,14 @@ public class KotlinCompletionCharFilter() : CharFilter() {
else -> CharFilter.Result.HIDE_LOOKUP
}
}
private fun isInFunctionLiteralStart(position: PsiElement): Boolean {
var prev = position.prevLeafSkipWhitespacesAndComments()
if (prev?.getNode()?.getElementType() == JetTokens.LPAR) {
prev = prev?.prevLeafSkipWhitespacesAndComments()
}
if (prev?.getNode()?.getElementType() != JetTokens.LBRACE) return false
val functionLiteral = prev!!.getParent() as? JetFunctionLiteral ?: return false
return functionLiteral.getLBrace() == prev
}
}
@@ -248,9 +248,6 @@ public class KotlinCompletionContributor : CompletionContributor() {
// no auto-popup on typing after "val", "var" and "fun" because it's likely the name of the declaration which is being typed by user
if (invocationCount == 0 && isInExtensionReceiver(position)) return true
// no auto-popup on typing in the very beginning of function literal where name of the first parameter can be
if (invocationCount == 0 && isInFunctionLiteralStart(position)) return true
return false
}
@@ -267,16 +264,6 @@ public class KotlinCompletionContributor : CompletionContributor() {
}
}
private fun isInFunctionLiteralStart(position: PsiElement): Boolean {
var prev = position.prevLeafSkipWhitespacesAndComments()
if (prev?.getNode()?.getElementType() == JetTokens.LPAR) {
prev = prev?.prevLeafSkipWhitespacesAndComments()
}
if (prev?.getNode()?.getElementType() != JetTokens.LBRACE) return false
val functionLiteral = prev!!.getParent() as? JetFunctionLiteral ?: return false
return functionLiteral.getLBrace() == prev
}
private fun isAtEndOfLine(offset: Int, document: Document): Boolean {
var i = offset
val chars = document.getCharsSequence()
@@ -3,4 +3,5 @@ fun bar() {
}
// INVOCATION_COUNT: 0
// NUMBER: 0
// EXIST: bar
// EXIST: null
@@ -3,4 +3,5 @@ fun bar() {
}
// INVOCATION_COUNT: 0
// NUMBER: 0
// EXIST: bar
// EXIST: null
@@ -5,4 +5,5 @@ fun bar() {
}
// INVOCATION_COUNT: 0
// NUMBER: 0
// EXIST: bar
// EXIST: null
@@ -0,0 +1,9 @@
fun foo(p: (String) -> Unit){}
fun bar() {
foo { p<caret> }
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ' '
@@ -0,0 +1,9 @@
fun foo(p: (String) -> Unit){}
fun bar() {
foo { p <caret> }
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ' '
@@ -0,0 +1,9 @@
fun foo(p: (String) -> Unit){}
fun bar() {
foo { (p<caret> }
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ':'
@@ -0,0 +1,9 @@
fun foo(p: (String) -> Unit){}
fun bar() {
foo { (p:<caret> }
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ':'
@@ -0,0 +1,9 @@
fun bar() {
val handler = { p<caret>
foo()
}
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ' '
@@ -0,0 +1,9 @@
fun bar() {
val handler = { p <caret>
foo()
}
}
// INVOCATION_COUNT: 0
// ELEMENT: *
// CHAR: ' '
@@ -126,6 +126,24 @@ public class CompletionCharFilterTestGenerated extends AbstractCompletionCharFil
doTest(fileName);
}
@TestMetadata("FunctionLiteralParameter1.kt")
public void testFunctionLiteralParameter1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt");
doTest(fileName);
}
@TestMetadata("FunctionLiteralParameter2.kt")
public void testFunctionLiteralParameter2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt");
doTest(fileName);
}
@TestMetadata("FunctionLiteralParameter3.kt")
public void testFunctionLiteralParameter3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt");
doTest(fileName);
}
@TestMetadata("FunctionWithLambdaArg1.kt")
public void testFunctionWithLambdaArg1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionWithLambdaArg1.kt");