diff --git a/gradle.properties b/gradle.properties index 4dc5164..2ceac84 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,16 +2,16 @@ pluginGroup = space.whitememory.pythoninlayparams pluginName = Python Inlay Params pluginRepositoryUrl = https://github.com/WhiteMemory99/Intellij-Python-Inlay-Params -pluginVersion = 0.3.4 +pluginVersion = 1.0.0 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. -pluginSinceBuild = 223 -pluginUntilBuild = 233.* +pluginSinceBuild = 231 +pluginUntilBuild = 241.* # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType = PC -platformVersion = 2022.3.3 +platformVersion = 2023.1 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 @@ -30,4 +30,4 @@ org.gradle.configuration-cache = true org.gradle.caching = true # Enable Gradle Kotlin DSL Lazy Property Assignment -> https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:assignment -systemProp.org.gradle.unsafe.kotlin.assignment = true \ No newline at end of file +systemProp.org.gradle.unsafe.kotlin.assignment = true diff --git a/src/main/kotlin/space/whitememory/pythoninlayparams/InlayHintsProvider.kt b/src/main/kotlin/space/whitememory/pythoninlayparams/InlayHintsProvider.kt new file mode 100644 index 0000000..f3b8448 --- /dev/null +++ b/src/main/kotlin/space/whitememory/pythoninlayparams/InlayHintsProvider.kt @@ -0,0 +1,112 @@ +package space.whitememory.pythoninlayparams + +import com.intellij.codeInsight.hints.declarative.* +import com.intellij.codeInsight.hints.declarative.InlayHintsProvider +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.SmartPointerManager +import com.intellij.refactoring.suggested.endOffset +import com.jetbrains.python.psi.PyTargetExpression +import com.jetbrains.python.psi.types.TypeEvalContext +import space.whitememory.pythoninlayparams.types.hints.HintGenerator +import space.whitememory.pythoninlayparams.types.hints.HintResolver +import space.whitememory.pythoninlayparams.types.hints.InlayElement + +class InlayHintsProvider : InlayHintsProvider { + companion object { + const val PROVIDER_ID = "python.implicit.types" + const val PROVIDER_NAME = "Implicit types" + } + + override fun createCollector(file: PsiFile, editor: Editor): InlayHintsCollector { + return Collector() + } + + private class Collector() : SharedBypassCollector { + + override fun collectFromElement(element: PsiElement, sink: InlayTreeSink) { + if (!element.isValid || element.project.isDefault || element !is PyTargetExpression) return + + val typeEvalContext = TypeEvalContext.codeCompletion(element.project, element.containingFile) + + if (HintResolver.resolve(element, typeEvalContext)) return + + val typeAnnotation = HintResolver.getExpressionAnnotationType(element, typeEvalContext) + val inlayHint = HintGenerator.generateTypeHintText( + element, typeAnnotation, typeEvalContext + ) + + if (inlayHint.isEmpty()) return + + sink.addPresentation( + position = InlineInlayPosition(element.endOffset, true), + hasBackground = true, + builder = { + text(": ") + + generateClickableInlayHint(this, inlayHint, createCollapsed = true) + } + ) + } + + private fun createRootInlayHint(builder: PresentationTreeBuilder, hintElement: InlayElement) { + if (hintElement.element == null) return + + builder.text( + hintElement.element.text, actionData = when (hintElement.element.psiElement) { + null -> null + else -> { + InlayActionData( + PsiPointerInlayActionPayload( + SmartPointerManager.createPointer( + hintElement.element.psiElement + ) + ), + handlerId = PsiPointerInlayActionNavigationHandler.HANDLER_ID + ) + } + } + ) + } + + private fun generateClickableInlayHint( + builder: PresentationTreeBuilder, + hintElement: InlayElement, + createCollapsed: Boolean = false + ) { + if (createCollapsed && hintElement.isTooLong()) { + return builder.collapsibleList( + state = CollapseState.Collapsed, + expandedState = { toggleButton { generateClickableInlayHint(this, hintElement) } }, + collapsedState = { + toggleButton { + createRootInlayHint(this, hintElement) + if (hintElement.isGenericType()) { + text("[...]") + } else { + text("${hintElement.inlayType.shortPrefix}[...]") + } + } + } + ) + } else { + createRootInlayHint(builder, hintElement) + } + + if (hintElement.isGenericType()) builder.text("[") + + val childrenIterator = hintElement.children.iterator() + + while (childrenIterator.hasNext()) { + generateClickableInlayHint(builder, childrenIterator.next()) + + if (childrenIterator.hasNext()) { + builder.text(hintElement.separatorType.separator) + } + } + + if (hintElement.isGenericType()) builder.text("]") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/whitememory/pythoninlayparams/types/AbstractPythonInlayTypeHintsCollector.kt b/src/main/kotlin/space/whitememory/pythoninlayparams/types/AbstractPythonInlayTypeHintsCollector.kt index 5c6f7a1..86a074a 100644 --- a/src/main/kotlin/space/whitememory/pythoninlayparams/types/AbstractPythonInlayTypeHintsCollector.kt +++ b/src/main/kotlin/space/whitememory/pythoninlayparams/types/AbstractPythonInlayTypeHintsCollector.kt @@ -34,8 +34,8 @@ abstract class AbstractPythonInlayTypeHintsCollector(editor: Editor) : return } - val resolvedHintName = resolveInlayPresentation(hintName) - displayTypeHint(element, sink, resolvedHintName) +// val resolvedHintName = resolveInlayPresentation(hintName) +// displayTypeHint(element, sink, resolvedHintName) } private fun resolveInlayPresentation( diff --git a/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintGenerator.kt b/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintGenerator.kt index e1fa4e8..dbdcbed 100644 --- a/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintGenerator.kt +++ b/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintGenerator.kt @@ -12,34 +12,16 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? { + ): InlayElement? { if (type !is PyUnionType) return null - val generatedValues = type.members - .filterNotNull() - .map { generateTypeHintText(element, it, typeEvalContext) } - .distinct() - .flatten() - - val isNoneExists = generatedValues.firstOrNull { - it.rootInlayInfo is TextInlayInfoDetail && it.rootInlayInfo.text == PyNames.NONE - } - - if (isNoneExists != null) { - return listOf( - InlayInfoDetails( - null, - generatedValues - ) - ) - } - - return listOf( - InlayInfoDetails( - null, - generatedValues, - limit = 2 - ) + return InlayElement( + children = type.members + .filterNotNull() + .map { + generateTypeHintText(element, it, typeEvalContext) + } + .distinct() ) } }, @@ -49,50 +31,37 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? { + ): InlayElement? { if (type is PyTypedDictType && !type.isInferred()) return null - if ( - type is PyCollectionType - && type.name != null - && type !is PyTupleType - && type.elementTypes.isNotEmpty() - ) { - val collectionName = when (type) { - is PyTypedDictType -> "dict" - else -> type.name - } ?: return null - - val baseInfoDetails = resolvePsiReference(type, collectionName) - - if (type.elementTypes.all { it == null }) { - return listOf( - InlayInfoDetails( - baseInfoDetails - ) - ) - } + if (type !is PyCollectionType || type.name == null || type is PyTupleType || type.elementTypes.isEmpty()) { + return null + } - val elements = - type.elementTypes.mapNotNull { generateTypeHintText(element, it, typeEvalContext) }.flatten() + val collectionName = when (type) { + is PyTypedDictType -> "dict" + else -> type.name + } ?: return null - if (elements.isEmpty()) { - return listOf( - InlayInfoDetails( - baseInfoDetails - ) - ) - } - - return listOf( - InlayInfoDetails( - baseInfoDetails, - elements, - separator = ", " - ) - ) + val baseElement = InlayElement( + element = TextElement(type, collectionName) + ) + + if (type.elementTypes.all { it == null }) { + return baseElement + } + + val elements = + type.elementTypes.mapNotNull { generateTypeHintText(element, it, typeEvalContext) } + + if (elements.isEmpty()) { + return baseElement } - return null + return InlayElement( + element = baseElement.element, + children = elements, + separatorType = InlaySeparator.COMMA + ) } }, @@ -101,40 +70,36 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? { + ): InlayElement? { if (type !is PyTupleType) return null - val baseInlayDetail = resolvePsiReference(type, PyNames.TUPLE) + val baseElement = TextElement(type, PyNames.TUPLE) if (type.elementCount == 0 || type.elementTypes.filterNotNull().isEmpty()) { - return listOf(InlayInfoDetails(baseInlayDetail)) + return InlayElement(element = baseElement) } if (type.elementCount > 2) { val firstElement = generateTypeHintText(element, type.elementTypes[0], typeEvalContext) val secondElement = generateTypeHintText(element, type.elementTypes[1], typeEvalContext) - return listOf( - InlayInfoDetails( - baseInlayDetail, - firstElement + secondElement + listOf( - InlayInfoDetails( - TextInlayInfoDetail("...") - ) - ), - separator = ", " - ) + return InlayElement( + element = baseElement, + children = listOf( + firstElement, + secondElement, + InlayElement( + element = TextElement("...") + ) + ), + separatorType = InlaySeparator.COMMA ) } - return listOf( - InlayInfoDetails( - baseInlayDetail, - type.elementTypes - .mapNotNull { generateTypeHintText(element, it, typeEvalContext) } - .flatten(), - separator = ", " - ) + return InlayElement( + element = baseElement, + children = type.elementTypes.mapNotNull { generateTypeHintText(element, it, typeEvalContext) }, + separatorType = InlaySeparator.COMMA ) } }, @@ -144,24 +109,22 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? { + ): InlayElement? { if (type !is PyClassType) return null - val baseInlayDetail = resolvePsiReference(type, type.declarationElement?.name!!) - val classInlayDetails = listOf(InlayInfoDetails(baseInlayDetail)) + val baseElement = TextElement(type, type.declarationElement?.name!!) + + val classInlayElement = InlayElement(element = baseElement) if (type.isDefinition) { - val inlayDetail = InlayInfoDetails( - TextInlayInfoDetail(PyNames.TYPE.replaceFirstChar { it.titlecaseChar() }), - classInlayDetails + val inlayDetail = InlayElement( + element = TextElement(text = PyNames.TYPE.replaceFirstChar { it.titlecaseChar() }), + children = listOf(classInlayElement) ) - - return listOf(inlayDetail) + return inlayDetail } - if (!type.isDefinition) return classInlayDetails - - return null + return classInlayElement } }, @@ -170,7 +133,7 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? { + ): InlayElement? { if (type !is PyFunctionType) return null val parametersText = when (type.callable) { @@ -184,20 +147,16 @@ enum class HintGenerator { val callableReturnType = typeEvalContext.getReturnType(type.callable) - // TODO: Implement open\close inlay presentation - return listOf( - InlayInfoDetails( - null, - listOf( - InlayInfoDetails(TextInlayInfoDetail(parametersText)), - InlayInfoDetails(TextInlayInfoDetail(" -> ")), - InlayInfoDetails(TextInlayInfoDetail("(")), - *generateTypeHintText(element, callableReturnType, typeEvalContext).toTypedArray(), - InlayInfoDetails(TextInlayInfoDetail(")")) - ), - separator = "", - limit = null - ) + val generatedHint = generateTypeHintText(element, callableReturnType, typeEvalContext) + + return InlayElement( + children = listOf( + InlayElement(TextElement("$parametersText -> (")), + generatedHint, + InlayElement(TextElement(")")) + ), + separatorType = InlaySeparator.EMPTY, + inlayType = InlayType.CALLABLE ) } }, @@ -207,10 +166,8 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List { - val baseInlayDetail = resolvePsiReference(type, type?.name ?: PyNames.UNKNOWN_TYPE) - - return listOf(InlayInfoDetails(baseInlayDetail)) + ): InlayElement { + return InlayElement(element = TextElement(type, type?.name ?: PyNames.UNKNOWN_TYPE)) } }; @@ -218,31 +175,69 @@ enum class HintGenerator { element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List? + ): InlayElement? companion object { - - private fun resolvePsiReference(type: PyType?, name: String): InlayInfoDetail { - return type?.declarationElement?.navigationElement?.let { - return PsiInlayInfoDetail(name, it) - } ?: TextInlayInfoDetail(name) - } - fun generateTypeHintText( element: PyElement, type: PyType?, typeEvalContext: TypeEvalContext - ): List = + ): InlayElement = values().firstNotNullOf { it.handleType(element, type, typeEvalContext) } } } +data class TextElement( + val text: String, + val psiElement: PsiElement? = null, +) { + constructor(type: PyType?, name: String) : this(name, type?.declarationElement?.navigationElement) +} + + +enum class InlaySeparator(val separator: String) { + COMMA(", "), + LINE(" | "), + EMPTY(""), +} + +enum class InlayType(val shortPrefix: String) { + TYPE("Union"), + CALLABLE("Callable") +} + +data class InlayElement( + val element: TextElement? = null, + val children: List = listOf(), + val separatorType: InlaySeparator = InlaySeparator.LINE, + val inlayType: InlayType = InlayType.TYPE +) { + fun isEmpty(): Boolean { + return element == null && children.isEmpty() + } + + fun isGenericType(): Boolean { + return element != null && children.isNotEmpty() + } + + fun isTooLong(): Boolean { + return contextLength > 4 + } + + private val contextLength: Short by lazy { + children.fold(1) { acc, inlayElement -> + (acc + inlayElement.contextLength).toShort() + } + } +} + data class InlayInfoDetails( val rootInlayInfo: InlayInfoDetail?, val details: List = listOf(), val separator: String = " | ", val limit: Int? = 3 + ) sealed class InlayInfoDetail(val text: String) diff --git a/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintResolver.kt b/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintResolver.kt index 3da5097..f2ef8c2 100644 --- a/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintResolver.kt +++ b/src/main/kotlin/space/whitememory/pythoninlayparams/types/hints/HintResolver.kt @@ -7,18 +7,14 @@ import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider import com.jetbrains.python.psi.* import com.jetbrains.python.psi.impl.PyCallExpressionHelper import com.jetbrains.python.psi.types.* -import space.whitememory.pythoninlayparams.types.variables.PythonVariablesInlayTypeHintsProvider enum class HintResolver { GLOBALS_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) if (assignedValue !is PyCallExpression) return true @@ -28,13 +24,10 @@ enum class HintResolver { }, GENERAL_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -51,13 +44,10 @@ enum class HintResolver { }, TYPING_MODULE_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -85,19 +75,16 @@ enum class HintResolver { }, GENERIC_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) assignedValue?.let { typeEvalContext.getType(element.findAssignedValue() as PyTypedElement)?.let { - return it !is PyGenericType + return it !is PyTypeVarType } } @@ -106,41 +93,31 @@ enum class HintResolver { }, EXCEPTION_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean = PsiTreeUtil.getParentOfType(element, PyExceptPart::class.java) == null }, - CLASS_ATTRIBUTE_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings): Boolean = - !settings.showClassAttributeHints - - override fun shouldShowTypeHint( - element: PyTargetExpression, - typeAnnotation: PyType?, - typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings - ): Boolean = !PyUtil.isClassAttribute(element) - }, +// CLASS_ATTRIBUTE_HINT { +// override fun shouldShowTypeHint( +// element: PyTargetExpression, +// typeAnnotation: PyType?, +// typeEvalContext: TypeEvalContext, +// ): Boolean = !PyUtil.isClassAttribute(element) +// }, UNION_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { if (typeAnnotation is PyUnionType) { return typeAnnotation.members.any { type -> - resolveEnabled(settings).all { - shouldShowTypeHint(element, type, typeEvalContext, settings) + values().all { + shouldShowTypeHint(element, type, typeEvalContext) } } } @@ -150,13 +127,10 @@ enum class HintResolver { }, CLASS_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -166,7 +140,7 @@ enum class HintResolver { if (resolvedClasses.isNotEmpty()) { return resolvedClasses.all { - shouldShowTypeHint(element, it, typeEvalContext, settings) + shouldShowTypeHint(element, it, typeEvalContext) } } @@ -176,9 +150,9 @@ enum class HintResolver { ) { // Handle case like User().get_name() and list() if (typeAnnotation.isBuiltin || assignedValue.callee?.reference?.resolve() is PyFunction) { - return resolveEnabled(settings) + return values() .filter { it != CLASS_HINT } - .all { it.shouldShowTypeHint(element, typeAnnotation, typeEvalContext, settings) } + .all { it.shouldShowTypeHint(element, typeAnnotation, typeEvalContext) } } return false @@ -189,13 +163,10 @@ enum class HintResolver { }, CONDITIONAL_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignmentValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -227,13 +198,10 @@ enum class HintResolver { }, COMPREHENSION_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignmentValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -250,15 +218,12 @@ enum class HintResolver { }, SET_HINT { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - private val collectionNames = setOf("frozenset", PyNames.SET) override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignmentValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -278,13 +243,10 @@ enum class HintResolver { }, LITERAL_EXPRESSION { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -314,13 +276,10 @@ enum class HintResolver { }, TUPLE_TYPE { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { if (typeAnnotation !is PyTupleType) return true if (typeAnnotation.elementTypes.filterNotNull().isEmpty()) return false @@ -334,13 +293,10 @@ enum class HintResolver { }, ENUM_TYPE { - override fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings) = true - override fun shouldShowTypeHint( element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val assignedValue = PyUtil.peelArgument(element.findAssignedValue()) @@ -349,9 +305,9 @@ enum class HintResolver { val resolvedExpression = assignedValue.reference.resolve() ?: return true if (resolvedExpression is PyTargetExpression) { - return resolveEnabled(settings) + return values() .filter { it != ENUM_TYPE } - .all { it.shouldShowTypeHint(resolvedExpression, typeAnnotation, typeEvalContext, settings) } + .all { it.shouldShowTypeHint(resolvedExpression, typeAnnotation, typeEvalContext) } } return true @@ -362,30 +318,22 @@ enum class HintResolver { element: PyTargetExpression, typeAnnotation: PyType?, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean - abstract fun isApplicable(settings: PythonVariablesInlayTypeHintsProvider.Settings): Boolean - companion object { val builtinMethods = setOf("globals", "locals") fun resolve( element: PyTargetExpression, typeEvalContext: TypeEvalContext, - settings: PythonVariablesInlayTypeHintsProvider.Settings ): Boolean { val typeAnnotation = getExpressionAnnotationType(element, typeEvalContext) - return resolveEnabled(settings).any { - !it.shouldShowTypeHint(element, typeAnnotation, typeEvalContext, settings) + return values().any { + !it.shouldShowTypeHint(element, typeAnnotation, typeEvalContext) } } - private fun resolveEnabled( - settings: PythonVariablesInlayTypeHintsProvider.Settings - ): List = values().filter { it.isApplicable(settings) } - private fun isLiteralExpression(element: PyExpression?): Boolean { return element is PySequenceExpression || element is PyLiteralExpression || element is PySetCompExpression } diff --git a/src/main/kotlin/space/whitememory/pythoninlayparams/types/variables/PythonVariablesInlayTypeHintsCollector.kt b/src/main/kotlin/space/whitememory/pythoninlayparams/types/variables/PythonVariablesInlayTypeHintsCollector.kt index 95cc285..61f65c3 100644 --- a/src/main/kotlin/space/whitememory/pythoninlayparams/types/variables/PythonVariablesInlayTypeHintsCollector.kt +++ b/src/main/kotlin/space/whitememory/pythoninlayparams/types/variables/PythonVariablesInlayTypeHintsCollector.kt @@ -26,7 +26,7 @@ class PythonVariablesInlayTypeHintsCollector( if (!validateExpression(element)) return true val typeEvalContext = getTypeEvalContext(editor, element) - if (HintResolver.resolve(element as PyTargetExpression, typeEvalContext, settings)) return true + if (HintResolver.resolve(element as PyTargetExpression, typeEvalContext)) return true try { renderTypeHint(element, typeEvalContext, sink) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 5836639..0bba951 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -8,8 +8,9 @@ com.intellij.modules.python - - + \ No newline at end of file diff --git a/src/main/resources/messages/InlayProperties.properties b/src/main/resources/messages/InlayProperties.properties new file mode 100644 index 0000000..61e4826 --- /dev/null +++ b/src/main/resources/messages/InlayProperties.properties @@ -0,0 +1,2 @@ +python.variables.name=Python +python.variables.description=Provide type information where it is not explicit. \ No newline at end of file diff --git a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonAbstractInlayHintsTestCase.kt b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonAbstractInlayHintsTestCase.kt index d215c0b..0721fe3 100644 --- a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonAbstractInlayHintsTestCase.kt +++ b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonAbstractInlayHintsTestCase.kt @@ -1,10 +1,11 @@ package space.whitememory.pythoninlayparams import com.intellij.testFramework.utils.inlays.InlayHintsProviderTestCase +import com.intellij.testFramework.utils.inlays.declarative.DeclarativeInlayHintsProviderTestCase import com.jetbrains.python.psi.LanguageLevel import space.whitememory.pythoninlayparams.python.PyLightProjectDescriptor -abstract class PythonAbstractInlayHintsTestCase : InlayHintsProviderTestCase() { +abstract class PythonAbstractInlayHintsTestCase : DeclarativeInlayHintsProviderTestCase() { override fun getProjectDescriptor() = PyLightProjectDescriptor(LanguageLevel.getLatest()) } \ No newline at end of file diff --git a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonFunctionReturnTypesTest.kt b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonFunctionReturnTypesTest.kt index 0809159..979673a 100644 --- a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonFunctionReturnTypesTest.kt +++ b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonFunctionReturnTypesTest.kt @@ -170,10 +170,9 @@ class PythonFunctionReturnTypesTest : PythonAbstractInlayHintsTestCase() { """.trimIndent() ) - @Suppress("UnstableApiUsage") private fun doTest(text: String) { doTestProvider( - "foo.py", text, PythonFunctionInlayTypeHintsProvider() + "foo.py", text, InlayHintsProvider() ) } } \ No newline at end of file diff --git a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonVariableTypesTest.kt b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonVariableTypesTest.kt index 0cb91ba..a200fa6 100644 --- a/src/test/kotlin/space/whitememory/pythoninlayparams/PythonVariableTypesTest.kt +++ b/src/test/kotlin/space/whitememory/pythoninlayparams/PythonVariableTypesTest.kt @@ -196,13 +196,11 @@ class PythonVariableTypesTest : PythonAbstractInlayHintsTestCase() { """.trimIndent() ) - @Suppress("UnstableApiUsage") private fun doTest(text: String) { doTestProvider( "foo.py", "$testObjects\n$text", - PythonVariablesInlayTypeHintsProvider(), - PythonVariablesInlayTypeHintsProvider.Settings(showClassAttributeHints = true, showGeneralHints = true) + InlayHintsProvider(), ) } } \ No newline at end of file