mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-46668 Impl multiple arguments completion contributor
(cherry picked from commit 42efe6a20f52cfb3bd827a2b68d1fb6cc3949626) IJ-MR-5791 GitOrigin-RevId: e2a40572b0de4919a5049ff06e437b34d78c296c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b4eceba7a8
commit
a350ff045f
@@ -109,6 +109,8 @@
|
||||
implementationClass="com.jetbrains.python.codeInsight.completion.PyModulePackageCompletionContributor"/>
|
||||
<completion.contributor language="Python"
|
||||
implementationClass="com.jetbrains.python.codeInsight.completion.PyFStringLikeCompletionContributor"/>
|
||||
<completion.contributor language="Python"
|
||||
implementationClass="com.jetbrains.python.codeInsight.completion.PyMultipleArgumentsCompletionContributor"/>
|
||||
|
||||
<lang.tokenSeparatorGenerator language="Python" implementationClass="com.jetbrains.python.PyTokenSeparatorGenerator"/>
|
||||
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.jetbrains.python.codeInsight.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.PlatformIcons
|
||||
import com.intellij.util.ProcessingContext
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
|
||||
import com.jetbrains.python.extensions.inArgumentList
|
||||
import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext
|
||||
import com.jetbrains.python.psi.types.PyCallableParameter
|
||||
|
||||
class PyMultipleArgumentsCompletionContributor: CompletionContributor() {
|
||||
init {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inArgumentList(), MyCompletionProvider)
|
||||
}
|
||||
|
||||
private object MyCompletionProvider : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||
val position = parameters.position
|
||||
val argumentIndex = getArgumentIndex(position) ?: return
|
||||
|
||||
val call = PsiTreeUtil.getParentOfType(position, PyCallExpression::class.java) ?: return
|
||||
val typeEvalContext = parameters.getTypeEvalContext()
|
||||
val resolveContext = PyResolveContext.defaultContext().withTypeEvalContext(typeEvalContext)
|
||||
val callableTypes = call.multiResolveCallee(resolveContext)
|
||||
if (callableTypes.isEmpty()) return
|
||||
|
||||
val scopeOwner = ScopeUtil.getScopeOwner(position) ?: return
|
||||
val names = collectNames(scopeOwner, position)
|
||||
|
||||
callableTypes.forEach { callableType ->
|
||||
val callableParameters = callableType.getParameters(typeEvalContext)
|
||||
if (callableParameters == null || callableParameters.any { it.isKeywordContainer || it.isPositionalContainer }) return@forEach
|
||||
|
||||
val unfilledParameters = ContainerUtil.subList(callableParameters, argumentIndex + callableType.implicitOffset)
|
||||
val variables = collectVariablesToComplete(unfilledParameters, names)
|
||||
if (variables.size > 1) {
|
||||
result.addElement(createParametersLookupElement(variables, call))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val MULTIPLE_ARGUMENTS_VARIANT_KEY: Key<Boolean> = Key.create("py.multiple.arguments.completion.variant")
|
||||
|
||||
private fun getArgumentIndex(position: PsiElement): Int? {
|
||||
val argumentList = PsiTreeUtil.getParentOfType(position, PyArgumentList::class.java) ?: return null
|
||||
if (argumentList.arguments.any { it is PyKeywordArgument || it is PyStarArgument }) return null
|
||||
if (!PsiTreeUtil.isAncestor(argumentList.arguments.last(), position, false)) return null
|
||||
return argumentList.arguments.size - 1
|
||||
}
|
||||
|
||||
private fun createParametersLookupElement(variables: List<String>, call: PyCallExpression): LookupElement {
|
||||
return LookupElementBuilder.create(variables.joinToString(", "))
|
||||
.withIcon(PlatformIcons.VARIABLE_ICON)
|
||||
.withInsertHandler(PyMultipleArgumentsInsertHandler(call))
|
||||
.apply {
|
||||
putUserData(MULTIPLE_ARGUMENTS_VARIANT_KEY, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectVariablesToComplete(parameters: List<PyCallableParameter>, argumentsNames: Set<String>): List<String> {
|
||||
val variables = mutableListOf<String>()
|
||||
var keywordsOnlyFlag = false
|
||||
|
||||
for (parameter in parameters) {
|
||||
if (parameter.parameter is PySlashParameter) continue
|
||||
if (parameter.parameter is PySingleStarParameter) {
|
||||
keywordsOnlyFlag = true
|
||||
continue
|
||||
}
|
||||
|
||||
val paramName = parameter.name ?: return emptyList()
|
||||
if (paramName in argumentsNames) {
|
||||
if (!keywordsOnlyFlag) {
|
||||
variables.add(paramName)
|
||||
}
|
||||
else {
|
||||
variables.add("$paramName=$paramName")
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!parameter.hasDefaultValue()) return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
return variables
|
||||
}
|
||||
|
||||
private fun collectNames(scope: ScopeOwner, position: PsiElement): Set<String> =
|
||||
ControlFlowCache.getScope(scope).namedElements
|
||||
.asSequence()
|
||||
.filter { element ->
|
||||
PsiTreeUtil.getParentOfType(element, PyListCompExpression::class.java) ?.let { listComp ->
|
||||
PsiTreeUtil.isAncestor(listComp.resultExpression, position, false)
|
||||
} ?: PyPsiUtils.isBefore(element, position)
|
||||
}
|
||||
.mapNotNull { it.name }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
class PyMultipleArgumentsInsertHandler(private val call: PyCallExpression): ParenthesesInsertHandler<LookupElement>() {
|
||||
override fun placeCaretInsideParentheses(context: InsertionContext?, item: LookupElement?): Boolean = false
|
||||
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val editor = context.editor
|
||||
context.commitDocument()
|
||||
if (call.argumentList?.closingParen == null) {
|
||||
editor.document.insertString(context.tailOffset, ")")
|
||||
editor.caretModel.moveToOffset(context.tailOffset)
|
||||
}
|
||||
else {
|
||||
editor.caretModel.moveToOffset(context.tailOffset + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -37,6 +37,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class PythonCompletionWeigher extends CompletionWeigher {
|
||||
|
||||
public static final int PRIORITY_WEIGHT = 5;
|
||||
public static final int WEIGHT_FOR_MULTIPLE_ARGUMENTS = 5;
|
||||
public static final int WEIGHT_FOR_KEYWORDS = 0;
|
||||
private static final Logger LOG = Logger.getInstance(PythonCompletionWeigher.class);
|
||||
public static final String COLLECTION_KEY = "dict key";
|
||||
@@ -71,6 +72,10 @@ public class PythonCompletionWeigher extends CompletionWeigher {
|
||||
return WEIGHT_FOR_KEYWORDS;
|
||||
}
|
||||
|
||||
if (element.getUserData(PyMultipleArgumentsCompletionContributor.Companion.getMULTIPLE_ARGUMENTS_VARIANT_KEY()) != null) {
|
||||
return WEIGHT_FOR_MULTIPLE_ARGUMENTS;
|
||||
}
|
||||
|
||||
return PyCompletionUtilsKt.FALLBACK_WEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.patterns.PlatformPatterns.psiElement
|
||||
import com.intellij.patterns.PsiElementPattern
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.jetbrains.python.PythonLanguage
|
||||
import com.jetbrains.python.psi.PyArgumentList
|
||||
import com.jetbrains.python.psi.PyClass
|
||||
import com.jetbrains.python.psi.PyFunction
|
||||
import com.jetbrains.python.psi.PyParameterList
|
||||
@@ -28,3 +29,6 @@ fun PsiElementPattern.Capture<*>.afterDefInFunction(): PsiElementPattern.Capture
|
||||
|
||||
fun PsiElementPattern.Capture<*>.inParameterList(): PsiElementPattern.Capture<out PsiElement> =
|
||||
withLanguage(PythonLanguage.getInstance()).and(psiElement().inside(PyParameterList::class.java))
|
||||
|
||||
fun PsiElementPattern.Capture<*>.inArgumentList(): PsiElementPattern.Capture<out PsiElement> =
|
||||
withLanguage(PythonLanguage.getInstance()).and(psiElement().inside(PyArgumentList::class.java))
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.completion.ml.ContextFeatures
|
||||
import com.intellij.codeInsight.completion.ml.ElementFeatureProvider
|
||||
import com.intellij.codeInsight.completion.ml.MLFeatureValue
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.jetbrains.python.codeInsight.completion.PyMultipleArgumentsCompletionContributor
|
||||
import com.jetbrains.python.codeInsight.mlcompletion.prev2calls.PyPrevCallsCompletionFeatures
|
||||
import com.jetbrains.python.psi.PyParameter
|
||||
|
||||
@@ -100,6 +101,10 @@ class PyElementFeatureProvider : ElementFeatureProvider {
|
||||
}}
|
||||
}
|
||||
|
||||
element.getUserData(PyMultipleArgumentsCompletionContributor.MULTIPLE_ARGUMENTS_VARIANT_KEY)?.let {
|
||||
result["is_multiple_arguments"] = MLFeatureValue.binary(true)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(bar, baz):
|
||||
pass
|
||||
|
||||
|
||||
def main(bar):
|
||||
for baz in []:
|
||||
foo(bar, baz)<caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(bar, baz):
|
||||
pass
|
||||
|
||||
|
||||
def main(bar):
|
||||
for baz in []:
|
||||
foo(<caret>)
|
||||
@@ -0,0 +1,12 @@
|
||||
class Foo:
|
||||
def __init__(self, x, y, z):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
|
||||
def foo():
|
||||
x = 1
|
||||
y = 2
|
||||
z = 3
|
||||
return Foo(x, y, z)<caret>
|
||||
@@ -0,0 +1,12 @@
|
||||
class Foo:
|
||||
def __init__(self, x, y, z):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
|
||||
def foo():
|
||||
x = 1
|
||||
y = 2
|
||||
z = 3
|
||||
return Foo(<caret>)
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo:
|
||||
def foo(self, x, y, z):
|
||||
pass
|
||||
|
||||
def bar(self):
|
||||
x = 1
|
||||
y = 2
|
||||
z = 3
|
||||
self.foo(x, y, z)<caret>
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo:
|
||||
def foo(self, x, y, z):
|
||||
pass
|
||||
|
||||
def bar(self):
|
||||
x = 1
|
||||
y = 2
|
||||
z = 3
|
||||
self.foo(<caret>)
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
z = 22
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(x, y, z)<caret>
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
z = 22
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(x, <caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, y):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(x, y)<caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, y):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
@@ -0,0 +1,6 @@
|
||||
def foo(bar, baz):
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
return [foo(bar, baz)<caret> for bar, baz in []]
|
||||
@@ -0,0 +1,6 @@
|
||||
def foo(bar, baz):
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
return [foo(<caret>) for bar, baz in []]
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
z = 42
|
||||
foo(x, <caret>, z)
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
z = 33
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
z = 33
|
||||
def bar():
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
def bar():
|
||||
z = 33
|
||||
def baz():
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
@@ -0,0 +1,5 @@
|
||||
def foo(x, y=42)
|
||||
pass
|
||||
|
||||
x = 42
|
||||
foo(<caret>)
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, y, z):
|
||||
z = 42
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>)
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
z = 42
|
||||
foo(x=<caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, **y):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 22
|
||||
foo(<caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
def foo(x, *y):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 22
|
||||
foo(<caret>
|
||||
@@ -0,0 +1,24 @@
|
||||
from typing import overload, Any
|
||||
|
||||
|
||||
@overload
|
||||
def bar(a: int, b: int) -> None:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def bar(c: str, d: str) -> None:
|
||||
...
|
||||
|
||||
|
||||
def bar(*args: Any, **kwargs: Any) -> None:
|
||||
...
|
||||
|
||||
|
||||
def foo():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
|
||||
bar(<caret>)
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(a, *, b):
|
||||
print(a, b)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
foo(a, b=b)<caret>
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(a, *, b):
|
||||
print(a, b)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
foo(<caret>)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(x, y)<caret>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
z = 42
|
||||
def bar():
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(x, y)<caret>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
z = 42
|
||||
def bar():
|
||||
x = 42
|
||||
y = 100500
|
||||
foo(<caret>
|
||||
@@ -0,0 +1,9 @@
|
||||
def foo(a, /, b, *, c):
|
||||
print(a, b, c)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
foo(a, b, c=c)<caret>
|
||||
@@ -0,0 +1,9 @@
|
||||
def foo(a, /, b, *, c):
|
||||
print(a, b, c)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
foo(<caret>
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(a, /, b):
|
||||
print(a, b)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
foo(a, b)<caret>
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(a, /, b):
|
||||
print(a, b)
|
||||
|
||||
|
||||
def egg():
|
||||
a = 1
|
||||
b = 2
|
||||
foo(<caret>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
z = 42
|
||||
foo(x, y, z)<caret>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
def foo(x, y, z=42):
|
||||
pass
|
||||
|
||||
|
||||
x = 42
|
||||
y = 100500
|
||||
z = 42
|
||||
foo(<caret>
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.python
|
||||
|
||||
import com.intellij.codeInsight.lookup.Lookup
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
|
||||
class PyMultipleArgumentsCompletionTest: PyTestCase() {
|
||||
fun testFunctionWithTwoArgs() {
|
||||
doTestVariantsContainFinished("x, y")
|
||||
}
|
||||
|
||||
fun testFunctionWithThreeArgsTwoSuggested() {
|
||||
doTestVariantsContainFinished("y, z")
|
||||
}
|
||||
|
||||
fun testSuggestArgumentsForParametersWithDefaultValue() {
|
||||
doTestVariantsContainFinished("x, y, z")
|
||||
}
|
||||
|
||||
fun testSkipArgumentsForParametersWithDefaultValue() {
|
||||
doTestVariantsContainFinished("x, y")
|
||||
}
|
||||
|
||||
fun testSkipDefaultValueIfNotFromFunctionContext() {
|
||||
doTestVariantsContainFinished("x, y")
|
||||
}
|
||||
|
||||
fun testClassConstructor() {
|
||||
doTestVariantsContainFinished("x, y, z")
|
||||
}
|
||||
|
||||
fun testClassMember() {
|
||||
doTestVariantsContainFinished("x, y, z")
|
||||
}
|
||||
|
||||
fun testArgumentParameter() {
|
||||
doTestVariantsContainFinished("bar, baz")
|
||||
}
|
||||
|
||||
fun testListComprehension() {
|
||||
doTestVariantsContainFinished("bar, baz")
|
||||
}
|
||||
|
||||
fun testOverloads() {
|
||||
doTestVariantsContain("a, b", "c, d")
|
||||
}
|
||||
|
||||
fun testSingleStarParameter() {
|
||||
doTestVariantsContainFinished("a, b=b")
|
||||
}
|
||||
|
||||
fun testSlashParameter() {
|
||||
doTestVariantsContainFinished("a, b")
|
||||
}
|
||||
|
||||
fun testSlashAndSingleStarParameter() {
|
||||
doTestVariantsContainFinished("a, b, c=c")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfNotEnoughArguments() {
|
||||
doTestVariantsNotContain("x, y", "x, y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfNotEnoughArgumentsBeforeCaret() {
|
||||
doTestVariantsNotContain("x, y", "x, y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfNotEnoughArgumentsInTheScopeOfFunction() {
|
||||
doTestVariantsNotContain("x, y", "x, y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfNotEnoughArgumentsInTheScopeOfNestedFunction() {
|
||||
doTestVariantsNotContain("x, y", "x, y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfTargetOutOfScopeFunction() {
|
||||
doTestVariantsNotContain("x, y", "x, y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfHaveArgumentsRight() {
|
||||
doTestVariantsNotContain("y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestInKeywordArgument() {
|
||||
doTestVariantsNotContain("x, y, z", "y, z")
|
||||
}
|
||||
|
||||
fun testNotSuggestKeywordContainer() {
|
||||
doTestVariantsNotContain("x, y")
|
||||
}
|
||||
|
||||
fun testNotSuggestPositionalContainer() {
|
||||
doTestVariantsNotContain("x, y")
|
||||
}
|
||||
|
||||
fun testNotSuggestIfOnlyOneVariable() {
|
||||
assertEquals(1, doTestByTestName().count { it == "x" })
|
||||
}
|
||||
|
||||
private fun doTestByTestName(): List<String?> {
|
||||
val testName = "multipleArgumentsCompletion/${getTestName(true)}"
|
||||
myFixture.configureByFile("$testName.py")
|
||||
myFixture.completeBasic()
|
||||
return myFixture.lookupElementStrings!!
|
||||
}
|
||||
|
||||
private fun doTestVariantsContain(vararg elements: String) = assertContainsElements(doTestByTestName(), *elements)
|
||||
|
||||
private fun doTestVariantsContainFinished(element: String) {
|
||||
doTestVariantsContain(element)
|
||||
myFixture.lookup.currentItem = myFixture.lookupElements.find { it.lookupString == element }
|
||||
myFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR)
|
||||
myFixture.checkResultByFile("multipleArgumentsCompletion/${getTestName(true)}.after.py")
|
||||
}
|
||||
|
||||
private fun doTestVariantsNotContain(vararg elements: String) = assertDoesntContain(doTestByTestName(), *elements)
|
||||
}
|
||||
Reference in New Issue
Block a user