KT-12447 Don't use CompletionProgressIndicator in Kotlin plugin

#KT-12447 Fixed
This commit is contained in:
Valentin Kipyatkov
2016-06-16 20:35:40 +03:00
parent 4e16d67321
commit 962a8f9bf4
5 changed files with 61 additions and 92 deletions
@@ -23,8 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.template.TemplateManager
import com.intellij.patterns.PatternCondition
import com.intellij.patterns.StandardPatterns
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.ProcessingContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -119,11 +118,28 @@ class BasicCompletionSession(
lookupElement.putUserData(LookupCancelWatcher.AUTO_POPUP_AT, position.startOffset)
lookupElement
}
if (isInFunctionLiteralStart(position)) {
collector.addLookupElementPostProcessor { lookupElement ->
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
lookupElement
}
}
}
completionKind.doComplete()
}
private fun isInFunctionLiteralStart(position: PsiElement): Boolean {
var prev = position.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
if (prev?.node?.elementType == KtTokens.LPAR) {
prev = prev?.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
}
if (prev?.node?.elementType != KtTokens.LBRACE) return false
val functionLiteral = prev!!.parent as? KtFunctionLiteral ?: return false
return functionLiteral.lBrace == prev
}
override fun createSorter(): CompletionSorter {
var sorter = super.createSorter()
@@ -16,12 +16,9 @@
package org.jetbrains.kotlin.idea.completion
import com.intellij.codeInsight.completion.CompletionProgressIndicator
import com.intellij.codeInsight.completion.CompletionService
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.codeInsight.completion.PrefixMatcher
import com.intellij.codeInsight.lookup.*
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.Key
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.StandardPatterns
@@ -107,17 +104,6 @@ fun LookupElement.keepOldArgumentListOnTab(): LookupElement {
return this
}
fun rethrowWithCancelIndicator(exception: ProcessCanceledException): ProcessCanceledException {
val indicator = CompletionService.getCompletionService().currentCompletion as CompletionProgressIndicator
// Force cancel to avoid deadlock in CompletionThreading.delegateWeighing()
if (!indicator.isCanceled) {
indicator.cancel()
}
return exception
}
fun PrefixMatcher.asNameFilter(): (Name) -> Boolean {
return { name -> !name.isSpecial && prefixMatches(name.identifier) }
}
@@ -16,19 +16,11 @@
package org.jetbrains.kotlin.idea.completion
import com.intellij.codeInsight.completion.CompletionProgressIndicator
import com.intellij.codeInsight.completion.CompletionService
import com.intellij.codeInsight.lookup.CharFilter
import com.intellij.codeInsight.lookup.CharFilter.Result
import com.intellij.codeInsight.lookup.Lookup
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
class KotlinCompletionCharFilter() : CharFilter() {
companion object {
@@ -43,10 +35,7 @@ class KotlinCompletionCharFilter() : CharFilter() {
override fun acceptChar(c : Char, prefixLength : Int, lookup : Lookup) : Result? {
if (lookup.psiFile !is KtFile) return null
if (!lookup.isCompletion) return null
// it does not work in tests, so we use other way
// val isAutopopup = CompletionService.getCompletionService().getCurrentCompletion().isAutopopupCompletion()
val completionParameters = (CompletionService.getCompletionService().currentCompletion as CompletionProgressIndicator).parameters
val isAutopopup = completionParameters.invocationCount == 0
val isAutopopup = CompletionService.getCompletionService().currentCompletion!!.isAutopopupCompletion
if (Character.isJavaIdentifierPart(c) || c == '@') {
return CharFilter.Result.ADD_TO_PREFIX
@@ -55,8 +44,7 @@ class KotlinCompletionCharFilter() : CharFilter() {
val currentItem = lookup.currentItem
// do not accept items by special chars in some special positions such as in the very beginning of function literal where name of the first parameter can be
if (isAutopopup && !lookup.isSelectionTouched
&& (currentItem?.getUserData(SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING) != null || isInFunctionLiteralStart(completionParameters.position))) {
if (isAutopopup && !lookup.isSelectionTouched && currentItem?.getUserData(SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING) != null) {
return Result.HIDE_LOOKUP
}
@@ -94,14 +82,4 @@ class KotlinCompletionCharFilter() : CharFilter() {
else -> CharFilter.Result.HIDE_LOOKUP
}
}
private fun isInFunctionLiteralStart(position: PsiElement): Boolean {
var prev = position.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
if (prev?.node?.elementType == KtTokens.LPAR) {
prev = prev?.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment }
}
if (prev?.node?.elementType != KtTokens.LBRACE) return false
val functionLiteral = prev!!.parent as? KtFunctionLiteral ?: return false
return functionLiteral.lBrace == prev
}
}
@@ -284,44 +284,39 @@ class KotlinCompletionContributor : CompletionContributor() {
}
}
try {
result.restartCompletionWhenNothingMatches()
result.restartCompletionWhenNothingMatches()
val configuration = CompletionSessionConfiguration(parameters)
if (parameters.completionType == CompletionType.BASIC) {
val session = BasicCompletionSession(configuration, parameters, toFromOriginalFileMapper, result)
val configuration = CompletionSessionConfiguration(parameters)
if (parameters.completionType == CompletionType.BASIC) {
val session = BasicCompletionSession(configuration, parameters, toFromOriginalFileMapper, result)
addPostProcessor(session)
addPostProcessor(session)
if (parameters.isAutoPopup && session.shouldDisableAutoPopup()) {
result.stopHere()
return
}
val somethingAdded = session.complete()
if (!somethingAdded && parameters.invocationCount < 2) {
// Rerun completion if nothing was found
val newConfiguration = CompletionSessionConfiguration(
useBetterPrefixMatcherForNonImportedClasses = false,
completeNonAccessibleDeclarations = false,
filterOutJavaGettersAndSetters = false,
completeJavaClassesNotToBeUsed = false,
completeStaticMembers = parameters.invocationCount > 0
)
val newSession = BasicCompletionSession(newConfiguration, parameters, toFromOriginalFileMapper, result)
addPostProcessor(newSession)
newSession.complete()
}
if (parameters.isAutoPopup && session.shouldDisableAutoPopup()) {
result.stopHere()
return
}
else {
val session = SmartCompletionSession(configuration, parameters, toFromOriginalFileMapper, result)
addPostProcessor(session)
session.complete()
val somethingAdded = session.complete()
if (!somethingAdded && parameters.invocationCount < 2) {
// Rerun completion if nothing was found
val newConfiguration = CompletionSessionConfiguration(
useBetterPrefixMatcherForNonImportedClasses = false,
completeNonAccessibleDeclarations = false,
filterOutJavaGettersAndSetters = false,
completeJavaClassesNotToBeUsed = false,
completeStaticMembers = parameters.invocationCount > 0
)
val newSession = BasicCompletionSession(newConfiguration, parameters, toFromOriginalFileMapper, result)
addPostProcessor(newSession)
newSession.complete()
}
}
catch (e: ProcessCanceledException) {
throw rethrowWithCancelIndicator(e)
else {
val session = SmartCompletionSession(configuration, parameters, toFromOriginalFileMapper, result)
addPostProcessor(session)
session.complete()
}
}
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.completion
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.PlainPrefixMatcher
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.patterns.PlatformPatterns
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType
@@ -44,29 +43,24 @@ object PackageDirectiveCompletion {
val expression = file.findElementAt(parameters.offset)?.parent as? KtSimpleNameExpression ?: return false
try {
val prefixLength = parameters.offset - expression.textOffset
val prefix = expression.text!!
val prefixMatcher = PlainPrefixMatcher(prefix.substring(0, prefixLength))
val result = result.withPrefixMatcher(prefixMatcher)
val prefixLength = parameters.offset - expression.textOffset
val prefix = expression.text!!
val prefixMatcher = PlainPrefixMatcher(prefix.substring(0, prefixLength))
val result = result.withPrefixMatcher(prefixMatcher)
val resolutionFacade = expression.getResolutionFacade()
val resolutionFacade = expression.getResolutionFacade()
val packageMemberScope = resolutionFacade.moduleDescriptor.getPackage(file.packageFqName.parent()).memberScope
val packageMemberScope = resolutionFacade.moduleDescriptor.getPackage(file.packageFqName.parent()).memberScope
val variants = packageMemberScope.getContributedDescriptors(DescriptorKindFilter.PACKAGES, prefixMatcher.asNameFilter())
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.PACKAGE_DIRECTIVE, expectedInfosCalculator = { emptyList() }))
for (variant in variants) {
val lookupElement = lookupElementFactory.createLookupElement(variant)
if (!lookupElement.lookupString.contains(DUMMY_IDENTIFIER)) {
result.addElement(lookupElement)
}
val variants = packageMemberScope.getContributedDescriptors(DescriptorKindFilter.PACKAGES, prefixMatcher.asNameFilter())
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.PACKAGE_DIRECTIVE, expectedInfosCalculator = { emptyList() }))
for (variant in variants) {
val lookupElement = lookupElementFactory.createLookupElement(variant)
if (!lookupElement.lookupString.contains(DUMMY_IDENTIFIER)) {
result.addElement(lookupElement)
}
}
return true
}
catch (e: ProcessCanceledException) {
throw rethrowWithCancelIndicator(e)
}
return true
}
}