mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJ-MR-219988
IJPL-253731 add IntelliJ Platform dependency version completion Import product release metadata before Gradle task execution and use it to suggest product-specific versions in Kotlin DSL builds. Publish fetched models after successful and failed syncs so invalid versions can be corrected during initial import. Signed-off-by: Jakub Chrzanowski <jakub.chrzanowski@jetbrains.com> (cherry picked from commit 047e54ca52d6e0435cc06d90664ae259a30598fd) Signed-off-by: Jakub Chrzanowski <jakub.chrzanowski@jetbrains.com> GitOrigin-RevId: f87119fb6d747b8d5d55c83e96865601d861dc7c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bf5d227b92
commit
7aeed064b8
@@ -21,7 +21,9 @@ jvm_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
# do not sort,
|
||||
"@lib//:kotlin-stdlib",
|
||||
"@lib//:jetbrains-annotations",
|
||||
"//plugins/gradle/tooling-extension-api:toolingExtension",
|
||||
"//plugins/gradle/tooling-extension-impl:toolingExtension-impl",
|
||||
"@lib//:gradle-provided",
|
||||
],
|
||||
@@ -40,6 +42,7 @@ jvm_library(
|
||||
runtime_deps = [
|
||||
# do not sort,
|
||||
":gradle-tooling",
|
||||
"//plugins/gradle/tooling-extension-api:toolingExtension_test_lib",
|
||||
"//plugins/gradle/tooling-extension-impl:toolingExtension-impl_test_lib",
|
||||
"@lib//:gradle-provided",
|
||||
],
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="library" name="jetbrains-annotations" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.toolingExtension" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.toolingExtension.impl" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Gradle" level="project" />
|
||||
</component>
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
# Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
com.intellij.devkit.gradle.tooling.IntelliJPlatformModelBuilder
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
|
||||
<module name="intellij.gradle.toolingExtension"/>
|
||||
<module name="intellij.gradle.toolingExtension.impl"/>
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.devkit.gradle.tooling
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.tooling.model.Model
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.plugins.gradle.tooling.AbstractModelBuilderService
|
||||
import org.jetbrains.plugins.gradle.tooling.Message
|
||||
import org.jetbrains.plugins.gradle.tooling.ModelBuilderContext
|
||||
import java.io.Serializable
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
||||
private const val INTELLIJ_PLATFORM_EXTENSION_NAME = "intellijPlatform"
|
||||
private const val INTELLIJ_PLATFORM_DEPENDENCY_CONFIGURATION_CLASS =
|
||||
"org.jetbrains.intellij.platform.gradle.extensions.IntelliJPlatformDependencyConfiguration"
|
||||
private const val INTELLIJ_PLATFORM_TYPE_CLASS = "org.jetbrains.intellij.platform.gradle.IntelliJPlatformType"
|
||||
private const val DUMP_PRODUCTS_RELEASES_TASK_NAME = "dumpProductsReleases"
|
||||
private const val GRADLE_ACTION_CLASS = "org.gradle.api.Action"
|
||||
private const val PRODUCT_CODE_GETTER = "getCode"
|
||||
|
||||
/**
|
||||
* Transfers IntelliJ Platform dependency helpers and the generated product-release catalog from Gradle to the IDE.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
interface IntelliJPlatformGradleModel : Model, Serializable {
|
||||
val dependencyHelperProductCodes: Map<String, String>
|
||||
val productReleasesFile: String?
|
||||
}
|
||||
|
||||
internal class IntelliJPlatformGradleModelImpl(
|
||||
override val dependencyHelperProductCodes: Map<String, String>,
|
||||
override val productReleasesFile: String?,
|
||||
) : IntelliJPlatformGradleModel
|
||||
|
||||
/**
|
||||
* Reflects over the IntelliJ Platform Gradle Plugin DSL and schedules its release-catalog dump for IDE import.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
class IntelliJPlatformModelBuilder : AbstractModelBuilderService() {
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean {
|
||||
return modelName == IntelliJPlatformGradleModel::class.java.name
|
||||
}
|
||||
|
||||
override fun buildAll(modelName: String, project: Project, context: ModelBuilderContext): Any? {
|
||||
val extension = (project.dependencies as? ExtensionAware)
|
||||
?.extensions
|
||||
?.findByName(INTELLIJ_PLATFORM_EXTENSION_NAME)
|
||||
?: return null
|
||||
val dumpTask = project.tasks.findByName(DUMP_PRODUCTS_RELEASES_TASK_NAME)
|
||||
|
||||
if (dumpTask != null) {
|
||||
project.gradle.startParameter.setTaskNames(
|
||||
project.gradle.startParameter.taskNames.toSet() + dumpTask.path,
|
||||
)
|
||||
}
|
||||
|
||||
return IntelliJPlatformGradleModelImpl(
|
||||
dependencyHelperProductCodes = extension.javaClass.loadDependencyHelperProductCodes(),
|
||||
productReleasesFile = dumpTask?.outputs?.files?.singleFile?.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
override fun reportErrorMessage(modelName: String, project: Project, context: ModelBuilderContext, exception: Exception) {
|
||||
context.messageReporter.createMessage()
|
||||
.withGroup(this)
|
||||
.withKind(Message.Kind.WARNING)
|
||||
.withTitle("Gradle import errors")
|
||||
.withText("Unable to build IntelliJ Platform project configuration")
|
||||
.withException(exception)
|
||||
.reportMessage(project)
|
||||
}
|
||||
|
||||
private fun Class<*>.loadDependencyHelperProductCodes(): Map<String, String> {
|
||||
val platformTypeClass = classLoader.loadClass(INTELLIJ_PLATFORM_TYPE_CLASS)
|
||||
val productCodeGetter = platformTypeClass.getMethod(PRODUCT_CODE_GETTER)
|
||||
val productCodeByTypeName = platformTypeClass.enumConstants.associate { platformType ->
|
||||
(platformType as Enum<*>).name.lowercase() to productCodeGetter.invoke(platformType) as String
|
||||
}
|
||||
|
||||
return methods.asSequence()
|
||||
.filter { method ->
|
||||
method.genericParameterTypes.any { parameterType ->
|
||||
parameterType is ParameterizedType &&
|
||||
parameterType.rawType.typeName == GRADLE_ACTION_CLASS &&
|
||||
parameterType.actualTypeArguments.any { it.typeName == INTELLIJ_PLATFORM_DEPENDENCY_CONFIGURATION_CLASS }
|
||||
}
|
||||
}
|
||||
.mapNotNull { method ->
|
||||
productCodeByTypeName[method.name.lowercase()]?.let { method.name to it }
|
||||
}
|
||||
.toMap(sortedMapOf())
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,10 @@ jvm_library(
|
||||
["resources/**/*"],
|
||||
),
|
||||
visibility = ["//visibility:public"],
|
||||
runtime_deps = ["//plugins/kotlin/plugin"],
|
||||
deps = [
|
||||
# do not sort,
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//java/idea-ui:ui",
|
||||
"//platform/core-api:core",
|
||||
"//platform/core-impl",
|
||||
@@ -35,9 +37,11 @@ jvm_library(
|
||||
"//platform/analysis-api:analysis",
|
||||
"//platform/execution",
|
||||
"//platform/lang-api:lang",
|
||||
"//platform/util",
|
||||
"//plugins/gradle",
|
||||
"//plugins/gradle:gradle-common",
|
||||
"//plugins/gradle/java",
|
||||
"//plugins/gradle/tooling-extension-api:toolingExtension",
|
||||
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling",
|
||||
"//platform/smRunner",
|
||||
"//plugins/devkit/devkit-core:core",
|
||||
@@ -51,6 +55,8 @@ jvm_library(
|
||||
"//platform/backend/workspace",
|
||||
"//platform/projectModel-impl",
|
||||
"//jps/model-api:model",
|
||||
"//plugins/kotlin/base/psi",
|
||||
"@lib//:kotlinc-kotlin-compiler-common-provided",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -80,9 +86,11 @@ jvm_library(
|
||||
"//platform/analysis-api:analysis_test_lib",
|
||||
"//platform/execution:execution_test_lib",
|
||||
"//platform/lang-api:lang_test_lib",
|
||||
"//platform/util:util_test_lib",
|
||||
"//plugins/gradle:gradle_test_lib",
|
||||
"//plugins/gradle:gradle-common_test_lib",
|
||||
"//plugins/gradle/java:java_test_lib",
|
||||
"//plugins/gradle/tooling-extension-api:toolingExtension_test_lib",
|
||||
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling_test_lib",
|
||||
"//platform/smRunner:smRunner_test_lib",
|
||||
"//plugins/devkit/devkit-core:core_test_lib",
|
||||
@@ -100,6 +108,9 @@ jvm_library(
|
||||
"//platform/backend/workspace:workspace_test_lib",
|
||||
"//platform/projectModel-impl:projectModel-impl_test_lib",
|
||||
"//jps/model-api:model_test_lib",
|
||||
"//plugins/kotlin/plugin:plugin_test_lib",
|
||||
"//plugins/kotlin/base/psi:psi_test_lib",
|
||||
"@lib//:kotlinc-kotlin-compiler-common-provided",
|
||||
],
|
||||
)
|
||||
### auto-generated section `build intellij.devkit.gradle` end
|
||||
@@ -207,6 +218,8 @@ jvm_library(
|
||||
"//platform/projectModel-impl:projectModel-impl_test_lib",
|
||||
"//jps/model-api:model",
|
||||
"//jps/model-api:model_test_lib",
|
||||
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling",
|
||||
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling_test_lib",
|
||||
"//libraries/junit4",
|
||||
"//libraries/junit4:junit4_test_lib",
|
||||
],
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.java.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.impl" />
|
||||
@@ -22,9 +23,11 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.analysis" />
|
||||
<orderEntry type="module" module-name="intellij.platform.execution" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.gradle" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.common" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.java" />
|
||||
<orderEntry type="module" module-name="intellij.gradle.toolingExtension" />
|
||||
<orderEntry type="module" module-name="intellij.devkit.gradle.tooling" />
|
||||
<orderEntry type="module" module-name="intellij.platform.smRunner" />
|
||||
<orderEntry type="module" module-name="intellij.devkit.core" />
|
||||
@@ -40,5 +43,8 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.workspace" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.model" />
|
||||
<orderEntry type="module" module-name="kotlin.plugin" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.kotlin.base.psi" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-common" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -38,6 +38,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel.impl" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jps.model" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.devkit.gradle" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.devkit.gradle.tooling" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.junit4" scope="TEST" />
|
||||
</component>
|
||||
<component name="TestModuleProperties" production-module="intellij.devkit.gradle" />
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<idea-plugin>
|
||||
<!-- region Generated dependencies - run `Generate Product Layouts` to regenerate -->
|
||||
<dependencies>
|
||||
<plugin id="org.jetbrains.kotlin"/>
|
||||
<module name="intellij.devkit.core"/>
|
||||
<module name="intellij.devkit.gradle.tooling"/>
|
||||
<module name="intellij.gradle"/>
|
||||
<module name="intellij.gradle.java"/>
|
||||
<module name="intellij.gradle.toolingExtension"/>
|
||||
<module name="intellij.java.psi"/>
|
||||
<module name="intellij.java.ui"/>
|
||||
<module name="intellij.platform.smRunner"/>
|
||||
@@ -19,5 +21,14 @@
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<attachSourcesProvider implementation="org.jetbrains.idea.devkit.gradle.IntelliJPlatformAttachSourcesProvider"/>
|
||||
<consoleFilterProvider implementation="org.jetbrains.idea.devkit.gradle.GradlePluginConsoleFilterProvider"/>
|
||||
<completion.contributor language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.gradle.IntelliJPlatformVersionsCompletionContributor"/>
|
||||
<projectService serviceInterface="org.jetbrains.idea.devkit.gradle.IntelliJPlatformGradleModelProvider"
|
||||
serviceImplementation="org.jetbrains.idea.devkit.gradle.IntelliJPlatformGradleModelProviderImpl"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
<applicationListeners>
|
||||
<listener class="org.jetbrains.idea.devkit.gradle.IntelliJPlatformGradleSyncListener"
|
||||
topic="org.jetbrains.plugins.gradle.service.syncAction.GradleSyncListener"/>
|
||||
</applicationListeners>
|
||||
</idea-plugin>
|
||||
@@ -2,9 +2,22 @@
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformAuxiliaryArtifactProvider
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
|
||||
import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
|
||||
import com.intellij.gradle.toolingExtension.modelProvider.GradleClassProjectModelProvider
|
||||
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||
|
||||
/**
|
||||
* Fetches IntelliJ Platform metadata before task execution, allowing the IDE to retain it when later sync stages fail.
|
||||
*/
|
||||
internal class DevKitGradleProjectResolverExtension : AbstractProjectResolverExtension() {
|
||||
override fun getToolingExtensionsClasses(): Set<Class<*>> =
|
||||
setOf(IntelliJPlatformAuxiliaryArtifactProvider::class.java)
|
||||
|
||||
override fun getModelProviders() = listOf(
|
||||
GradleClassProjectModelProvider(
|
||||
IntelliJPlatformGradleModel::class.java,
|
||||
GradleModelFetchPhase.PROJECT_LOADED_PHASE,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.readLines
|
||||
|
||||
/** IDE-side completion metadata imported from [IntelliJPlatformGradleModel]. */
|
||||
internal data class IntelliJPlatformGradleData(
|
||||
val dependencyHelperProductCodes: Map<String, String>,
|
||||
val productReleases: Map<String, List<IntelliJPlatformProductRelease>>,
|
||||
)
|
||||
|
||||
internal data class IntelliJPlatformProductRelease(
|
||||
val version: String,
|
||||
val channel: String,
|
||||
)
|
||||
|
||||
internal fun IntelliJPlatformGradleModel.toIntelliJPlatformGradleData() = IntelliJPlatformGradleData(
|
||||
dependencyHelperProductCodes = dependencyHelperProductCodes,
|
||||
productReleases = productReleasesFile.readProductReleases(),
|
||||
)
|
||||
|
||||
/** Reads `product-code<TAB>version<TAB>channel` records written by the Gradle task. */
|
||||
internal fun String?.readProductReleases(): Map<String, List<IntelliJPlatformProductRelease>> {
|
||||
val file = this?.let { Path.of(it) }?.takeIf { it.isRegularFile() } ?: return emptyMap()
|
||||
|
||||
return runCatching {
|
||||
file.readLines()
|
||||
.mapNotNull(::parseProductRelease)
|
||||
.groupBy(
|
||||
keySelector = { it.first },
|
||||
valueTransform = { it.second },
|
||||
)
|
||||
}.getOrDefault(emptyMap())
|
||||
}
|
||||
|
||||
private fun parseProductRelease(value: String): Pair<String, IntelliJPlatformProductRelease>? {
|
||||
val fields = value.split('\t')
|
||||
if (fields.size != 3 || fields.any(String::isBlank)) return null
|
||||
|
||||
return fields[0] to IntelliJPlatformProductRelease(
|
||||
version = fields[1],
|
||||
channel = fields[2],
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiFile
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
/** Resolves imported metadata for the closest Gradle module containing a physical PSI file. */
|
||||
internal fun interface IntelliJPlatformGradleModelProvider {
|
||||
fun getModel(file: PsiFile): IntelliJPlatformGradleData?
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): IntelliJPlatformGradleModelProvider =
|
||||
project.getService(IntelliJPlatformGradleModelProvider::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/** Publishes per-sync model snapshots without blocking concurrent completion lookups. */
|
||||
internal class IntelliJPlatformGradleModelProviderImpl : IntelliJPlatformGradleModelProvider {
|
||||
|
||||
private val dataByLinkedProjectPath = AtomicReference<Map<String, Map<String, IntelliJPlatformGradleData>>>(emptyMap())
|
||||
|
||||
override fun getModel(file: PsiFile): IntelliJPlatformGradleData? {
|
||||
val filePath = file.virtualFile?.path
|
||||
if (filePath == null) {
|
||||
LOG.debug("Cannot find IntelliJ Platform Gradle model for a non-physical file: ${file.name}")
|
||||
return null
|
||||
}
|
||||
|
||||
val match = dataByLinkedProjectPath.get()
|
||||
.values
|
||||
.asSequence()
|
||||
.flatMap { it.asSequence() }
|
||||
.filter { (modulePath) -> FileUtil.isAncestor(modulePath, filePath, false) }
|
||||
.maxByOrNull { (modulePath) -> modulePath.length }
|
||||
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("IntelliJ Platform Gradle model lookup for '$filePath': ${match?.key ?: "no matching Gradle module"}")
|
||||
}
|
||||
return match?.value
|
||||
}
|
||||
|
||||
internal fun replaceProjectData(
|
||||
linkedProjectPath: String,
|
||||
dataByModulePath: Map<String, IntelliJPlatformGradleData>,
|
||||
) {
|
||||
dataByLinkedProjectPath.updateAndGet { currentData ->
|
||||
if (dataByModulePath.isEmpty()) currentData - linkedProjectPath
|
||||
else currentData + (linkedProjectPath to dataByModulePath.toMap())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(IntelliJPlatformGradleModelProviderImpl::class.java)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncListener
|
||||
|
||||
/** Publishes fetched IntelliJ Platform models after both successful and failed Gradle syncs. */
|
||||
internal class IntelliJPlatformGradleSyncListener : GradleSyncListener {
|
||||
|
||||
override fun onModelFetchCompleted(context: ProjectResolverContext) {
|
||||
importProjectModels(context)
|
||||
}
|
||||
|
||||
override fun onModelFetchFailed(context: ProjectResolverContext, exception: Throwable) {
|
||||
importProjectModels(context)
|
||||
}
|
||||
|
||||
@Suppress("SSBasedInspection") // Gradle's tooling model exposes the project directory as File.
|
||||
private fun importProjectModels(context: ProjectResolverContext) {
|
||||
if (!context.hasModulesWithModel(IntelliJPlatformGradleModel::class.java)) return
|
||||
val provider = IntelliJPlatformGradleModelProvider.getInstance(context.project) as? IntelliJPlatformGradleModelProviderImpl ?: return
|
||||
val modelsByModulePath = context.allBuilds
|
||||
.asSequence()
|
||||
.flatMap { it.projects.asSequence() }
|
||||
.mapNotNull { gradleProject ->
|
||||
context.getProjectModel(gradleProject, IntelliJPlatformGradleModel::class.java)?.let {
|
||||
gradleProject.projectDirectory.toPath().toString() to it
|
||||
}
|
||||
}
|
||||
.toMap()
|
||||
|
||||
val importedModels = provider.importProjectModels(context.externalProjectPath, modelsByModulePath)
|
||||
if (importedModels > 0) {
|
||||
LOG.debug("Imported IntelliJ Platform Gradle data for $importedModels module(s)")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(IntelliJPlatformGradleSyncListener::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts fetched tooling models and publishes modules with a usable product-release catalog. */
|
||||
internal fun IntelliJPlatformGradleModelProviderImpl.importProjectModels(
|
||||
linkedProjectPath: String,
|
||||
modelsByModulePath: Map<String, IntelliJPlatformGradleModel>,
|
||||
): Int {
|
||||
val dataByModulePath = modelsByModulePath
|
||||
.mapValues { (_, model) -> model.toIntelliJPlatformGradleData() }
|
||||
.filterValues { it.productReleases.isNotEmpty() }
|
||||
if (dataByModulePath.isNotEmpty()) {
|
||||
replaceProjectData(linkedProjectPath, dataByModulePath)
|
||||
}
|
||||
return dataByModulePath.size
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionContributor
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionProvider
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.codeInsight.completion.PrioritizedLookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.devkit.core.icons.DevkitCoreIcons
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.idea.devkit.projectRoots.IntelliJPlatformProduct
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
|
||||
private const val DEPENDENCIES_BLOCK = "dependencies"
|
||||
private const val INTELLIJ_PLATFORM_BLOCK = "intellijPlatform"
|
||||
private const val CREATE_HELPER = "create"
|
||||
private const val TYPE_PARAMETER = "type"
|
||||
private const val VERSION_PARAMETER = "version"
|
||||
private const val COMPLETION_PRIORITY = 100.0
|
||||
|
||||
/** Completes IntelliJ Platform dependency versions from metadata imported during Gradle sync. */
|
||||
internal class IntelliJPlatformVersionsCompletionContributor : CompletionContributor() {
|
||||
|
||||
init {
|
||||
val place = PlatformPatterns.psiElement()
|
||||
.withParent(KtLiteralStringTemplateEntry::class.java)
|
||||
.with(object : PatternCondition<PsiElement>("intellijPlatformVersionLiteral") {
|
||||
override fun accepts(element: PsiElement, context: ProcessingContext?): Boolean {
|
||||
if (!element.containingFile.name.endsWith(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION)) return false
|
||||
|
||||
val callExpression = element.getParentOfType<KtCallExpression>(true) ?: return false
|
||||
|
||||
val intellijPlatformClosure = callExpression.getParentOfType<KtCallExpression>(true)
|
||||
?.takeIf { it.calleeExpression?.text == INTELLIJ_PLATFORM_BLOCK }
|
||||
?: return false
|
||||
|
||||
intellijPlatformClosure.getParentOfType<KtCallExpression>(true)
|
||||
?.takeIf { it.calleeExpression?.text == DEPENDENCIES_BLOCK }
|
||||
?: return false
|
||||
|
||||
return callExpression.isVersionArgument(element) ||
|
||||
(callExpression.containsInLambda(element) && element.isVersionAssignmentValue())
|
||||
}
|
||||
})
|
||||
|
||||
extend(CompletionType.BASIC, place, IntelliJPlatformVersionsCompletionProvider())
|
||||
}
|
||||
|
||||
private fun KtCallExpression.isVersionArgument(element: PsiElement): Boolean {
|
||||
val argument = valueArguments.firstOrNull { PsiTreeUtil.isAncestor(it, element, false) } ?: return false
|
||||
val argumentName = argument.getArgumentName()?.asName?.asString()
|
||||
if (argumentName != null) return argumentName == VERSION_PARAMETER
|
||||
|
||||
val versionArgumentIndex = if (calleeExpression?.text == CREATE_HELPER) 1 else 0
|
||||
return valueArguments.indexOf(argument) == versionArgumentIndex
|
||||
}
|
||||
|
||||
private fun KtCallExpression.containsInLambda(element: PsiElement): Boolean {
|
||||
return lambdaArguments.any { PsiTreeUtil.isAncestor(it, element, false) }
|
||||
}
|
||||
|
||||
private fun PsiElement.isVersionAssignmentValue(): Boolean {
|
||||
val assignment = getParentOfType<KtBinaryExpression>(strict = false) ?: return false
|
||||
val property = assignment.left as? KtNameReferenceExpression ?: return false
|
||||
val value = assignment.right ?: return false
|
||||
|
||||
return assignment.operationToken == KtTokens.EQ &&
|
||||
property.getReferencedName() == VERSION_PARAMETER &&
|
||||
PsiTreeUtil.isAncestor(value, this, false)
|
||||
}
|
||||
|
||||
private class IntelliJPlatformVersionsCompletionProvider : CompletionProvider<CompletionParameters>() {
|
||||
|
||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||
val callExpression = parameters.position.getParentOfType<KtCallExpression>(true) ?: return
|
||||
val dependencyHelper = callExpression.calleeExpression?.text ?: return
|
||||
val gradleModel = IntelliJPlatformGradleModelProvider.getInstance(parameters.position.project).getModel(parameters.originalFile) ?: return
|
||||
val productCode = when (dependencyHelper) {
|
||||
CREATE_HELPER -> callExpression.getCreateProductCode()
|
||||
else -> gradleModel.dependencyHelperProductCodes[dependencyHelper]
|
||||
} ?: return
|
||||
|
||||
val productName = IntelliJPlatformProduct.fromProductCode(productCode)?.getName() ?: "IntelliJ Platform"
|
||||
val releases = gradleModel.productReleases[productCode]
|
||||
.orEmpty()
|
||||
.asSequence()
|
||||
.distinct()
|
||||
.sortedWith { first, second ->
|
||||
StringUtil.compareVersionNumbers(second.version, first.version)
|
||||
.takeIf { it != 0 }
|
||||
?: compareValues(first.channel, second.channel)
|
||||
}
|
||||
.toList()
|
||||
|
||||
releases.forEachIndexed { index, release ->
|
||||
val channel = release.channel.toPresentableChannel()
|
||||
val lookupElement = LookupElementBuilder.create(release.version)
|
||||
.withIcon(DevkitCoreIcons.Sdk_closed)
|
||||
.withTailText(" $channel", true)
|
||||
.withTypeText("$productName ($productCode)", true)
|
||||
result.addElement(PrioritizedLookupElement.withPriority(lookupElement, COMPLETION_PRIORITY + releases.size - index))
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtCallExpression.getCreateProductCode(): String? {
|
||||
val typeArgument = valueArguments.firstOrNull {
|
||||
it.getArgumentName()?.asName?.asString() == TYPE_PARAMETER
|
||||
} ?: valueArguments.firstOrNull { it.getArgumentName() == null }
|
||||
val typeExpression = typeArgument?.getArgumentExpression() as? KtStringTemplateExpression ?: return null
|
||||
|
||||
return (typeExpression.entries.singleOrNull() as? KtLiteralStringTemplateEntry)?.text
|
||||
}
|
||||
|
||||
private fun String.toPresentableChannel(): String {
|
||||
return when (this) {
|
||||
"EAP", "RC" -> this
|
||||
else -> lowercase().replaceFirstChar(Char::titlecase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
|
||||
import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
||||
import java.lang.reflect.Proxy
|
||||
import java.nio.file.Files
|
||||
|
||||
internal class DevKitGradleProjectResolverExtensionTest : TestCase() {
|
||||
|
||||
fun testModelIsFetchedBeforeTaskExecution() {
|
||||
val modelProvider = DevKitGradleProjectResolverExtension().modelProviders.single()
|
||||
|
||||
assertEquals(GradleModelFetchPhase.PROJECT_LOADED_PHASE, modelProvider.phase)
|
||||
}
|
||||
|
||||
fun testFailedFetchWithoutIntelliJPlatformModelIsIgnored() {
|
||||
val context = Proxy.newProxyInstance(
|
||||
javaClass.classLoader,
|
||||
arrayOf(ProjectResolverContext::class.java),
|
||||
) { _, method, arguments ->
|
||||
when (method.name) {
|
||||
"hasModulesWithModel" -> {
|
||||
assertSame(IntelliJPlatformGradleModel::class.java, arguments.single())
|
||||
false
|
||||
}
|
||||
else -> error("Unexpected ProjectResolverContext call: ${method.name}")
|
||||
}
|
||||
} as ProjectResolverContext
|
||||
|
||||
IntelliJPlatformGradleSyncListener().onModelFetchFailed(context, RuntimeException("Expected sync failure"))
|
||||
}
|
||||
|
||||
fun testReadsProductReleaseCatalog() {
|
||||
val file = Files.createTempFile("product-releases", ".txt")
|
||||
try {
|
||||
Files.writeString(
|
||||
file,
|
||||
"""
|
||||
IU${'\t'}2025.2.6${'\t'}RELEASE
|
||||
IU${'\t'}253.123${'\t'}EAP
|
||||
IC-2024.3
|
||||
IC${'\t'}2024.3
|
||||
IC${'\t'}2024.3${'\t'}RELEASE${'\t'}unexpected
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
mapOf(
|
||||
"IU" to listOf(
|
||||
IntelliJPlatformProductRelease("2025.2.6", "RELEASE"),
|
||||
IntelliJPlatformProductRelease("253.123", "EAP"),
|
||||
),
|
||||
),
|
||||
file.toString().readProductReleases(),
|
||||
)
|
||||
}
|
||||
finally {
|
||||
Files.deleteIfExists(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
import com.intellij.testFramework.replaceService
|
||||
import java.nio.file.Files
|
||||
|
||||
internal class IntelliJPlatformGradleModelProviderTest : LightJavaCodeInsightFixtureTestCase() {
|
||||
|
||||
private lateinit var provider: IntelliJPlatformGradleModelProviderImpl
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
provider = IntelliJPlatformGradleModelProviderImpl()
|
||||
project.replaceService(IntelliJPlatformGradleModelProvider::class.java, provider, testRootDisposable)
|
||||
}
|
||||
|
||||
fun testImportsDataForModule() {
|
||||
val file = myFixture.addFileToProject("project/build.gradle.kts", "")
|
||||
val projectPath = file.virtualFile.parent.path
|
||||
val data = gradleData("2026.1")
|
||||
|
||||
updateProjectData(projectPath, projectPath to data)
|
||||
|
||||
assertSame(data, provider.getModel(file))
|
||||
}
|
||||
|
||||
fun testUsesClosestModulePath() {
|
||||
val file = myFixture.addFileToProject("project/nested/build.gradle.kts", "")
|
||||
val nestedProjectPath = file.virtualFile.parent.path
|
||||
val projectPath = file.virtualFile.parent.parent.path
|
||||
val rootData = gradleData("2025.3")
|
||||
val nestedData = gradleData("2026.1")
|
||||
|
||||
updateProjectData(projectPath, projectPath to rootData, nestedProjectPath to nestedData)
|
||||
|
||||
assertSame(nestedData, provider.getModel(file))
|
||||
}
|
||||
|
||||
fun testEmptyImportClearsLinkedProjectData() {
|
||||
val file = myFixture.addFileToProject("project/build.gradle.kts", "")
|
||||
val projectPath = file.virtualFile.parent.path
|
||||
updateProjectData(projectPath, projectPath to gradleData("2026.1"))
|
||||
|
||||
updateProjectData(projectPath)
|
||||
|
||||
assertNull(provider.getModel(file))
|
||||
}
|
||||
|
||||
fun testImportsDataProducedByModelFetch() {
|
||||
val file = myFixture.addFileToProject("project/build.gradle.kts", "")
|
||||
val projectPath = file.virtualFile.parent.path
|
||||
val releasesFile = Files.createTempFile("product-releases", ".txt")
|
||||
try {
|
||||
Files.writeString(releasesFile, "IU\t2026.1\tRELEASE\n")
|
||||
val model = object : IntelliJPlatformGradleModel {
|
||||
override val dependencyHelperProductCodes = mapOf("intellijIdea" to "IU")
|
||||
override val productReleasesFile = releasesFile.toString()
|
||||
}
|
||||
|
||||
assertEquals(1, provider.importProjectModels(projectPath, mapOf(projectPath to model)))
|
||||
|
||||
assertEquals(gradleData("2026.1"), provider.getModel(file))
|
||||
}
|
||||
finally {
|
||||
Files.deleteIfExists(releasesFile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateProjectData(projectPath: String, vararg moduleData: Pair<String, IntelliJPlatformGradleData>) {
|
||||
provider.replaceProjectData(projectPath, moduleData.toMap())
|
||||
}
|
||||
|
||||
private fun gradleData(version: String) = IntelliJPlatformGradleData(
|
||||
dependencyHelperProductCodes = mapOf("intellijIdea" to "IU"),
|
||||
productReleases = mapOf("IU" to listOf(IntelliJPlatformProductRelease(version, "RELEASE"))),
|
||||
)
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.devkit.gradle
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import com.intellij.codeInsight.completion.CompletionContributor
|
||||
import com.intellij.codeInsight.completion.CompletionContributorEP
|
||||
import com.intellij.codeInsight.completion.PrioritizedLookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.devkit.core.icons.DevkitCoreIcons
|
||||
import com.intellij.openapi.extensions.DefaultPluginDescriptor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
import com.intellij.testFramework.registerExtension
|
||||
import com.intellij.testFramework.replaceService
|
||||
import com.intellij.util.application
|
||||
|
||||
internal class IntelliJPlatformVersionsCompletionContributorTest : LightJavaCodeInsightFixtureTestCase() {
|
||||
|
||||
private var gradleData = IntelliJPlatformGradleData(
|
||||
dependencyHelperProductCodes = mapOf(
|
||||
"intellijIdea" to "IU",
|
||||
"intellijIdeaCommunity" to "IC",
|
||||
),
|
||||
productReleases = mapOf(
|
||||
"IC" to listOf(release("2023.1"), release("2023.2")),
|
||||
"IU" to listOf(release("2023.2"), release("2024.1")),
|
||||
),
|
||||
)
|
||||
private var modelRequestFile: PsiFile? = null
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
project.replaceService(
|
||||
IntelliJPlatformGradleModelProvider::class.java,
|
||||
IntelliJPlatformGradleModelProvider { file ->
|
||||
modelRequestFile = file
|
||||
gradleData
|
||||
},
|
||||
testRootDisposable,
|
||||
)
|
||||
val contributor = CompletionContributorEP(
|
||||
"kotlin",
|
||||
IntelliJPlatformVersionsCompletionContributor::class.java.name,
|
||||
DefaultPluginDescriptor("testIntelliJPlatformVersionsCompletion"),
|
||||
)
|
||||
application.registerExtension(CompletionContributor.EP, contributor, testRootDisposable)
|
||||
}
|
||||
|
||||
fun testSuggestsPlatformVersionInKotlinStringLiteral() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
intellijIdea("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertPlatformVersions("2023.2", "2024.1")
|
||||
assertSame(myFixture.file, modelRequestFile)
|
||||
}
|
||||
|
||||
fun testSuggestsOnlyVersionsForDependencyHelperProductType() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
intellijIdeaCommunity("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertPlatformVersions("2023.1", "2023.2")
|
||||
}
|
||||
|
||||
fun testRendersProductDetailsAndPrioritizesDottedVersionsNewestFirst() {
|
||||
val versions = listOf("2025.2.6", "2025.2.6.3", "2025.2.6.2", "2025.2.6.1")
|
||||
gradleData = gradleData.copy(
|
||||
productReleases = mapOf(
|
||||
"IU" to versions.map { version ->
|
||||
release(version, channel = if (version == "2025.2.6.2") "EAP" else "RELEASE")
|
||||
},
|
||||
),
|
||||
)
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
intellijIdea("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val elements = completeBasicElements()
|
||||
assertEquals(
|
||||
mapOf(
|
||||
"2025.2.6.3" to 104.0,
|
||||
"2025.2.6.2" to 103.0,
|
||||
"2025.2.6.1" to 102.0,
|
||||
"2025.2.6" to 101.0,
|
||||
),
|
||||
elements.filter { it.lookupString in versions }.associate {
|
||||
it.lookupString to it.`as`(PrioritizedLookupElement.CLASS_CONDITION_KEY)?.priority
|
||||
},
|
||||
)
|
||||
|
||||
val presentation = LookupElementPresentation()
|
||||
elements.first { it.lookupString == "2025.2.6.3" }.renderElement(presentation)
|
||||
assertSame(DevkitCoreIcons.Sdk_closed, presentation.icon)
|
||||
assertEquals(" Release", presentation.tailText)
|
||||
assertEquals("IntelliJ IDEA (IU)", presentation.typeText)
|
||||
|
||||
val eapPresentation = LookupElementPresentation()
|
||||
elements.first { it.lookupString == "2025.2.6.2" }.renderElement(eapPresentation)
|
||||
assertEquals(" EAP", eapPresentation.tailText)
|
||||
}
|
||||
|
||||
fun testSuggestsPlatformVersionForCreateVersionArgument() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create("IU", "<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertPlatformVersions("2023.2", "2024.1")
|
||||
}
|
||||
|
||||
fun testSuggestsPlatformVersionForCreateNamedTypeArgument() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create(version = "<caret>", type = "IC")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertPlatformVersions("2023.1", "2023.2")
|
||||
}
|
||||
|
||||
fun testDoesNotSuggestPlatformVersionForCreateTypeArgument() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create("<caret>", "2026.1")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertNoPlatformVersions()
|
||||
}
|
||||
|
||||
fun testDoesNotSuggestPlatformVersionForUnsupportedDependencyHelper() {
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
plugin("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertNoPlatformVersions()
|
||||
}
|
||||
|
||||
fun testDoesNotSuggestPlatformVersionWithoutImportedProductReleases() {
|
||||
gradleData = gradleData.copy(productReleases = emptyMap())
|
||||
myFixture.configureByText(
|
||||
"build.gradle.kts",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
intellijIdea("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertNoPlatformVersions()
|
||||
}
|
||||
|
||||
fun testDoesNotSuggestPlatformVersionOutsideKotlinStringLiteral() {
|
||||
myFixture.configureByText("build.gradle.kts", "val <caret>")
|
||||
|
||||
assertNoPlatformVersions()
|
||||
}
|
||||
|
||||
fun testDoesNotSuggestPlatformVersionOutsideGradleKotlinScript() {
|
||||
myFixture.configureByText(
|
||||
"Example.kt",
|
||||
"""
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
intellijIdea("<caret>")
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
assertNoPlatformVersions()
|
||||
}
|
||||
|
||||
private fun completeBasic(): List<String> {
|
||||
return completeBasicElements().map { it.lookupString }
|
||||
}
|
||||
|
||||
private fun completeBasicElements(): List<LookupElement> {
|
||||
val settings = CodeInsightSettings.getInstance()
|
||||
val autoComplete = settings.AUTOCOMPLETE_ON_CODE_COMPLETION
|
||||
settings.AUTOCOMPLETE_ON_CODE_COMPLETION = false
|
||||
return try {
|
||||
myFixture.completeBasic().orEmpty().toList()
|
||||
}
|
||||
finally {
|
||||
settings.AUTOCOMPLETE_ON_CODE_COMPLETION = autoComplete
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertNoPlatformVersions() {
|
||||
assertDoesntContain(completeBasic(), *PLATFORM_VERSIONS.toTypedArray())
|
||||
}
|
||||
|
||||
private fun assertPlatformVersions(vararg expected: String) {
|
||||
assertEquals(expected.toSet(), completeBasic().filter { it in PLATFORM_VERSIONS }.toSet())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PLATFORM_VERSIONS = listOf("2023.1", "2023.2", "2024.1")
|
||||
|
||||
private fun release(version: String, channel: String = "RELEASE") = IntelliJPlatformProductRelease(version, channel)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user