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:
Valentin Kipyatkov
2014-11-13 17:47:04 +03:00
parent f36208718e
commit 3ebc681eec
52 changed files with 447 additions and 96 deletions
@@ -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))
@@ -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)
}
}