PY-47254 Don't duplicate already imported module names in completion

By running the completion contributor for non-imported modules after everything
else, including the LegacyCompletionContributor offering names present in
the scope, and filtering out duplicate variants.

GitOrigin-RevId: 98982b2c33d1fc11d70b144de556a6825bd3febc
This commit is contained in:
Mikhail Golubev
2022-02-23 11:55:12 +00:00
committed by intellij-monorepo-bot
parent 329030f0b1
commit ff82f4e058
5 changed files with 24 additions and 9 deletions
@@ -120,7 +120,7 @@
implementationClass="com.jetbrains.python.codeInsight.completion.PyClassNameCompletionContributor"/>
<completion.contributor language="Python"
implementationClass="com.jetbrains.python.codeInsight.completion.PyModulePackageCompletionContributor"/>
<completion.contributor language="Python"
<completion.contributor language="Python" order="first"
implementationClass="com.jetbrains.python.codeInsight.completion.PyModuleNameCompletionContributor"/>
<completion.contributor language="Python"
implementationClass="com.jetbrains.python.codeInsight.completion.PyUnresolvedModuleAttributeCompletionContributor"/>
@@ -4,7 +4,7 @@ package com.jetbrains.python.codeInsight.completion
import com.intellij.codeInsight.completion.CompletionContributor
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.project.DumbAware
import com.intellij.psi.MultiplePsiFilesPerDocumentFileViewProvider
import com.intellij.psi.PsiDirectory
@@ -41,19 +41,24 @@ class PyModuleNameCompletionContributor : CompletionContributor(), DumbAware {
*/
override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) {
if (!shouldDoCompletion(parameters)) return
doFillCompletionVariants(parameters, result)
val otherVariants = mutableSetOf<String>()
result.runRemainingContributors(parameters) {
otherVariants.add(it.lookupElement.lookupString)
result.passResult(it)
}
doFillCompletionVariants(parameters, result, otherVariants)
}
fun doFillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) {
getCompletionVariants(parameters.position.parent, parameters.originalFile).asSequence()
.filterIsInstance<LookupElementBuilder>()
.filter { result.prefixMatcher.prefixMatches(it.lookupString) }
private fun doFillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet, otherVariants: Set<String>) {
getCompletionVariants(parameters.position.parent, parameters.originalFile, otherVariants).asSequence()
.filterIsInstance<LookupElement>()
.filterNot { it.lookupString.startsWith('_') }
.forEach { result.addElement(it) }
}
private fun getCompletionVariants(element: PsiElement, file: PsiElement): List<Any> {
val alreadyAddedNames = HashSet<String>()
private fun getCompletionVariants(element: PsiElement, file: PsiElement, otherVariants: Set<String>): List<Any> {
val alreadyAddedNames = HashSet<String>(otherVariants)
val result = ArrayList<Any>()
resolveQualifiedName(QualifiedName.fromComponents(), fromFoothold(file))
.asSequence()
@@ -2,6 +2,7 @@
package com.jetbrains.python;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.stubs.PyQualifiedNameCompletionMatcher.QualifiedNameMatcher;
import org.jetbrains.annotations.Nullable;
@@ -166,6 +167,12 @@ public class PyNotImportedQualifiedNameCompletionTest extends PyTestCase {
assertContainsElements(doBasicCompletion(), "pytest.mark", "pytest.param");
}
// PY-47254
public void testAlreadyImportedModulesNotSuggestedTwice() {
List<String> variants = doBasicCompletion();
assertEquals(1, ContainerUtil.count(variants, "foo"::equals));
}
@Nullable
private List<String> doBasicCompletion() {
myFixture.copyDirectoryToProject(getTestName(false), "");