Behavior on typing chars with code completion lookup is completely defined by our own handler + added tests for this handler + fixed a few bugs related to this behavior
This commit is contained in:
@@ -25,17 +25,22 @@ import com.intellij.openapi.util.Key
|
||||
|
||||
public class KotlinCompletionCharFilter() : CharFilter() {
|
||||
class object {
|
||||
public val ACCEPT_OPENING_BRACE: Key<Boolean> = Key<Boolean>("KotlinCompletionCharFilter.ACCEPT_OPENNING_BRACE")
|
||||
public val ACCEPT_EQ: Key<Boolean> = Key<Boolean>("KotlinCompletionCharFilter.ACCEPT_EQ")
|
||||
public val ACCEPT_OPENING_BRACE: Key<Boolean> = Key("KotlinCompletionCharFilter.ACCEPT_OPENNING_BRACE")
|
||||
public val ACCEPT_EQ: Key<Boolean> = Key("KotlinCompletionCharFilter.ACCEPT_EQ")
|
||||
}
|
||||
|
||||
public override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
|
||||
if (lookup.getPsiFile() !is JetFile) return null
|
||||
if (!lookup.isCompletion()) return null
|
||||
|
||||
if (Character.isJavaIdentifierPart(c) || c == ':' /* used in '::xxx'*/) return CharFilter.Result.ADD_TO_PREFIX
|
||||
if (Character.isJavaIdentifierPart(c) || c == ':' /* used in '::xxx'*/) {
|
||||
return CharFilter.Result.ADD_TO_PREFIX
|
||||
}
|
||||
|
||||
val currentItem = lookup.getCurrentItem()
|
||||
return when (c) {
|
||||
'.' -> {
|
||||
//TODO: this heuristics better to be only used for auto-popup completion but I see no way to check this
|
||||
if (prefixLength == 0 && !lookup.isSelectionTouched()) {
|
||||
val caret = lookup.getEditor().getCaretModel().getOffset()
|
||||
if (caret > 0 && lookup.getEditor().getDocument().getCharsSequence()[caret - 1] == '.') {
|
||||
@@ -45,8 +50,7 @@ public class KotlinCompletionCharFilter() : CharFilter() {
|
||||
Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||
}
|
||||
|
||||
'(' -> {
|
||||
val currentItem = lookup.getCurrentItem()
|
||||
'{' -> {
|
||||
if (currentItem != null && currentItem.getUserData(ACCEPT_OPENING_BRACE) ?: false)
|
||||
Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||
else
|
||||
@@ -54,14 +58,13 @@ public class KotlinCompletionCharFilter() : CharFilter() {
|
||||
}
|
||||
|
||||
'=' -> {
|
||||
val currentItem = lookup.getCurrentItem()
|
||||
if (currentItem != null && currentItem.getUserData(ACCEPT_EQ) ?: false)
|
||||
Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||
else
|
||||
Result.HIDE_LOOKUP
|
||||
Result.HIDE_LOOKUP //TODO: why not for others?
|
||||
}
|
||||
|
||||
',', ' ' -> Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||
',', ' ', '(' -> Result.SELECT_ITEM_AND_FINISH_LOOKUP
|
||||
|
||||
else -> return CharFilter.Result.HIDE_LOOKUP
|
||||
}
|
||||
|
||||
@@ -88,14 +88,14 @@ public object KotlinLookupElementFactory {
|
||||
val insertHandler = getDefaultInsertHandler(descriptor)
|
||||
element = element.withInsertHandler(insertHandler)
|
||||
|
||||
if (insertHandler is JetFunctionInsertHandler && insertHandler.lambdaInfo != null) {
|
||||
element.putUserData<Boolean>(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||
}
|
||||
|
||||
element = element.withTailText(tailText, true).withTypeText(typeText).withPresentableText(presentableText)
|
||||
element = element.withIcon(JetDescriptorIconProvider.getIcon(descriptor, declaration, Iconable.ICON_FLAG_VISIBILITY))
|
||||
element = element.withStrikeoutness(KotlinBuiltIns.getInstance().isDeprecated(descriptor))
|
||||
|
||||
if (insertHandler is JetFunctionInsertHandler && insertHandler.lambdaInfo != null) {
|
||||
element.putUserData<Boolean>(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||
}
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ object NamedParametersCompletion {
|
||||
val name = parameter.getName()
|
||||
val nameString = name.asString()
|
||||
if (nameString !in usedArguments) {
|
||||
val text = "$nameString ="
|
||||
val lookupElement = LookupElementBuilder.create(text)
|
||||
val lookupElement = LookupElementBuilder.create(nameString)
|
||||
.withPresentableText("$nameString =")
|
||||
.withTailText(" ${DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(parameter.getType())}")
|
||||
.withIcon(JetIcons.PARAMETER)
|
||||
.withInsertHandler(NamedParameterInsertHandler(name))
|
||||
|
||||
+3
-3
@@ -126,13 +126,13 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
|
||||
}
|
||||
|
||||
private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) {
|
||||
if (context.getCompletionChar() == '(') { //TODO: more correct behavior related to braces type
|
||||
val completionChar = context.getCompletionChar()
|
||||
if (completionChar == '(') { //TODO: more correct behavior related to braces type
|
||||
context.setAddCompletionChar(false)
|
||||
}
|
||||
|
||||
val offset = context.getTailOffset()
|
||||
val document = context.getDocument()
|
||||
val completionChar = context.getCompletionChar()
|
||||
|
||||
val forceParenthesis = lambdaInfo != null && completionChar == '\t' && document.getCharsSequence().charAt(offset) == '('
|
||||
val braces = lambdaInfo != null && completionChar != '(' && !forceParenthesis
|
||||
@@ -168,7 +168,7 @@ public class JetFunctionInsertHandler(val caretPosition : CaretPosition, val lam
|
||||
val closeBracketOffset = indexOfSkippingSpace(document, closingBracket, openingBracketOffset + 1)
|
||||
val editor = context.getEditor()
|
||||
|
||||
var forcePlaceCaretIntoParentheses : Boolean = completionChar == '('
|
||||
var forcePlaceCaretIntoParentheses = completionChar == '('
|
||||
|
||||
if (caretPosition == CaretPosition.IN_BRACKETS || forcePlaceCaretIntoParentheses || closeBracketOffset == -1) {
|
||||
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
||||
|
||||
@@ -30,9 +30,13 @@ class WithTailInsertHandler(val tailText: String,
|
||||
val spaceAfter: Boolean,
|
||||
val overwriteText: Boolean = true) : InsertHandler<LookupElement> {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val document = context.getDocument()
|
||||
|
||||
item.handleInsert(context)
|
||||
|
||||
if (tailText == context.getCompletionChar().toString() && context.shouldAddCompletionChar()) {
|
||||
return
|
||||
}
|
||||
|
||||
val document = context.getDocument()
|
||||
PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(document)
|
||||
|
||||
var tailOffset = context.getTailOffset()
|
||||
|
||||
@@ -39,7 +39,6 @@ object LambdaItems {
|
||||
.suppressAutoInsertion()
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA_NO_PARAMS)
|
||||
.addTailAndNameSimilarity(functionExpectedInfos)
|
||||
lookupElement.putUserData(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||
collection.add(lookupElement)
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@ object LambdaItems {
|
||||
.suppressAutoInsertion()
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA)
|
||||
.addTailAndNameSimilarity(functionExpectedInfos.filter { it.type == functionType })
|
||||
lookupElement.putUserData(KotlinCompletionCharFilter.ACCEPT_OPENING_BRACE, true)
|
||||
collection.add(lookupElement)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user