[kotlin] introduce ide scripting refinement api

Merge-request: IJ-MR-159069
Merged-by: Vlad Koshkin <Vladislav.Koshkin@jetbrains.com>

GitOrigin-RevId: dab6bf1bec7d32a6d0cb24cadff9477bdaf766bd
This commit is contained in:
Vlad Koshkin
2025-04-03 23:02:53 +00:00
committed by intellij-monorepo-bot
parent 8c93fe043a
commit 0595001d12
40 changed files with 1086 additions and 1130 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.impl
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
@@ -19,8 +19,17 @@ internal object MetadataStorageImpl: MetadataStorageBase() {
var typeMetadata: StorageTypeMetadata
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.gradleJava.scripting.GradleScriptConfigurationsSource\$KotlinGradleScriptModuleEntitySource", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource",
"com.intellij.platform.workspace.storage.EntitySource"))
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = true, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.EntitySource"))
addMetadata(typeMetadata)
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptConfigurationHandler\$DefaultScriptEntitySource", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = true, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.EntitySource",
"org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource"))
addMetadata(typeMetadata)
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.k2.MainKtsScriptConfigurationProvider\$MainKtsKotlinScriptEntitySource", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = true, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.EntitySource",
"org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource"))
addMetadata(typeMetadata)
@@ -32,55 +41,54 @@ internal object MetadataStorageImpl: MetadataStorageBase() {
addMetadata(typeMetadata)
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
addMetadata(typeMetadata)
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptEntity", entityDataFqName = "org.jetbrains.kotlin.idea.core.script.ucache.impl.KotlinScriptEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "dependencies", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId")))), primitive = primitiveTypeSetNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "dependencies", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId")))), primitive = primitiveTypeSetNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryEntity", entityDataFqName = "org.jetbrains.kotlin.idea.core.script.ucache.impl.KotlinScriptLibraryEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "roots", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRoot", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "url", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "type", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRootTypeId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("java.io.Serializable"))), withDefault = false)), supertypes = listOf("java.io.Serializable")))), primitive = primitiveTypeListNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "roots", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRoot", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "type", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRootTypeId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("java.io.Serializable"))), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "url", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("java.io.Serializable")))), primitive = primitiveTypeListNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "indexSourceRoots", valueType = primitiveTypeBooleanNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "usedInScripts", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId")))), primitive = primitiveTypeSetNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "usedInScripts", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "path", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId")))), primitive = primitiveTypeSetNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptEntity", metadataHash = -1499515069)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryEntity", metadataHash = 1908715706)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", metadataHash = -733365339)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", metadataHash = -1141885280)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRoot", metadataHash = 940316485)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptEntity", metadataHash = 187402499)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryEntity", metadataHash = -1434664930)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryId", metadataHash = -623708217)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId", metadataHash = 1048767682)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRoot", metadataHash = 509227373)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRootTypeId", metadataHash = -2068549764)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.EntitySource", metadataHash = 1946578919)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource", metadataHash = -2106192691)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.k2.BundledScriptConfigurationsSource\$KotlinBundledScriptModuleEntitySource", metadataHash = -1547303786)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.k2.DependentScriptConfigurationsSource\$KotlinDependentScriptModuleEntitySource", metadataHash = 1428315510)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.gradleJava.scripting.GradleScriptConfigurationsSource\$KotlinGradleScriptModuleEntitySource", metadataHash = 1681787859)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource", metadataHash = -387173779)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptConfigurationHandler\$DefaultScriptEntitySource", metadataHash = -269097726)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.k2.MainKtsScriptConfigurationProvider\$MainKtsKotlinScriptEntitySource", metadataHash = 1024193770)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptEntitySource", metadataHash = 236614476)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryEntitySource", metadataHash = 1353548779)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = -194396395)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = -1791994671)
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2.impl
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi

View File

@@ -1,16 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.ucache.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.SymbolicEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.SoftLinkable
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase

View File

@@ -1,16 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.ucache.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.SymbolicEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.SoftLinkable
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.ucache.impl
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi

View File

@@ -27,3 +27,4 @@ tooltip.this.definition.used.for.current.kotlin.script.configuration=This defini
progress.title.dependency.resolution=Dependency resolution
progress.text.resolving=Resolving {0}
progress.title.processing.scripts=Kotlin: Processing scripts\u2026

View File

@@ -8,6 +8,7 @@ import com.intellij.openapi.roots.ProjectRootManager
import org.jetbrains.kotlin.idea.base.plugin.artifacts.KotlinArtifacts
import org.jetbrains.kotlin.idea.core.script.k2.NewScriptFileInfo
import org.jetbrains.kotlin.idea.core.script.k2.kotlinScriptTemplateInfo
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
import java.io.File
@@ -37,18 +38,19 @@ private fun Project.javaHomePath(): File? {
val Project.defaultDefinition: ScriptDefinition
get() {
val project = this
val (compilationConfiguration, evaluationConfiguration) = createScriptDefinitionFromTemplate(
KotlinType(ScriptTemplateWithArgs::class),
defaultJvmScriptingHostConfiguration,
compilation = {
javaHomePath()?.let {
project.javaHomePath()?.let {
jvm.jdkHome(it)
}
dependencies(JvmDependency(scriptClassPath))
displayName("Default Kotlin Script")
hostConfiguration(defaultJvmScriptingHostConfiguration)
ide.dependenciesSources(JvmDependency(KotlinArtifacts.kotlinStdlibSources))
ide.kotlinScriptTemplateInfo(NewScriptFileInfo().apply{
ide.kotlinScriptTemplateInfo(NewScriptFileInfo().apply {
id = "default-kts"
title = ".kts"
})

View File

@@ -1,132 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.waitForSmartMode
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.jetbrains.kotlin.idea.core.script.*
import org.jetbrains.kotlin.idea.core.script.ucache.relativeName
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.with
import kotlin.script.experimental.jvm.jdkHome
import kotlin.script.experimental.jvm.jvm
open class BundledScriptConfigurationsSource(override val project: Project, val coroutineScope: CoroutineScope) :
ScriptConfigurationsSource<BaseScriptModel>(project) {
override fun getDefinitions(): Sequence<ScriptDefinition>? =
project.scriptDefinitionsSourceOfType<BundledScriptDefinitionSource>()?.definitions
override fun getConfigurationWithSdk(virtualFile: VirtualFile): ScriptConfigurationWithSdk? {
val current = data.get()[virtualFile]
if (current?.scriptConfiguration is ResultWithDiagnostics.Success) {
return current
}
if (KotlinScriptLazyResolveProhibitionCondition.prohibitLazyResolve(project, virtualFile)) return null
coroutineScope.launch {
project.waitForSmartMode()
val definition = findScriptDefinition(project, VirtualFileScriptSource(virtualFile))
val suitableDefinitions = getDefinitions() ?: return@launch
if (suitableDefinitions.none { it.definitionId == definition.definitionId }) return@launch
updateDependenciesAndCreateModules(setOf(BaseScriptModel(virtualFile)))
}
return data.get()[virtualFile]
}
override suspend fun updateConfigurations(scripts: Iterable<BaseScriptModel>) {
val sdk = ProjectRootManager.getInstance(project).projectSdk ?: ProjectJdkTable.getInstance().allJdks.firstOrNull()
val configurations = scripts.associate {
val scriptSource = VirtualFileScriptSource(it.virtualFile)
val definition = findScriptDefinition(project, scriptSource)
val providedConfiguration = sdk?.homePath?.let {
definition.compilationConfiguration.with {
jvm.jdkHome(File(it))
}
}
val result = smartReadAction(project) {
refineScriptCompilationConfiguration(scriptSource, definition, project, providedConfiguration)
}
project.service<ScriptReportSink>().attachReports(it.virtualFile, result.reports)
it.virtualFile to ScriptConfigurationWithSdk(result, sdk)
}
data.getAndAccumulate(configurations) { left, right -> left + right }
}
override suspend fun updateModules(storage: MutableEntityStorage?) {
val updatedStorage = getUpdatedStorage(
project, data.get()
) { KotlinBundledScriptModuleEntitySource(it) }
project.workspaceModel.update("updating .kts modules") {
it.replaceBySource(
{ source -> source is KotlinBundledScriptModuleEntitySource }, updatedStorage
)
}
}
private fun getUpdatedStorage(
project: Project,
configurationsData: Map<VirtualFile, ScriptConfigurationWithSdk>,
entitySourceSupplier: (virtualFileUrl: VirtualFileUrl) -> KotlinScriptEntitySource,
): MutableEntityStorage {
val updatedStorage = MutableEntityStorage.create()
for ((scriptFile, configurationWithSdk) in configurationsData) {
val definition = findScriptDefinition(project, VirtualFileScriptSource(scriptFile))
val definitionScriptModuleName = "$KOTLIN_SCRIPTS_MODULE_NAME.${definition.name}"
val locationName = scriptFile.relativeName(project).replace(VfsUtilCore.VFS_SEPARATOR_CHAR, ':')
val virtualFileManager = WorkspaceModel.getInstance(project).getVirtualFileUrlManager()
val source = entitySourceSupplier(scriptFile.toVirtualFileUrl(virtualFileManager))
val definitionDependency =
updatedStorage.getDefinitionLibraryEntity(definition, project, KotlinBundledScriptModuleEntitySource(null))?.let {
LibraryDependency(it.symbolicId, false, DependencyScope.COMPILE)
}
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
val allDependencies = listOfNotNull(sdkDependency, definitionDependency)
updatedStorage.addEntity(ModuleEntity("$definitionScriptModuleName.$locationName", allDependencies, source))
}
return updatedStorage
}
open class KotlinBundledScriptModuleEntitySource(override val virtualFileUrl: VirtualFileUrl?) :
KotlinScriptEntitySource(virtualFileUrl)
}

View File

@@ -0,0 +1,121 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.workspace.jps.entities.ModuleEntity
import com.intellij.platform.workspace.jps.entities.SdkDependency
import com.intellij.platform.workspace.jps.entities.SdkId
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.util.containers.addIfNotNull
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource
import org.jetbrains.kotlin.idea.core.script.compiledLibraryRoot
import org.jetbrains.kotlin.idea.core.script.getOrCreateLibrary
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathUtil.Companion.findVirtualFiles
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.api.valueOrNull
import kotlin.script.experimental.api.with
import kotlin.script.experimental.jvm.jdkHome
import kotlin.script.experimental.jvm.jvm
open class DefaultScriptConfigurationHandler(
val project: Project,
val coroutineScope: CoroutineScope
) : ScriptWorkspaceModelManager, ScriptRefinedConfigurationResolver {
private val data = ConcurrentHashMap<VirtualFile, ScriptConfigurationWithSdk>()
override suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptConfigurationWithSdk {
val current = data[virtualFile]
if (current != null) return current
val configuration = resolveScriptConfiguration(virtualFile, definition)
data[virtualFile] = configuration
return configuration
}
override fun get(virtualFile: VirtualFile): ScriptConfigurationWithSdk? = data[virtualFile]
private suspend fun resolveScriptConfiguration(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptConfigurationWithSdk {
val sdk = ProjectRootManager.getInstance(project).projectSdk ?: ProjectJdkTable.getInstance().allJdks.firstOrNull()
val scriptSource = VirtualFileScriptSource(virtualFile)
val providedConfiguration = sdk?.homePath?.let {
definition.compilationConfiguration.with {
jvm.jdkHome(File(it))
}
}
val result = smartReadAction(project) {
refineScriptCompilationConfiguration(scriptSource, definition, project, providedConfiguration)
}
project.service<ScriptReportSink>().attachReports(virtualFile, result.reports)
return ScriptConfigurationWithSdk(result, sdk)
}
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>) {
val workspaceModel = project.serviceAsync<WorkspaceModel>()
workspaceModel.update("updating .kts modules") {
val entityStorage = getUpdatedStorage(configurationPerFile, workspaceModel)
it.applyChangesFrom(entityStorage)
}
}
private fun getUpdatedStorage(
configurations: Map<VirtualFile, ScriptConfigurationWithSdk>,
workspaceModel: WorkspaceModel,
): MutableEntityStorage {
val result = MutableEntityStorage.from(workspaceModel.currentSnapshot)
val fileUrlManager = workspaceModel.getVirtualFileUrlManager()
for ((scriptFile, configurationWithSdk) in configurations) {
val definition = findScriptDefinition(project, VirtualFileScriptSource(scriptFile))
val moduleId = getModuleId(project, scriptFile, definition)
if (result.contains(moduleId)) continue
val wrapper = configurationWithSdk.scriptConfiguration.valueOrNull() ?: continue
val source = DefaultScriptEntitySource(scriptFile.toVirtualFileUrl(fileUrlManager))
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
val libraryDependencies = wrapper.configuration?.get(ScriptCompilationConfiguration.dependencies).findVirtualFiles()
.map { result.getOrCreateLibrary(it.name, listOf(it.compiledLibraryRoot(project)), source) }
val allDependencies = buildList {
addIfNotNull(sdkDependency)
addAll(libraryDependencies)
}
result.addEntity(ModuleEntity(moduleId.name, allDependencies, source))
}
return result
}
companion object {
@JvmStatic
fun getInstance(project: Project): DefaultScriptConfigurationHandler = project.service()
}
class DefaultScriptEntitySource(override val virtualFileUrl: VirtualFileUrl?) : KotlinScriptEntitySource(virtualFileUrl)
}

View File

@@ -0,0 +1,104 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile
import com.intellij.openapi.application.edtWriteAction
import com.intellij.openapi.application.readAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.platform.ide.progress.withBackgroundProgress
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.jetbrains.kotlin.analysis.api.platform.modification.publishGlobalModuleStateModificationEvent
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.script.alwaysVirtualFile
import org.jetbrains.kotlin.idea.core.script.scriptingErrorLog
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ide
@Service(Service.Level.PROJECT)
class DefaultScriptResolutionStrategy(val project: Project, val coroutineScope: CoroutineScope) {
fun isReadyToHighlight(ktFile: KtFile): Boolean {
val definition = ktFile.findScriptDefinition()
if (definition == null) {
return false
}
val configurationsSupplier = definition.refinedConfigurationSupplier()
val projectModelUpdater = definition.projectModelUpdater()
return configurationsSupplier.get(ktFile.alwaysVirtualFile) != null
&& projectModelUpdater.isModuleExist(project, ktFile.alwaysVirtualFile, definition)
}
fun execute(vararg ktFiles: KtFile): Job {
val firstDefinition = ktFiles.firstNotNullOfOrNull { it.findScriptDefinition() }
if (firstDefinition == null) {
scriptingErrorLog("failed to find script definition", IllegalStateException())
return Job()
}
val configurationsSupplier = firstDefinition.refinedConfigurationSupplier()
val projectModelUpdater = firstDefinition.projectModelUpdater()
val definitionByVirtualFile = ktFiles.associate {
it.alwaysVirtualFile to findScriptDefinition(
project,
VirtualFileScriptSource(it.alwaysVirtualFile)
)
}
return coroutineScope.launch {
withBackgroundProgress(project, KotlinBaseScriptingBundle.message("progress.title.processing.scripts")) {
val configurationPerVirtualFile = definitionByVirtualFile.entries.associate { (script, definition) ->
val configuration = configurationsSupplier.get(script)
?: configurationsSupplier.create(script, definition)
?: return@withBackgroundProgress
script to configuration
}
projectModelUpdater.updateWorkspaceModel(configurationPerVirtualFile)
ScriptConfigurationsProviderImpl.getInstance(project).store(configurationPerVirtualFile.values)
edtWriteAction {
project.publishGlobalModuleStateModificationEvent()
}
ScriptDependenciesModificationTracker.Companion.getInstance(project).incModificationCount()
HighlightingSettingsPerFile.getInstance(project).incModificationCount()
if (project.isOpen && !project.isDisposed) {
val focusedFile = readAction { FileEditorManager.getInstance(project).focusedEditor?.file }
ktFiles.firstOrNull { it.alwaysVirtualFile == focusedFile }?.let {
readAction {
DaemonCodeAnalyzer.getInstance(project).restart(it)
}
}
}
}
}
}
private fun ScriptDefinition.refinedConfigurationSupplier(): ScriptRefinedConfigurationResolver =
compilationConfiguration[ScriptCompilationConfiguration.ide.configurationResolverDelegate]?.invoke()
?: DefaultScriptConfigurationHandler.getInstance(project)
private fun ScriptDefinition.projectModelUpdater(): ScriptWorkspaceModelManager =
compilationConfiguration[ScriptCompilationConfiguration.ide.scriptWorkspaceModelManagerDelegate]?.invoke()
?: DefaultScriptConfigurationHandler.getInstance(project)
companion object {
@JvmStatic
fun getInstance(project: Project): DefaultScriptResolutionStrategy = project.service()
}
}

View File

@@ -1,291 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.progress.runBlockingMaybeCancellable
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
import com.intellij.psi.util.childrenOfType
import com.intellij.util.containers.addIfNotNull
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.amper.dependency.resolution.LocalM2RepositoryFinder
import org.jetbrains.kotlin.idea.core.script.*
import org.jetbrains.kotlin.idea.core.script.ucache.relativeName
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
import org.jetbrains.kotlin.psi.KtValueArgumentList
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import java.nio.file.Files
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.valueOrNull
import kotlin.script.experimental.api.with
import kotlin.script.experimental.jvm.jdkHome
import kotlin.script.experimental.jvm.jvm
class DependentScriptConfigurationsSource(override val project: Project, val coroutineScope: CoroutineScope) :
ScriptConfigurationsSource<BaseScriptModel>(project) {
private val m2LocalRepositoryPath = LocalM2RepositoryFinder.findPath()
override fun getConfigurationWithSdk(virtualFile: VirtualFile): ScriptConfigurationWithSdk? {
data.get()[virtualFile]?.let { return it }
val ktFile = virtualFile.toPsiFile(project) as? KtFile ?: return null
if (ktFile.hasNoDependencies()) {
runBlockingMaybeCancellable {
DependencyResolutionService.getInstance(project).resolveInBackground {
handleNoDependencies(virtualFile)
}
}
} else if (ktFile.dependenciesExistLocally()) {
runBlockingMaybeCancellable {
DependencyResolutionService.getInstance(project).resolveInBackground {
updateDependenciesAndCreateModules(listOf(BaseScriptModel(virtualFile)))
}
}
}
return data.get()[virtualFile]
}
private suspend fun handleNoDependencies(script: VirtualFile) {
val sourceCode = VirtualFileScriptSource(script)
val definition = findScriptDefinition(project, sourceCode)
val result = ResultWithDiagnostics.Success(
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
sourceCode, definition.compilationConfiguration
)
)
val projectSdk = ProjectJdkTable.getInstance().allJdks.firstOrNull()
val entry = mapOf(script to ScriptConfigurationWithSdk(result, projectSdk))
data.getAndAccumulate(entry) { left, right -> left + right }
ScriptConfigurationsProviderImpl.getInstance(project).notifySourceUpdated()
updateModules()
val filesInEditors = readAction {
FileEditorManager.getInstance(project).allEditors.mapTo(hashSetOf(), FileEditor::getFile)
}
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
HighlightingSettingsPerFile.getInstance(project).incModificationCount()
if (script in filesInEditors) {
if (project.isOpen && !project.isDisposed) {
readAction {
val ktFile = script.toPsiFile(project) as? KtFile ?: error("Cannot convert to PSI file: $script")
DaemonCodeAnalyzer.getInstance(project).restart(ktFile)
}
}
}
}
override fun getDefinitions(): Sequence<ScriptDefinition>? =
project.scriptDefinitionsSourceOfType<MainKtsScriptDefinitionSource>()?.definitions
override suspend fun updateConfigurations(scripts: Iterable<BaseScriptModel>) {
val sdk = ProjectJdkTable.getInstance().allJdks.firstOrNull()
val configurations = scripts.associate {
val scriptSource = VirtualFileScriptSource(it.virtualFile)
val definition = findScriptDefinition(project, scriptSource)
val providedConfiguration = sdk?.homePath?.let { jdkHome ->
definition.compilationConfiguration.with {
jvm.jdkHome(File(jdkHome))
}
}
val result = smartReadAction(project) {
refineScriptCompilationConfiguration(scriptSource, definition, project, providedConfiguration)
}
project.service<ScriptReportSink>().attachReports(it.virtualFile, result.reports)
it.virtualFile to ScriptConfigurationWithSdk(result, sdk)
}
data.getAndAccumulate(configurations) { left, right -> left + right }
}
override suspend fun updateModules(storage: MutableEntityStorage?) {
val updatedStorage = getUpdatedStorage(project, data.get())
project.workspaceModel.update("updating .main.kts modules") { targetStorage ->
targetStorage.replaceBySource(
{ it is KotlinDependentScriptModuleEntitySource }, updatedStorage
)
}
}
private fun KtFile.hasNoDependencies() = annotationEntries.none { it.text.startsWith("@file:DependsOn") }
private suspend fun getUpdatedStorage(
project: Project,
configurationsData: Map<VirtualFile, ScriptConfigurationWithSdk>,
): MutableEntityStorage {
val virtualFileManager = project.serviceAsync<WorkspaceModel>().getVirtualFileUrlManager()
val libraryFactory = LibraryDependencyFactory(virtualFileManager) {
KotlinDependentScriptModuleEntitySource(it)
}
val updatedStorage = MutableEntityStorage.create()
for ((scriptFile, configurationWithSdk) in configurationsData) {
val configuration = configurationWithSdk.scriptConfiguration.valueOrNull() ?: continue
val definition = findScriptDefinition(project, VirtualFileScriptSource(scriptFile))
val definitionScriptModuleName = "$KOTLIN_SCRIPTS_MODULE_NAME.${definition.name}"
val locationName = scriptFile.relativeName(project).replace(VfsUtilCore.VFS_SEPARATOR_CHAR, ':')
val source = KotlinDependentScriptModuleEntitySource(scriptFile.toVirtualFileUrl(virtualFileManager))
val libraryDependencies = updatedStorage.addLibraryDependencies(configuration, source, definition, locationName, libraryFactory)
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
val allDependencies = listOfNotNull(sdkDependency) + libraryDependencies
updatedStorage.addEntity(ModuleEntity("$definitionScriptModuleName.$locationName", allDependencies, source))
}
return updatedStorage
}
private suspend fun MutableEntityStorage.addLibraryDependencies(
configurationWrapper: ScriptCompilationConfigurationWrapper,
source: KotlinScriptEntitySource,
definition: ScriptDefinition,
locationName: String,
libraryFactory: LibraryDependencyFactory
): List<LibraryDependency> {
val definitionLibraryEntity = getDefinitionLibraryEntity(definition, project, source)
val rootsToSkip = definitionLibraryEntity?.roots?.map { it.url }?.toSet() ?: emptySet()
val urlManager = project.serviceAsync<WorkspaceModel>().getVirtualFileUrlManager()
val storage = this
val scriptClassPathCache = ScriptClassPathVirtualFileCache.getInstance()
val classes = configurationWrapper.dependenciesClassPath.mapNotNull { scriptClassPathCache.findVirtualFile(it.path) }
.filterNot { it.toVirtualFileUrl(urlManager) in rootsToSkip }
.sortedBy { it.name }.distinct()
return buildList {
addIfNotNull(definitionLibraryEntity?.let { LibraryDependency(it.symbolicId, false, DependencyScope.COMPILE) })
if (configurationWrapper.isUberDependencyAllowed()) {
val sources =
configurationWrapper.dependenciesSources.mapNotNull { scriptClassPathCache.findVirtualFile(it.path) }
.filterNot { it.toVirtualFileUrl(urlManager) in rootsToSkip }
.sortedBy { it.name }
addIfNotNull(storage.createUberDependency(locationName, classes, sources, source))
} else {
addAll(classes.map {
LibraryDependency(libraryFactory.get(it, storage).symbolicId, false, DependencyScope.COMPILE)
})
}
}
}
private suspend fun MutableEntityStorage.createUberDependency(
locationName: String,
classes: List<VirtualFile>,
sources: List<VirtualFile>,
source: KotlinScriptEntitySource,
): LibraryDependency? {
if (classes.isEmpty() && sources.isEmpty()) return null
val fileUrlManager = project.serviceAsync<WorkspaceModel>().getVirtualFileUrlManager()
val classRoots = classes.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.COMPILED)
}
val sourceRoots = sources.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.SOURCES)
}
val dependencyLibrary =
addEntity(LibraryEntity("$locationName dependencies", LibraryTableId.ProjectLibraryTableId, classRoots + sourceRoots, source))
return LibraryDependency(dependencyLibrary.symbolicId, false, DependencyScope.COMPILE)
}
private fun ScriptCompilationConfigurationWrapper.isUberDependencyAllowed(): Boolean {
return dependenciesSources.size + dependenciesClassPath.size < 20
}
private fun KtFile.dependenciesExistLocally(): Boolean {
val artifactLocations = script?.annotationEntries?.filter { it.text.startsWith("@file:DependsOn") }?.mapNotNull {
it.childrenOfType<KtValueArgumentList>().singleOrNull()
?.arguments?.singleOrNull()
?.stringTemplateExpression?.childrenOfType<KtLiteralStringTemplateEntry>()
?.singleOrNull()
?.text
} ?: return true
return artifactLocations.all {
val splitted = it.split(":")
val group = splitted[0]
val module = splitted[1]
val version = splitted[2]
val dependencyPath = m2LocalRepositoryPath.resolve(
"${group.split('.').joinToString("/")}/$module/$version"
)
Files.exists(dependencyPath)
}
}
}
class KotlinDependentScriptModuleEntitySource(override val virtualFileUrl: VirtualFileUrl?) : KotlinScriptEntitySource(virtualFileUrl)
private class LibraryDependencyFactory(
private val fileUrlManager: VirtualFileUrlManager,
private val entitySourceSupplier: (virtualFileUrl: VirtualFileUrl) -> KotlinScriptEntitySource,
) {
private val cache = HashMap<VirtualFile, LibraryEntity>()
fun get(file: VirtualFile, storage: MutableEntityStorage): LibraryEntity {
return cache.computeIfAbsent(file) {
storage.createLibrary(file)
}
}
fun MutableEntityStorage.createLibrary(file: VirtualFile): LibraryEntity {
val fileUrl = file.toVirtualFileUrl(fileUrlManager)
val libraryRoot = LibraryRoot(fileUrl, LibraryRootTypeId.COMPILED)
val libraryEntity =
LibraryEntity(file.name, LibraryTableId.ProjectLibraryTableId, listOf(libraryRoot), entitySourceSupplier(fileUrl))
return addEntity(libraryEntity)
}
}

View File

@@ -11,12 +11,12 @@ import com.intellij.openapi.vfs.VirtualFile
*/
interface KotlinScriptLazyResolveProhibitionCondition {
companion object {
val EP_NAME =
val EP_NAME: ProjectExtensionPointName<KotlinScriptLazyResolveProhibitionCondition> =
ProjectExtensionPointName<KotlinScriptLazyResolveProhibitionCondition>("org.jetbrains.kotlin.kotlinScriptLazyResolveProhibitionCondition")
fun prohibitLazyResolve(project: Project, script: VirtualFile): Boolean =
EP_NAME.getExtensions(project).any { it.prohibitLazyResolve(script) }
fun shouldPostponeResolution(project: Project, script: VirtualFile): Boolean =
EP_NAME.getExtensions(project).any { it.shouldPostponeResolution(script) }
}
fun prohibitLazyResolve(script: VirtualFile): Boolean = false
fun shouldPostponeResolution(script: VirtualFile): Boolean = false
}

View File

@@ -0,0 +1,219 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.psi.util.childrenOfType
import com.intellij.util.containers.addIfNotNull
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.amper.dependency.resolution.LocalM2RepositoryFinder
import org.jetbrains.kotlin.idea.core.script.*
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathUtil.Companion.findVirtualFiles
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
import org.jetbrains.kotlin.psi.KtValueArgumentList
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import java.nio.file.Files
import java.util.concurrent.ConcurrentHashMap
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.jdkHome
import kotlin.script.experimental.jvm.jvm
@Service(Service.Level.PROJECT)
class MainKtsScriptConfigurationProvider(val project: Project, val coroutineScope: CoroutineScope) : ScriptRefinedConfigurationResolver,
ScriptWorkspaceModelManager {
private val data = ConcurrentHashMap<VirtualFile, ScriptConfigurationWithSdk>()
private val m2LocalRepositoryPath = LocalM2RepositoryFinder.findPath()
override fun get(virtualFile: VirtualFile): ScriptConfigurationWithSdk? = data[virtualFile]
override suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptConfigurationWithSdk? {
val ktFile = readAction { virtualFile.toPsiFile(project) as? KtFile } ?: return null
val hasNoDependencies = readAction { ktFile.hasNoDependencies() }
if (hasNoDependencies) {
createNoDependenciesConfiguration(virtualFile)
} else if (ktFile.dependenciesExistLocally()) {
refineConfiguration(virtualFile)
}
return data[virtualFile]
}
suspend fun refineConfiguration(virtualFile: VirtualFile): ScriptConfigurationWithSdk {
val sdk = ProjectJdkTable.getInstance().allJdks.firstOrNull()
val scriptSource = VirtualFileScriptSource(virtualFile)
val definition = findScriptDefinition(project, scriptSource)
val providedConfiguration = sdk?.homePath?.let { jdkHome ->
definition.compilationConfiguration.with {
jvm.jdkHome(File(jdkHome))
}
}
val result = smartReadAction(project) {
refineScriptCompilationConfiguration(scriptSource, definition, project, providedConfiguration)
}
project.service<ScriptReportSink>().attachReports(virtualFile, result.reports)
val newData = ScriptConfigurationWithSdk(result, sdk)
data[virtualFile] = newData
return newData
}
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>) {
val updatedStorage = getUpdatedStorage(project, configurationPerFile)
project.workspaceModel.update("updating .main.kts modules") { targetStorage ->
targetStorage.applyChangesFrom(updatedStorage)
}
}
private suspend fun getUpdatedStorage(
project: Project,
configurationsData: Map<VirtualFile, ScriptConfigurationWithSdk>,
): MutableEntityStorage {
val virtualFileManager = project.serviceAsync<WorkspaceModel>().getVirtualFileUrlManager()
val storageToUpdate = MutableEntityStorage.from(project.workspaceModel.currentSnapshot)
for ((scriptFile, configurationWithSdk) in configurationsData) {
val configuration = configurationWithSdk.scriptConfiguration.valueOrNull() ?: continue
val definition = findScriptDefinition(project, VirtualFileScriptSource(scriptFile))
val source = MainKtsKotlinScriptEntitySource(scriptFile.toVirtualFileUrl(virtualFileManager))
val locationName = project.scriptModuleRelativeLocation(scriptFile)
val libraryDependencies =
storageToUpdate.getDependencies(configuration, source, definition, locationName)
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
val allDependencies = listOfNotNull(sdkDependency) + libraryDependencies
val scriptModuleId = ModuleId("${KOTLIN_SCRIPTS_MODULE_NAME}.${definition.name}.$locationName")
val existingModule = storageToUpdate.resolve(scriptModuleId)
if (existingModule == null) {
storageToUpdate.addEntity(
ModuleEntity(scriptModuleId.name, allDependencies, source)
)
} else {
storageToUpdate.modifyModuleEntity(existingModule) {
dependencies = allDependencies.toMutableList()
}
}
}
return storageToUpdate
}
private fun KtFile.hasNoDependencies() = annotationEntries.none { it.text.startsWith("@file:DependsOn") }
private fun MutableEntityStorage.getDependencies(
wrapper: ScriptCompilationConfigurationWrapper,
source: KotlinScriptEntitySource,
definition: ScriptDefinition,
locationName: String
): List<LibraryDependency> {
val definitionDependency = getOrCreateDefinitionDependency(definition, project, source)
val storage = this
return buildList {
if (wrapper.isUberDependencyAllowed()) {
val classes = wrapper.configuration?.get(ScriptCompilationConfiguration.dependencies).findVirtualFiles()
val sources = wrapper.configuration?.get(ScriptCompilationConfiguration.ide.dependenciesSources).findVirtualFiles()
addIfNotNull(storage.createUberDependency(locationName, classes, sources, source))
} else {
add(definitionDependency)
val classes = wrapper.configuration?.get(ScriptCompilationConfiguration.dependencies)?.drop(1).findVirtualFiles()
addAll(
classes.map {
getOrCreateLibrary(it.name, listOf(it.compiledLibraryRoot(project)), source)
}
)
}
}
}
private fun MutableEntityStorage.createUberDependency(
locationName: String,
classes: List<VirtualFile>,
sources: List<VirtualFile>,
source: KotlinScriptEntitySource,
): LibraryDependency? {
if (classes.isEmpty() && sources.isEmpty()) return null
val classRoots = classes.map { it.compiledLibraryRoot(project) }
val sourceRoots = sources.map { it.sourceLibraryRoot(project) }
return createOrUpdateLibrary("$locationName dependencies", classRoots + sourceRoots, source)
}
private fun ScriptCompilationConfigurationWrapper.isUberDependencyAllowed(): Boolean {
return dependenciesSources.size + dependenciesClassPath.size < 20
}
private suspend fun KtFile.dependenciesExistLocally(): Boolean {
val artifactLocations = readAction {
script?.annotationEntries?.filter { it.text.startsWith("@file:DependsOn") }?.mapNotNull {
it.childrenOfType<KtValueArgumentList>()
.singleOrNull()?.arguments?.singleOrNull()?.stringTemplateExpression?.childrenOfType<KtLiteralStringTemplateEntry>()
?.singleOrNull()?.text
}
} ?: return true
return artifactLocations.all {
val splitted = it.split(":")
val group = splitted[0]
val module = splitted[1]
val version = splitted[2]
val dependencyPath = m2LocalRepositoryPath.resolve(
"${group.split('.').joinToString("/")}/$module/$version"
)
Files.exists(dependencyPath)
}
}
private fun createNoDependenciesConfiguration(script: VirtualFile) {
val sourceCode = VirtualFileScriptSource(script)
val definition = findScriptDefinition(project, sourceCode)
val result = ResultWithDiagnostics.Success(
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
sourceCode, definition.compilationConfiguration
)
)
val projectSdk = ProjectJdkTable.getInstance().allJdks.firstOrNull()
data[script] = ScriptConfigurationWithSdk(result, projectSdk)
}
companion object {
@JvmStatic
fun getInstance(project: Project): MainKtsScriptConfigurationProvider = project.service()
}
class MainKtsKotlinScriptEntitySource(override val virtualFileUrl: VirtualFileUrl?) : KotlinScriptEntitySource(virtualFileUrl)
}

View File

@@ -7,24 +7,19 @@ import org.jetbrains.kotlin.idea.base.plugin.artifacts.KotlinArtifacts
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
import java.io.File
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.withTransformedResolvers
import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
class MainKtsScriptDefinitionSource(val project: Project) : ScriptDefinitionsSource {
val classPath: List<File> = listOf(
KotlinArtifacts.kotlinMainKts,
KotlinArtifacts.kotlinScriptRuntime,
KotlinArtifacts.kotlinStdlib,
KotlinArtifacts.kotlinReflect
)
override val definitions: Sequence<ScriptDefinition>
get() {
val discoveredDefinitions = ScriptDefinitionsFromClasspathDiscoverySource(
classPath, defaultJvmScriptingHostConfiguration, ::loggingReporter
listOf(KotlinArtifacts.kotlinMainKts, KotlinArtifacts.kotlinStdlib, KotlinArtifacts.kotlinScriptRuntime, KotlinArtifacts.kotlinReflect),
defaultJvmScriptingHostConfiguration,
::loggingReporter
).definitions
return discoveredDefinitions.map { definition ->
@@ -32,17 +27,25 @@ class MainKtsScriptDefinitionSource(val project: Project) : ScriptDefinitionsSou
ReportingExternalDependenciesResolver(it, DependencyResolutionService.getInstance(project))
}.with {
ide.dependenciesSources(JvmDependency(KotlinArtifacts.kotlinStdlibSources))
ide.kotlinScriptTemplateInfo(NewScriptFileInfo().apply {
id = "main-kts"
title = ".main.kts"
templateName = "Kotlin Script MainKts"
})
ide {
kotlinScriptTemplateInfo(NewScriptFileInfo().apply {
id = "main-kts"
title = ".main.kts"
templateName = "Kotlin Script MainKts"
})
configurationResolverDelegate {
MainKtsScriptConfigurationProvider.getInstance(project)
}
scriptWorkspaceModelManagerDelegate {
MainKtsScriptConfigurationProvider.getInstance(project)
}
}
}
ScriptDefinition.FromConfigurations(
compilationConfiguration[ScriptCompilationConfiguration.hostConfiguration] ?: defaultJvmScriptingHostConfiguration,
compilationConfiguration,
definition.evaluationConfiguration ?: ScriptEvaluationConfiguration.Default
definition.evaluationConfiguration
).apply {
order = Int.MIN_VALUE
}
@@ -53,11 +56,10 @@ class MainKtsScriptDefinitionSource(val project: Project) : ScriptDefinitionsSou
fun loggingReporter(severity: ScriptDiagnostic.Severity, message: String) {
val log = Logger.getInstance("ScriptDefinitionsProviders")
when (severity) {
ScriptDiagnostic.Severity.FATAL,
ScriptDiagnostic.Severity.ERROR -> log.error(message)
ScriptDiagnostic.Severity.WARNING,
ScriptDiagnostic.Severity.INFO -> log.info(message)
ScriptDiagnostic.Severity.FATAL, ScriptDiagnostic.Severity.ERROR -> log.error(message)
ScriptDiagnostic.Severity.WARNING, ScriptDiagnostic.Severity.INFO -> log.info(message)
else -> {}
}
}

View File

@@ -12,19 +12,30 @@ import kotlin.io.path.isDirectory
import kotlin.io.path.isRegularFile
import kotlin.io.path.notExists
import kotlin.io.path.pathString
import kotlin.script.experimental.api.ScriptDependency
import kotlin.script.experimental.jvm.JvmDependency
class ScriptClassPathVirtualFileCache {
class ScriptClassPathUtil {
private constructor()
private val cache = mutableMapOf<String, VirtualFile?>()
fun findVirtualFile(pathString: String): VirtualFile? =
cache.computeIfAbsent(pathString) {
ScriptClassPathVirtualFileCache.findVirtualFile(pathString)
ScriptClassPathUtil.findVirtualFile(pathString)
}
companion object {
fun getInstance(): ScriptClassPathVirtualFileCache = ScriptClassPathVirtualFileCache()
fun getInstance(): ScriptClassPathUtil = ScriptClassPathUtil()
fun List<ScriptDependency>?.findVirtualFiles(): List<VirtualFile> {
this ?: return emptyList()
return this
.flatMap { (it as? JvmDependency)?.classpath ?: emptyList() }
.distinct()
.mapNotNull { findVirtualFile(it.path) }
.sortedBy { it.name }
}
fun findVirtualFile(pathString: String): VirtualFile? {
val path = pathString.toNioPathOrNull()

View File

@@ -12,62 +12,55 @@ import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.NonClasspathDirectoriesScope.compose
import org.jetbrains.kotlin.idea.core.script.*
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.kotlin.idea.core.script.ScriptDependencyAware
import org.jetbrains.kotlin.idea.core.script.alwaysVirtualFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptConfigurationsProvider
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import java.util.concurrent.atomic.AtomicReference
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ide
import kotlin.script.experimental.api.valueOrNull
private class ScriptDependenciesData(
val classes: Set<VirtualFile> = mutableSetOf(),
val sources: Set<VirtualFile> = mutableSetOf(),
val sdks: Set<Sdk> = mutableSetOf(),
)
class ScriptConfigurationsProviderImpl(project: Project) : ScriptConfigurationsProvider(project), ScriptDependencyAware {
private val allDependencies = AtomicReference(ScriptDependenciesData())
private val dependenciesSourceByDefinition = AtomicReference(mapOf<String, ScriptConfigurationsSource<*>>())
init {
notifySourceUpdated()
) {
operator fun plus(other: ScriptDependenciesData): ScriptDependenciesData {
return ScriptDependenciesData(
this.classes + other.classes,
this.sources + other.sources,
this.sdks + other.sdks
)
}
fun notifySourceUpdated() {
val configurationSources = SCRIPT_CONFIGURATIONS_SOURCES.getExtensions(project)
val allScriptsSources = mutableSetOf<VirtualFile>()
val allScriptClasses = mutableSetOf<VirtualFile>()
val allScriptsSdks = mutableSetOf<Sdk>()
val sourceByDefinition = mutableMapOf<String, ScriptConfigurationsSource<*>>()
val virtualFileCache = ScriptClassPathVirtualFileCache.getInstance()
configurationSources.forEach { source ->
val data = source.data.get()
val configurations = data.values.mapNotNull { it.scriptConfiguration.valueOrNull() }
val sdks = data.values.mapNotNull { it.sdk }
configurations.forEach {
allScriptsSources.addAll(it.dependenciesSources.mapNotNull { file -> virtualFileCache.findVirtualFile(file.path) })
allScriptClasses.addAll(it.dependenciesClassPath.mapNotNull { file -> virtualFileCache.findVirtualFile(file.path) })
}
allScriptsSdks.addAll(sdks)
source.getDefinitions()?.forEach { sourceByDefinition.put(it.definitionId, source) }
companion object {
fun from(configuration: ScriptConfigurationWithSdk): ScriptDependenciesData {
val cache = ScriptClassPathUtil.getInstance()
return ScriptDependenciesData(
configuration.scriptConfiguration.valueOrNull()?.dependenciesClassPath?.mapNotNull { cache.findVirtualFile(it.path) }
?.toSet() ?: emptySet(),
configuration.scriptConfiguration.valueOrNull()?.dependenciesSources?.mapNotNull { cache.findVirtualFile(it.path) }
?.toSet() ?: emptySet(),
)
}
}
}
val definitionsFromProviders = project.scriptDefinitionsSourceOfType<BridgeScriptDefinitionsContributor>()?.definitions
val defaultScriptConfigurationSource = project.scriptConfigurationsSourceOfType<BundledScriptConfigurationsSource>()
if (defaultScriptConfigurationSource != null) {
definitionsFromProviders?.forEach { sourceByDefinition.put(it.definitionId, defaultScriptConfigurationSource) }
class ScriptConfigurationsProviderImpl(project: Project, val coroutineScope: CoroutineScope) : ScriptConfigurationsProvider(project),
ScriptDependencyAware {
private val allDependencies = AtomicReference(ScriptDependenciesData())
fun store(configurations: Collection<ScriptConfigurationWithSdk>) {
val dataToAdd = configurations.fold(ScriptDependenciesData()) { left, right ->
left + ScriptDependenciesData.from(right)
}
dependenciesSourceByDefinition.set(sourceByDefinition)
allDependencies.set(ScriptDependenciesData(allScriptClasses, allScriptsSources, allScriptsSdks))
allDependencies.accumulateAndGet(dataToAdd) { left, right -> left + right }
}
override fun getAllScriptDependenciesSources(): Collection<VirtualFile> = allDependencies.get()?.sources ?: emptyList()
@@ -86,7 +79,7 @@ class ScriptConfigurationsProviderImpl(project: Project) : ScriptConfigurationsP
val (configuration, sdk) = getConfigurationWithSdk(virtualFile) ?: return GlobalSearchScope.EMPTY_SCOPE
val configurationWrapper = configuration.valueOrNull() ?: return GlobalSearchScope.EMPTY_SCOPE
val roots = configurationWrapper.dependenciesClassPath.mapNotNull { ScriptClassPathVirtualFileCache.findVirtualFile(it.path) }
val roots = configurationWrapper.dependenciesClassPath.mapNotNull { ScriptClassPathUtil.findVirtualFile(it.path) }
val sdkClasses = sdk?.rootProvider?.getFiles(OrderRootType.CLASSES)?.toList() ?: emptyList<VirtualFile>()
@@ -94,8 +87,9 @@ class ScriptConfigurationsProviderImpl(project: Project) : ScriptConfigurationsP
}
override fun getScriptDependenciesClassFiles(virtualFile: VirtualFile): Collection<VirtualFile> {
val dependencies = getConfigurationWithSdk(virtualFile)?.scriptConfiguration?.valueOrNull()?.dependenciesClassPath ?: return emptyList()
return dependencies.mapNotNull { ScriptClassPathVirtualFileCache.findVirtualFile(it.path) }
val dependencies =
getConfigurationWithSdk(virtualFile)?.scriptConfiguration?.valueOrNull()?.dependenciesClassPath ?: return emptyList()
return dependencies.mapNotNull { ScriptClassPathUtil.findVirtualFile(it.path) }
}
override fun getFirstScriptsSdk(): Sdk? = getProjectSdk() ?: allDependencies.get().sdks.firstOrNull()
@@ -114,16 +108,19 @@ class ScriptConfigurationsProviderImpl(project: Project) : ScriptConfigurationsP
private fun Sdk.canBeUsedForScript() = sdkType is JavaSdkType && hasValidClassPathRoots()
override fun getScriptConfigurationResult(file: KtFile): ScriptCompilationConfigurationResult? =
getConfigurationWithSdk(file.alwaysVirtualFile)?.scriptConfiguration
override fun getScriptConfigurationResult(file: KtFile): ScriptCompilationConfigurationResult? {
val definition = file.findScriptDefinition() ?: return null
return getConfigurationSupplier(definition).get(file.alwaysVirtualFile)?.scriptConfiguration
}
fun getConfigurationWithSdk(virtualFile: VirtualFile): ScriptConfigurationWithSdk? =
resolveSource(virtualFile)?.getConfigurationWithSdk(virtualFile)
private fun getConfigurationSupplier(definition: ScriptDefinition): ScriptRefinedConfigurationResolver {
return definition.compilationConfiguration[ScriptCompilationConfiguration.ide.configurationResolverDelegate]?.invoke()
?: DefaultScriptConfigurationHandler.getInstance(project)
}
fun resolveSource(virtualFile: VirtualFile): ScriptConfigurationsSource<*>? {
fun getConfigurationWithSdk(virtualFile: VirtualFile): ScriptConfigurationWithSdk? {
val definition = findScriptDefinition(project, VirtualFileScriptSource(virtualFile))
return dependenciesSourceByDefinition.get()[definition.definitionId]
?: project.scriptConfigurationsSourceOfType<DependentScriptConfigurationsSource>()
return getConfigurationSupplier(definition).get(virtualFile)
}
private fun ScriptDependenciesData.getSdkSources(): List<VirtualFile> =

View File

@@ -1,80 +1,17 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.edtWriteAction
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.workspace.storage.MutableEntityStorage
import org.jetbrains.kotlin.analysis.api.platform.modification.publishGlobalModuleStateModificationEvent
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import java.util.concurrent.atomic.AtomicReference
import kotlin.script.experimental.api.ResultWithDiagnostics
typealias ScriptConfiguration = ResultWithDiagnostics<ScriptCompilationConfigurationWrapper>
open class BaseScriptModel(
open val virtualFile: VirtualFile
) {
override fun toString(): String {
return "BaseScriptModel(virtualFile=$virtualFile)"
}
}
data class ScriptConfigurationWithSdk(
val scriptConfiguration: ScriptConfiguration,
val sdk: Sdk?,
)
abstract class ScriptConfigurationsSource<T : BaseScriptModel>(open val project: Project) {
val data: AtomicReference<Map<VirtualFile, ScriptConfigurationWithSdk>> = AtomicReference(emptyMap())
abstract fun getDefinitions(): Sequence<ScriptDefinition>?
open fun getConfigurationWithSdk(virtualFile: VirtualFile): ScriptConfigurationWithSdk? =
data.get()[virtualFile]
protected abstract suspend fun updateConfigurations(scripts: Iterable<T>)
abstract suspend fun updateModules(storage: MutableEntityStorage? = null)
suspend fun updateDependenciesAndCreateModules(scripts: Iterable<T>, storage: MutableEntityStorage? = null) {
updateConfigurations(scripts)
updateModules(storage)
ScriptConfigurationsProviderImpl.getInstance(project).notifySourceUpdated()
edtWriteAction {
project.publishGlobalModuleStateModificationEvent()
}
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
HighlightingSettingsPerFile.getInstance(project).incModificationCount()
val filesInEditors = readAction {
FileEditorManager.getInstance(project).allEditors.mapTo(hashSetOf(), FileEditor::getFile)
}
for (script in scripts) {
val virtualFile = script.virtualFile
if (virtualFile !in filesInEditors) continue
if (project.isOpen && !project.isDisposed) {
readAction {
val ktFile = virtualFile.toPsiFile(project) as? KtFile ?: error("Cannot convert to PSI file: $virtualFile")
DaemonCodeAnalyzer.getInstance(project).restart(ktFile)
}
}
}
) {
companion object {
val EMPTY: ScriptConfigurationWithSdk = ScriptConfigurationWithSdk(ResultWithDiagnostics.Failure(), null)
}
}
}

View File

@@ -1,17 +1,24 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.ModuleId
import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.idea.core.script.KOTLIN_SCRIPTS_MODULE_NAME
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import java.io.File
import javax.swing.Icon
import kotlin.script.experimental.api.IdeScriptCompilationConfigurationKeys
import kotlin.script.experimental.util.PropertiesCollection
class NewScriptFileInfo(
var id: String = "",
var title: String = "",
var templateName: String = "Kotlin Script",
var icon: Icon = KotlinIcons.SCRIPT
var id: String = "", var title: String = "", var templateName: String = "Kotlin Script", var icon: Icon = KotlinIcons.SCRIPT
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -27,4 +34,38 @@ class NewScriptFileInfo(
}
}
val IdeScriptCompilationConfigurationKeys.kotlinScriptTemplateInfo: PropertiesCollection.Key<NewScriptFileInfo> by PropertiesCollection.key()
val IdeScriptCompilationConfigurationKeys.kotlinScriptTemplateInfo: PropertiesCollection.Key<NewScriptFileInfo> by PropertiesCollection.key()
val IdeScriptCompilationConfigurationKeys.configurationResolverDelegate: PropertiesCollection.Key<() -> ScriptRefinedConfigurationResolver> by PropertiesCollection.key()
val IdeScriptCompilationConfigurationKeys.scriptWorkspaceModelManagerDelegate: PropertiesCollection.Key<() -> ScriptWorkspaceModelManager> by PropertiesCollection.key()
interface ScriptRefinedConfigurationResolver {
suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptConfigurationWithSdk?
fun get(virtualFile: VirtualFile): ScriptConfigurationWithSdk?
}
interface ScriptWorkspaceModelManager {
suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>)
fun isModuleExist(
project: Project, scriptFile: VirtualFile, definition: ScriptDefinition
): Boolean = project.workspaceModel.currentSnapshot.contains(getModuleId(project, scriptFile, definition))
fun getModuleId(
project: Project, scriptFile: VirtualFile, definition: ScriptDefinition
): ModuleId {
val scriptModuleLocation = project.scriptModuleRelativeLocation(scriptFile)
return ModuleId("$KOTLIN_SCRIPTS_MODULE_NAME.${definition.name}.$scriptModuleLocation")
}
}
fun Project.scriptModuleRelativeLocation(scriptFile: VirtualFile): String {
val scriptPath = this.guessProjectDir()?.path?.let {
FileUtil.getRelativePath(
it,
scriptFile.path,
File.separatorChar
)
} ?: scriptFile.path
return scriptPath.replace(VfsUtilCore.VFS_SEPARATOR_CHAR, ':')
}

View File

@@ -0,0 +1,8 @@
package org.jetbrains.kotlin.idea.core.script
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
const val KOTLIN_SCRIPTS_MODULE_NAME: String = "kotlin.scripts"
open class KotlinScriptEntitySource(override val virtualFileUrl: VirtualFileUrl?) : EntitySource

View File

@@ -1,97 +0,0 @@
package org.jetbrains.kotlin.idea.core.script
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.platform.workspace.storage.url.VirtualFileUrlManager
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathVirtualFileCache
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationWithSdk
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import java.nio.file.Path
import kotlin.script.experimental.api.valueOrNull
const val KOTLIN_SCRIPTS_MODULE_NAME: String = "kotlin.scripts"
open class KotlinScriptEntitySource(override val virtualFileUrl: VirtualFileUrl?) : EntitySource
@ApiStatus.Internal
fun getUpdatedStorage(
project: Project,
configurationsData: Map<VirtualFile, ScriptConfigurationWithSdk>,
entitySourceSupplier: (virtualFileUrl: VirtualFileUrl) -> KotlinScriptEntitySource,
): MutableEntityStorage {
val updatedStorage = MutableEntityStorage.create()
val projectPath = project.basePath?.let { Path.of(it) } ?: return updatedStorage
val fileUrlManager = WorkspaceModel.getInstance(project).getVirtualFileUrlManager()
val updatedFactory = LibraryDependencyFactory(fileUrlManager, updatedStorage)
val fileCache = ScriptClassPathVirtualFileCache.getInstance()
for ((scriptFile, configurationWithSdk) in configurationsData) {
val configuration = configurationWithSdk.scriptConfiguration.valueOrNull() ?: continue
val source = entitySourceSupplier(scriptFile.toVirtualFileUrl(fileUrlManager))
val basePath = projectPath.toFile()
val file = Path.of(scriptFile.path).toFile()
val relativeLocation = FileUtil.getRelativePath(basePath, file) ?: continue
val definitionName = findScriptDefinition(project, VirtualFileScriptSource(scriptFile)).name
val definitionScriptModuleName = "$KOTLIN_SCRIPTS_MODULE_NAME.$definitionName"
val locationName = relativeLocation.replace(VfsUtilCore.VFS_SEPARATOR_CHAR, ':')
val moduleName = "$definitionScriptModuleName.$locationName"
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
val libraryDependencies = configuration.dependenciesClassPath.mapNotNull { fileCache.findVirtualFile(it.path) }
.sortedBy { it.name }
.map { updatedFactory.get(it, source) }
val allDependencies = listOfNotNull(sdkDependency) + libraryDependencies
updatedStorage.addEntity(ModuleEntity(moduleName, allDependencies, source))
}
return updatedStorage
}
class LibraryDependencyFactory(
private val fileUrlManager: VirtualFileUrlManager,
private val entityStorage: MutableEntityStorage,
) {
private val cache = HashMap<VirtualFile, LibraryDependency>()
private val nameCache = HashMap<String, Int>()
fun get(file: VirtualFile, source: KotlinScriptEntitySource): LibraryDependency {
return cache.computeIfAbsent(file) {
createLibrary(file, source)
}
}
fun createLibrary(file: VirtualFile, source: KotlinScriptEntitySource): LibraryDependency {
val fileUrl = file.toVirtualFileUrl(fileUrlManager)
val libraryRoot = LibraryRoot(fileUrl, LibraryRootTypeId.COMPILED)
val fileName = file.name
// Module names for duplicating file names will have a number suffix (such as '.2')
val libraryNameSuffixNumber = nameCache.compute(file.name) { _, oldValue -> if (oldValue != null) oldValue + 1 else 1 }!!
val libraryNameSuffix = if (libraryNameSuffixNumber > 1) ".$libraryNameSuffixNumber" else ""
val libraryName = "$fileName$libraryNameSuffix"
val libraryTableId = LibraryTableId.ProjectLibraryTableId
val libraryEntity = LibraryEntity(libraryName, libraryTableId, listOf(libraryRoot), source)
val dependencyEntity = entityStorage.addEntity(libraryEntity)
return LibraryDependency(dependencyEntity.symbolicId, false, DependencyScope.COMPILE)
}
}

View File

@@ -10,14 +10,15 @@ import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.MutableEntityStorage
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
import org.jetbrains.kotlin.idea.core.script.k2.K2ScriptDefinitionProvider
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathVirtualFileCache
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationsSource
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathUtil
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
@@ -28,49 +29,94 @@ import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty
val KtFile.alwaysVirtualFile: VirtualFile get() = originalFile.virtualFile ?: viewProvider.virtualFile
@ApiStatus.Internal
fun MutableEntityStorage.getDefinitionLibraryEntity(
definition: ScriptDefinition, project: Project, entitySource: KotlinScriptEntitySource
): LibraryEntity? {
val libraryId = LibraryId(".${definition.fileExtension} definition dependencies", LibraryTableId.ProjectLibraryTableId)
val entity = libraryId.resolve(this)
if (entity != null) {
return entity
fun MutableEntityStorage.createOrUpdateLibrary(
libraryName: String, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryDependency {
val libraryId = LibraryId(libraryName, LibraryTableId.ProjectLibraryTableId)
val existingLibrary = this.resolve(libraryId)
if (existingLibrary == null) {
createLibrary(libraryId, roots, source)
} else {
modifyLibraryEntity(existingLibrary) {
this.roots = roots.toMutableList()
}
}
val virtualFileCache = ScriptClassPathVirtualFileCache.getInstance()
val classes = definition.compilationConfiguration[ScriptCompilationConfiguration.dependencies]
.toClassPathOrEmpty()
.mapNotNull { virtualFileCache.findVirtualFile(it.path) }
.sortedBy { it.name }
val sources = definition.compilationConfiguration[ScriptCompilationConfiguration.ide.dependenciesSources]
.toClassPathOrEmpty()
.mapNotNull { virtualFileCache.findVirtualFile(it.path) }
.sortedBy { it.name }
if (classes.isEmpty() && sources.isEmpty()) {
return null
}
val fileUrlManager = WorkspaceModel.getInstance(project).getVirtualFileUrlManager()
val classRoots = classes.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.COMPILED)
}
val sourceRoots = sources.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.SOURCES)
}
return addEntity(
LibraryEntity(libraryId.name, libraryId.tableId, classRoots + sourceRoots, entitySource)
)
return LibraryDependency(libraryId, false, DependencyScope.COMPILE)
}
inline fun <reified T : ScriptConfigurationsSource<*>> Project.scriptConfigurationsSourceOfType(): T? =
SCRIPT_CONFIGURATIONS_SOURCES.getExtensions(this).filterIsInstance<T>().firstOrNull().safeAs<T>()
fun VirtualFile.sourceLibraryRoot(project: Project): LibraryRoot {
val urlManager = project.workspaceModel.getVirtualFileUrlManager()
return LibraryRoot(toVirtualFileUrl(urlManager), LibraryRootTypeId.SOURCES)
}
fun VirtualFile.compiledLibraryRoot(project: Project): LibraryRoot {
val urlManager = project.workspaceModel.getVirtualFileUrlManager()
return LibraryRoot(toVirtualFileUrl(urlManager), LibraryRootTypeId.COMPILED)
}
fun MutableEntityStorage.getOrCreateLibrary(
libraryName: String, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryDependency {
val libraryId = LibraryId(libraryName, LibraryTableId.ProjectLibraryTableId)
if (!this.contains(libraryId)) createLibrary(libraryId, roots, source)
return LibraryDependency(libraryId, false, DependencyScope.COMPILE)
}
fun MutableEntityStorage.createLibrary(
libraryId: LibraryId, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryEntity {
val sortedRoots = roots.sortedWith(ROOT_COMPARATOR)
val libraryEntity = LibraryEntity(libraryId.name, libraryId.tableId, sortedRoots, source)
return addEntity(libraryEntity)
}
val ROOT_COMPARATOR: Comparator<LibraryRoot> = Comparator { o1, o2 ->
when {
o1 == o2 -> 0
o1 == null -> -1
o2 == null -> 1
else -> o1.url.url.compareTo(o2.url.url)
}
}
@ApiStatus.Internal
fun MutableEntityStorage.getOrCreateDefinitionDependency(
definition: ScriptDefinition, project: Project, entitySource: EntitySource
): LibraryDependency {
val libraryId = LibraryId(".${definition.fileExtension} definition dependencies", LibraryTableId.ProjectLibraryTableId)
if (!this.contains(libraryId)) {
val fileUrlManager = WorkspaceModel.getInstance(project).getVirtualFileUrlManager()
val virtualFileCache = ScriptClassPathUtil.getInstance()
val classes = definition.compilationConfiguration[ScriptCompilationConfiguration.dependencies]
.toClassPathOrEmpty()
.mapNotNull { virtualFileCache.findVirtualFile(it.path) }
.sortedBy { it.name }
val sources = definition.compilationConfiguration[ScriptCompilationConfiguration.ide.dependenciesSources]
.toClassPathOrEmpty()
.mapNotNull { virtualFileCache.findVirtualFile(it.path) }
.sortedBy { it.name }
val classRoots = classes.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.COMPILED)
}
val sourceRoots = sources.map {
LibraryRoot(it.toVirtualFileUrl(fileUrlManager), LibraryRootTypeId.SOURCES)
}
addEntity(
LibraryEntity(libraryId.name, libraryId.tableId, classRoots + sourceRoots, entitySource)
)
}
return LibraryDependency(libraryId, false, DependencyScope.COMPILE)
}
inline fun <reified T : ScriptDefinitionsSource> Project.scriptDefinitionsSourceOfType(): T? =
SCRIPT_DEFINITIONS_SOURCES.getExtensions(this).filterIsInstance<T>().firstOrNull().safeAs<T>()
@@ -78,9 +124,6 @@ inline fun <reified T : ScriptDefinitionsSource> Project.scriptDefinitionsSource
val SCRIPT_DEFINITIONS_SOURCES: ProjectExtensionPointName<ScriptDefinitionsSource> =
ProjectExtensionPointName("org.jetbrains.kotlin.scriptDefinitionsSource")
val SCRIPT_CONFIGURATIONS_SOURCES: ProjectExtensionPointName<ScriptConfigurationsSource<*>> =
ProjectExtensionPointName("org.jetbrains.kotlin.scriptConfigurationsSource")
@set: org.jetbrains.annotations.TestOnly
var Application.isScriptChangesNotifierDisabled by NotNullableUserDataProperty(
Key.create("SCRIPT_CHANGES_NOTIFIER_DISABLED"), true

View File

@@ -2,11 +2,6 @@
package org.jetbrains.kotlin.idea.core.script.ucache
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.impl.containers.toMutableWorkspaceSet
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
@@ -21,42 +16,42 @@ interface KotlinScriptEntity : WorkspaceEntityWithSymbolicId {
override val symbolicId: KotlinScriptId
get() = KotlinScriptId(path)
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<KotlinScriptEntity> {
override var entitySource: EntitySource
var path: String
var dependencies: MutableSet<KotlinScriptLibraryId>
}
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<KotlinScriptEntity> {
override var entitySource: EntitySource
var path: String
var dependencies: MutableSet<KotlinScriptLibraryId>
}
companion object : EntityType<KotlinScriptEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
path: String,
dependencies: Set<KotlinScriptLibraryId>,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.path = path
builder.dependencies = dependencies.toMutableWorkspaceSet()
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
companion object : EntityType<KotlinScriptEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
path: String,
dependencies: Set<KotlinScriptLibraryId>,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.path = path
builder.dependencies = dependencies.toMutableWorkspaceSet()
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
//endregion
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyKotlinScriptEntity(
entity: KotlinScriptEntity,
modification: KotlinScriptEntity.Builder.() -> Unit,
entity: KotlinScriptEntity,
modification: KotlinScriptEntity.Builder.() -> Unit,
): KotlinScriptEntity {
return modifyEntity(KotlinScriptEntity.Builder::class.java, entity, modification)
return modifyEntity(KotlinScriptEntity.Builder::class.java, entity, modification)
}
//endregion

View File

@@ -2,11 +2,6 @@
package org.jetbrains.kotlin.idea.core.script.ucache
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.impl.containers.toMutableWorkspaceList
import com.intellij.platform.workspace.storage.impl.containers.toMutableWorkspaceSet
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
@@ -43,46 +38,46 @@ interface KotlinScriptLibraryEntity : WorkspaceEntityWithSymbolicId {
override val symbolicId: KotlinScriptLibraryId
get() = KotlinScriptLibraryId(name)
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<KotlinScriptLibraryEntity> {
override var entitySource: EntitySource
var name: String
var roots: MutableList<KotlinScriptLibraryRoot>
var indexSourceRoots: Boolean
var usedInScripts: MutableSet<KotlinScriptId>
}
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<KotlinScriptLibraryEntity> {
override var entitySource: EntitySource
var name: String
var roots: MutableList<KotlinScriptLibraryRoot>
var indexSourceRoots: Boolean
var usedInScripts: MutableSet<KotlinScriptId>
}
companion object : EntityType<KotlinScriptLibraryEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
roots: List<KotlinScriptLibraryRoot>,
indexSourceRoots: Boolean,
usedInScripts: Set<KotlinScriptId>,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.roots = roots.toMutableWorkspaceList()
builder.indexSourceRoots = indexSourceRoots
builder.usedInScripts = usedInScripts.toMutableWorkspaceSet()
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
companion object : EntityType<KotlinScriptLibraryEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
roots: List<KotlinScriptLibraryRoot>,
indexSourceRoots: Boolean,
usedInScripts: Set<KotlinScriptId>,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.roots = roots.toMutableWorkspaceList()
builder.indexSourceRoots = indexSourceRoots
builder.usedInScripts = usedInScripts.toMutableWorkspaceSet()
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
//endregion
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyKotlinScriptLibraryEntity(
entity: KotlinScriptLibraryEntity,
modification: KotlinScriptLibraryEntity.Builder.() -> Unit,
entity: KotlinScriptLibraryEntity,
modification: KotlinScriptLibraryEntity.Builder.() -> Unit,
): KotlinScriptLibraryEntity {
return modifyEntity(KotlinScriptLibraryEntity.Builder::class.java, entity, modification)
return modifyEntity(KotlinScriptLibraryEntity.Builder::class.java, entity, modification)
}
//endregion

View File

@@ -12,7 +12,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.NonClasspathDirectoriesScope.compose
import org.jetbrains.kotlin.idea.core.script.configuration.utils.ScriptClassRootsStorage
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathVirtualFileCache
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathUtil
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import java.lang.ref.Reference
@@ -96,7 +96,7 @@ class ScriptClassRootsCache(
private fun computeHeavy(lightScriptInfo: LightScriptInfo): HeavyScriptInfo? {
val configuration = lightScriptInfo.buildConfiguration() ?: return null
val vfsRoots = configuration.dependenciesClassPath.mapNotNull { ScriptClassPathVirtualFileCache.findVirtualFile(it.path) }
val vfsRoots = configuration.dependenciesClassPath.mapNotNull { ScriptClassPathUtil.findVirtualFile(it.path) }
val sdk = sdks[SdkId(configuration.javaHome?.toPath())]
fun heavyInfoForRoots(roots: List<VirtualFile>): HeavyScriptInfo {
@@ -123,7 +123,7 @@ class ScriptClassRootsCache(
return if (classpathVfsHint?.containsKey(this) == true) {
classpathVfsHint[this]
} else {
ScriptClassPathVirtualFileCache.findVirtualFile(this).also { vFile ->
ScriptClassPathUtil.findVirtualFile(this).also { vFile ->
classpathVfsHint?.put(this, vFile)
}
}
@@ -159,7 +159,7 @@ class ScriptClassRootsCache(
fun getScriptDependenciesSourceFiles(file: VirtualFile): List<VirtualFile> {
return getHeavyScriptInfo(file.path)?.scriptConfiguration?.dependenciesSources?.mapNotNull { file ->
ScriptClassPathVirtualFileCache.findVirtualFile(file.path)
ScriptClassPathUtil.findVirtualFile(file.path)
} ?: emptyList()
}

View File

@@ -2,26 +2,27 @@
package org.jetbrains.kotlin.idea.k2.inspections.tests
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.testFramework.common.runAll
import com.intellij.testFramework.registerExtension
import com.intellij.testFramework.replaceService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
import org.jetbrains.kotlin.idea.base.test.k2FileName
import org.jetbrains.kotlin.idea.core.script.SCRIPT_CONFIGURATIONS_SOURCES
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.idea.core.script.k2.BundledScriptConfigurationsSource
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptConfigurationHandler
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationWithSdk
import org.jetbrains.kotlin.idea.fir.K2DirectiveBasedActionUtils
import org.jetbrains.kotlin.idea.fir.invalidateCaches
import org.jetbrains.kotlin.idea.inspections.AbstractLocalInspectionTest
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import java.io.File
import java.nio.file.Path
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.io.path.div
import kotlin.io.path.exists
@@ -39,7 +40,7 @@ abstract class AbstractK2LocalInspectionTest : AbstractLocalInspectionTest() {
override val skipErrorsAfterCheckDirectives: List<String>
get() = super.skipErrorsAfterCheckDirectives + K2DirectiveBasedActionUtils.DISABLE_K2_ERRORS_DIRECTIVE
override fun checkForErrorsBefore(mainFile: File,ktFile: KtFile, fileText: String) {
override fun checkForErrorsBefore(mainFile: File, ktFile: KtFile, fileText: String) {
K2DirectiveBasedActionUtils.checkForErrorsBefore(mainFile, ktFile, fileText)
}
@@ -70,21 +71,36 @@ abstract class AbstractK2LocalInspectionTest : AbstractLocalInspectionTest() {
val extraFileNames = findExtraFilesForTest(mainFile)
val psiFile = myFixture.configureByFiles(*(listOf(mainFile.name) + extraFileNames).toTypedArray()).first()
myFixture.configureByFiles(*(listOf(mainFile.name) + extraFileNames).toTypedArray()).first()
if ((myFixture.file as? KtFile)?.isScript() == true) {
val dependenciesSource = object : BundledScriptConfigurationsSource(project, CoroutineScope(Dispatchers.IO + SupervisorJob())) {
override suspend fun updateModules(storage: MutableEntityStorage?) {
//do nothing because adding modules is not permitted in light tests
}
}
project.registerExtension(SCRIPT_CONFIGURATIONS_SOURCES, dependenciesSource, testRootDisposable)
val ktFile = myFixture.file as? KtFile
ktFile?.let { processKotlinScriptIfNeeded(ktFile) }
val script = BaseScriptModel(psiFile.virtualFile)
runWithModalProgressBlocking(project, "Testing") {
dependenciesSource.updateDependenciesAndCreateModules(setOf(script))
}
}
super.doTest(path)
}
private fun processKotlinScriptIfNeeded(ktFile: KtFile) {
if (!ktFile.isScript()) return
project.replaceService(
DefaultScriptConfigurationHandler::class.java,
DefaultScriptConfigurationHandlerForTests(project), testRootDisposable
)
runWithModalProgressBlocking(project, "AbstractK2LocalInspectionTest") {
DefaultScriptResolutionStrategy(project, this).execute(ktFile).join()
}
}
// kotlin scripts require adjusting project model which is not possible for lightweight test fixture
private class DefaultScriptConfigurationHandlerForTests(testProject: Project) :
DefaultScriptConfigurationHandler(testProject, CoroutineScope(EmptyCoroutineContext)) {
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>) {}
override fun isModuleExist(
project: Project,
scriptFile: VirtualFile,
definition: ScriptDefinition
): Boolean = true
}
}

View File

@@ -32,8 +32,6 @@
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<scriptConfigurationsSource implementation="org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptConfigurationsSource"/>
<kotlinScriptLazyResolveProhibitionCondition
implementation="org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptLazyResolveProhibitionCondition"/>
<scriptDefinitionsSource implementation="org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptDefinitionsSource"/>

View File

@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
private const val GRADLE_KTS = ".gradle.kts"
class GradleScriptLazyResolveProhibitionCondition(val project: Project) : KotlinScriptLazyResolveProhibitionCondition {
override fun prohibitLazyResolve(script: VirtualFile): Boolean {
override fun shouldPostponeResolution(script: VirtualFile): Boolean {
val gradleDefinitionIds =
project.scriptDefinitionsSourceOfType<GradleScriptDefinitionsSource>()?.definitions?.map { it.definitionId }?.toSet()
?: emptySet()

View File

@@ -19,7 +19,7 @@ import com.intellij.ui.EditorNotificationPanel
import com.intellij.ui.EditorNotificationProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptConfigurationsSource.KotlinGradleScriptModuleEntitySource
import org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptModuleEntitySource
import org.jetbrains.plugins.gradle.util.GradleConstants
import java.util.function.Function
import javax.swing.JComponent

View File

@@ -2,16 +2,21 @@
package org.jetbrains.kotlin.gradle.scripting.k2
import com.intellij.openapi.application.edtWriteAction
import com.intellij.openapi.application.readAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.platform.backend.observation.launchTracked
import com.intellij.psi.PsiManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.jetbrains.kotlin.gradle.scripting.shared.GradleScriptModel
import org.jetbrains.kotlin.gradle.scripting.shared.GradleScriptRefinedConfigurationProvider
import org.jetbrains.kotlin.gradle.scripting.shared.getGradleVersion
import org.jetbrains.kotlin.gradle.scripting.shared.loadGradleDefinitions
import org.jetbrains.kotlin.gradle.scripting.shared.roots.GradleBuildRootsManager
import org.jetbrains.kotlin.gradle.scripting.shared.roots.Imported
import org.jetbrains.kotlin.idea.core.script.scriptConfigurationsSourceOfType
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.plugins.gradle.service.GradleInstallationManager
import org.jetbrains.plugins.gradle.settings.DistributionType
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
@@ -89,7 +94,13 @@ class ProjectGradleSettingsListener(
}
}.toSet()
GradleScriptDefinitionsHolder.Companion.getInstance(project).updateDefinitions(definitions)
project.scriptConfigurationsSourceOfType<GradleScriptConfigurationsSource>()?.updateDependenciesAndCreateModules(gradleScripts)
GradleScriptDefinitionsHolder.getInstance(project).updateDefinitions(definitions)
GradleScriptRefinedConfigurationProvider.getInstance(project).updateConfigurations(gradleScripts)
val ktFiles = gradleScripts.mapNotNull {
readAction { PsiManager.getInstance(project).findFile(it.virtualFile) as? KtFile }
}.toTypedArray()
DefaultScriptResolutionStrategy.getInstance(project).execute(*ktFiles).join()
}
}

View File

@@ -1,19 +1,22 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.gradle.scripting.k2.importing
import com.intellij.openapi.application.readAction
import com.intellij.openapi.progress.blockingContext
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.psi.PsiManager
import org.gradle.tooling.model.kotlin.dsl.KotlinDslScriptsModel
import org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptConfigurationsSource
import org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptDefinitionsHolder
import org.jetbrains.kotlin.gradle.scripting.k2.GradleScriptModel
import org.jetbrains.kotlin.gradle.scripting.shared.GradleScriptModel
import org.jetbrains.kotlin.gradle.scripting.shared.GradleScriptRefinedConfigurationProvider
import org.jetbrains.kotlin.gradle.scripting.shared.importing.kotlinDslSyncListenerInstance
import org.jetbrains.kotlin.gradle.scripting.shared.importing.processScriptModel
import org.jetbrains.kotlin.gradle.scripting.shared.importing.saveGradleBuildEnvironment
import org.jetbrains.kotlin.gradle.scripting.shared.kotlinDslScriptsModelImportSupported
import org.jetbrains.kotlin.gradle.scripting.shared.loadGradleDefinitions
import org.jetbrains.kotlin.idea.core.script.scriptConfigurationsSourceOfType
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncContributor
import org.jetbrains.plugins.gradle.service.syncAction.GradleSyncProjectConfigurator.project
@@ -62,7 +65,12 @@ class KotlinDslScriptSyncContributor : GradleSyncContributor {
}
}
project.scriptConfigurationsSourceOfType<GradleScriptConfigurationsSource>()
?.updateDependenciesAndCreateModules(gradleScripts, storage)
GradleScriptRefinedConfigurationProvider.getInstance(project).updateConfigurations(gradleScripts)
val ktFiles = gradleScripts.mapNotNull {
readAction { PsiManager.getInstance(project).findFile(it.virtualFile) as? KtFile }
}.toTypedArray()
DefaultScriptResolutionStrategy.getInstance(project).execute(*ktFiles).join()
}
}

View File

@@ -0,0 +1,28 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.gradle.scripting.shared.impl
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.metadata.impl.MetadataStorageBase
import com.intellij.platform.workspace.storage.metadata.model.FinalClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.OwnPropertyMetadata
import com.intellij.platform.workspace.storage.metadata.model.StorageTypeMetadata
import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
var typeMetadata: StorageTypeMetadata
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptModuleEntitySource", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "virtualFileUrl", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.EntitySource",
"org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource"))
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.EntitySource", metadataHash = 248264869)
addMetadataHash(typeFqn = "org.jetbrains.kotlin.gradle.scripting.shared.KotlinGradleScriptModuleEntitySource", metadataHash = -592100153)
}
}

View File

@@ -5,6 +5,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@@ -1,30 +1,27 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.gradle.scripting.k2
package org.jetbrains.kotlin.gradle.scripting.shared
import com.intellij.openapi.application.smartReadAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdkType
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.toVirtualFileUrl
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.jps.entities.LibraryDependency
import com.intellij.platform.workspace.jps.entities.ModuleEntity
import com.intellij.platform.workspace.jps.entities.SdkDependency
import com.intellij.platform.workspace.jps.entities.SdkId
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import org.jetbrains.kotlin.idea.core.script.KOTLIN_SCRIPTS_MODULE_NAME
import org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.kotlin.idea.core.script.*
import org.jetbrains.kotlin.idea.core.script.dependencies.indexSourceRootsEagerly
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.idea.core.script.k2.ScriptClassPathVirtualFileCache
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationWithSdk
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationsSource
import org.jetbrains.kotlin.idea.core.script.scriptDefinitionsSourceOfType
import org.jetbrains.kotlin.idea.core.script.ucache.relativeName
import org.jetbrains.kotlin.idea.core.script.k2.*
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
@@ -32,46 +29,29 @@ import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
import java.util.function.Predicate
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.jdkHome
import kotlin.script.experimental.jvm.jvm
internal class GradleScriptModel(
override val virtualFile: VirtualFile,
val classPath: List<String> = listOf(),
val sourcePath: List<String> = listOf(),
val imports: List<String> = listOf(),
val javaHome: String? = null
) : BaseScriptModel(virtualFile) {
override fun toString(): String {
return "GradleScriptModel(virtualFile=$virtualFile)"
}
}
@Service(Service.Level.PROJECT)
class GradleScriptRefinedConfigurationProvider(
val project: Project, val coroutineScope: CoroutineScope
) : ScriptRefinedConfigurationResolver, ScriptWorkspaceModelManager {
private val data = ConcurrentHashMap<VirtualFile, ScriptConfigurationWithSdk>()
internal open class GradleScriptConfigurationsSource(override val project: Project) :
ScriptConfigurationsSource<GradleScriptModel>(project) {
private val gradleEntitySourceFilter: (EntitySource) -> Boolean =
{ entitySource -> entitySource is KotlinGradleScriptModuleEntitySource }
override suspend fun create(virtualFile: VirtualFile, definition: ScriptDefinition): ScriptConfigurationWithSdk? = null
override suspend fun updateModules(storage: MutableEntityStorage?) {
if (storage == null) return
override fun get(virtualFile: VirtualFile): ScriptConfigurationWithSdk? = data[virtualFile]
val storageWithGradleScriptModules = getUpdatedStorage(data.get())
storage.replaceBySource(gradleEntitySourceFilter, storageWithGradleScriptModules)
}
override fun getDefinitions(): Sequence<ScriptDefinition>? =
project.scriptDefinitionsSourceOfType<GradleScriptDefinitionsSource>()?.definitions
override suspend fun updateConfigurations(scripts: Iterable<GradleScriptModel>) {
suspend fun updateConfigurations(scripts: Iterable<GradleScriptModel>) {
val configurations = scripts.associate { it: GradleScriptModel ->
val sourceCode = VirtualFileScriptSource(it.virtualFile)
val definition = findScriptDefinition(project, sourceCode)
val sdk = ProjectRootManager.getInstance(project).projectSdk?.takeIf { it.sdkType is JavaSdkType }
val sdk = project.serviceAsync<ProjectRootManager>().projectSdk?.takeIf { it.sdkType is JavaSdkType }
?: it.javaHome?.let { ExternalSystemJdkUtil.lookupJdkByPath(it) }
val javaHomePath = sdk?.homePath?.let { Path.of(it) }
@@ -92,14 +72,22 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
it.virtualFile to ScriptConfigurationWithSdk(updatedConfiguration, sdk)
}
data.set(configurations)
data.putAll(configurations)
}
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>) {
val storageWithGradleScriptModules = getUpdatedStorage(configurationPerFile)
project.workspaceModel.update("updating .gradle.kts scripts") { storage ->
storage.replaceBySource({ it is KotlinGradleScriptModuleEntitySource }, storageWithGradleScriptModules)
}
}
private suspend fun getUpdatedStorage(configurations: Map<VirtualFile, ScriptConfigurationWithSdk>): MutableEntityStorage {
val result = MutableEntityStorage.create()
val urlManager = project.serviceAsync<WorkspaceModel>().getVirtualFileUrlManager()
val virtualFileCache = ScriptClassPathVirtualFileCache.getInstance()
val virtualFileCache = ScriptClassPathUtil.getInstance()
val dependencyFactory = ScriptDependencyFactory(result, configurations, virtualFileCache)
for ((scriptFile, configurationWithSdk) in configurations) {
@@ -107,9 +95,7 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
val source = KotlinGradleScriptModuleEntitySource(scriptFile.toVirtualFileUrl(urlManager))
val definitionName = findScriptDefinition(project, VirtualFileScriptSource(scriptFile)).name
val definitionScriptModuleName = "$KOTLIN_SCRIPTS_MODULE_NAME.$definitionName"
val locationName = scriptFile.relativeName(project).replace(VfsUtilCore.VFS_SEPARATOR_CHAR, ':')
val scriptRelativeLocation = project.scriptModuleRelativeLocation(scriptFile)
val sdkDependency = configurationWithSdk.sdk?.let { SdkDependency(SdkId(it.name, it.sdkType.name)) }
@@ -127,13 +113,13 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
addAll(result.createDependenciesWithSources(classes, sources, source))
add(
result.groupRootsByPredicate(
classes, sources, source, "$locationName accessors dependencies"
classes, sources, source, "$scriptRelativeLocation accessors dependencies"
) {
it.path.contains("accessors")
})
add(
result.groupRootsByPredicate(
classes, sources, source, "$locationName groovy dependencies"
classes, sources, source, "$scriptRelativeLocation groovy dependencies"
) {
it.path.contains("groovy")
})
@@ -144,24 +130,12 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
})
}.distinct().sortedBy { it.library.name }
result.addEntity(ModuleEntity("$definitionScriptModuleName.$locationName", allDependencies, source))
result.addEntity(ModuleEntity("$KOTLIN_SCRIPTS_MODULE_NAME.$definitionName.$scriptRelativeLocation", allDependencies, source))
}
return result
}
private val VirtualFile.sourceLibraryRoot: LibraryRoot
get() {
val urlManager = project.workspaceModel.getVirtualFileUrlManager()
return LibraryRoot(toVirtualFileUrl(urlManager), LibraryRootTypeId.SOURCES)
}
private val VirtualFile.compiledLibraryRoot: LibraryRoot
get() {
val urlManager = project.workspaceModel.getVirtualFileUrlManager()
return LibraryRoot(toVirtualFileUrl(urlManager), LibraryRootTypeId.COMPILED)
}
private fun MutableEntityStorage.groupRootsByPredicate(
classes: MutableSet<VirtualFile>,
sources: MutableSet<VirtualFile>,
@@ -172,8 +146,8 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
val groupedClasses = classes.removeOnMatch(predicate)
val groupedSources = sources.removeOnMatch(predicate)
val classRoots = groupedClasses.map { it.compiledLibraryRoot }.sortedWith(ROOT_COMPARATOR)
val sourceRoots = groupedSources.map { it.sourceLibraryRoot }.sortedWith(ROOT_COMPARATOR)
val classRoots = groupedClasses.map { it.compiledLibraryRoot(project) }.sortedWith(ROOT_COMPARATOR)
val sourceRoots = groupedSources.map { it.sourceLibraryRoot(project) }.sortedWith(ROOT_COMPARATOR)
return createOrUpdateLibrary(dependencyName, classRoots + sourceRoots, source)
}
@@ -194,7 +168,7 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
inner class ScriptDependencyFactory(
private val entityStorage: MutableEntityStorage,
scripts: Map<VirtualFile, ScriptConfigurationWithSdk>,
virtualFileCache: ScriptClassPathVirtualFileCache,
virtualFileCache: ScriptClassPathUtil,
) {
private val nameCache = HashMap<String, Set<VirtualFile>>()
@@ -212,15 +186,17 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
fun get(file: VirtualFile, source: KotlinScriptEntitySource): LibraryDependency {
val filesWithSameName = nameCache[file.name]
val root = listOf(file.compiledLibraryRoot(project))
return if (filesWithSameName == null || filesWithSameName.size == 1) {
entityStorage.getOrCreateLibrary(file.name, listOf(file.compiledLibraryRoot), source)
entityStorage.getOrCreateLibrary(file.name, root, source)
} else {
val commonAncestor = findCommonAncestor(filesWithSameName.map { it.path })
if (commonAncestor == null) {
entityStorage.getOrCreateLibrary(file.name, listOf(file.compiledLibraryRoot), source)
entityStorage.getOrCreateLibrary(file.name, root, source)
} else {
val libraryName = file.path.replace("$commonAncestor/", "")
entityStorage.getOrCreateLibrary(libraryName, listOf(file.compiledLibraryRoot), source)
entityStorage.getOrCreateLibrary(libraryName, root, source)
}
}
}
@@ -261,7 +237,7 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
for ((left, right) in pairs) {
if (right != null) {
val roots = listOf(left.compiledLibraryRoot, right.sourceLibraryRoot)
val roots = listOf(left.compiledLibraryRoot(project), right.sourceLibraryRoot(project))
val dependency = createOrUpdateLibrary(left.name, roots, source)
classes.remove(left)
@@ -273,52 +249,8 @@ internal open class GradleScriptConfigurationsSource(override val project: Proje
return result
}
data class KotlinGradleScriptModuleEntitySource(override val virtualFileUrl: VirtualFileUrl) : KotlinScriptEntitySource(virtualFileUrl)
}
private fun MutableEntityStorage.createOrUpdateLibrary(
libraryName: String, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryDependency {
val libraryId = LibraryId(libraryName, LibraryTableId.ProjectLibraryTableId)
val existingLibrary = this.resolve(libraryId)
if (existingLibrary == null) {
createLibrary(libraryId, roots, source)
} else {
val existingRoots = existingLibrary.roots.toSet()
if (!existingRoots.containsAll(roots)) {
modifyEntity(LibraryEntity.Builder::class.java, existingLibrary) {
this.roots = (this.roots.toSet() + roots).sortedWith(ROOT_COMPARATOR).toMutableList()
}
}
}
return LibraryDependency(libraryId, false, DependencyScope.COMPILE)
}
private fun MutableEntityStorage.getOrCreateLibrary(
libraryName: String, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryDependency {
val libraryId = LibraryId(libraryName, LibraryTableId.ProjectLibraryTableId)
if (!this.contains(libraryId)) createLibrary(libraryId, roots, source)
return LibraryDependency(libraryId, false, DependencyScope.COMPILE)
}
private fun MutableEntityStorage.createLibrary(
libraryId: LibraryId, roots: List<LibraryRoot>, source: KotlinScriptEntitySource
): LibraryEntity {
val sortedRoots = roots.sortedWith(ROOT_COMPARATOR)
val libraryEntity = LibraryEntity(libraryId.name, libraryId.tableId, sortedRoots, source)
return addEntity(libraryEntity)
}
private val ROOT_COMPARATOR: Comparator<LibraryRoot> = Comparator { o1, o2 ->
when {
o1 == o2 -> 0
o1 == null -> -1
o2 == null -> 1
else -> o1.url.url.compareTo(o2.url.url)
companion object {
@JvmStatic
fun getInstance(project: Project): GradleScriptRefinedConfigurationProvider = project.service()
}
}

View File

@@ -4,10 +4,15 @@ package org.jetbrains.kotlin.gradle.scripting.shared
import KotlinGradleScriptingBundle
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.util.EnvironmentUtil
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.core.script.KotlinScriptEntitySource
import org.jetbrains.kotlin.idea.core.script.k2.NewScriptFileInfo
import org.jetbrains.kotlin.idea.core.script.k2.configurationResolverDelegate
import org.jetbrains.kotlin.idea.core.script.k2.kotlinScriptTemplateInfo
import org.jetbrains.kotlin.idea.core.script.k2.scriptWorkspaceModelManagerDelegate
import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplatesByPaths
import org.jetbrains.kotlin.idea.core.script.scriptingDebugLog
import org.jetbrains.kotlin.idea.core.script.scriptingInfoLog
@@ -109,9 +114,6 @@ private fun findStdLibLanguageVersion(kotlinLibsClassPath: List<Path>): List<Str
?: emptyList()
}
/**
* Force-wrap legacy definitions into `ScriptDefinition.FromConfigurations` when updating.
*/
private fun loadGradleTemplates(
projectPath: String,
templateClasses: List<String>,
@@ -142,7 +144,8 @@ private fun loadGradleTemplates(
legacyDefinition,
it.hostConfiguration,
it.evaluationConfiguration,
it.defaultCompilerOptions
it.defaultCompilerOptions,
project
)
} ?: it
}
@@ -180,7 +183,7 @@ private fun String?.toGradleHomePath(): Path {
}
}
fun getFullDefinitionsClasspath(gradleLibDir: Path): List<Path> {
private fun getFullDefinitionsClasspath(gradleLibDir: Path): List<Path> {
val templateClasspath = Files.newDirectoryStream(gradleLibDir) { kotlinDslDependencySelector.matches(it.name) }
.use(DirectoryStream<Path>::toList)
.ifEmpty { error(KotlinGradleScriptingBundle.message("error.text.missing.jars.in.gradle.directory")) }
@@ -215,7 +218,8 @@ class GradleKotlinScriptDefinitionWrapper(
legacyDefinition: KotlinScriptDefinitionFromAnnotatedTemplate,
override val hostConfiguration: ScriptingHostConfiguration,
override val evaluationConfiguration: ScriptEvaluationConfiguration?,
override val defaultCompilerOptions: Iterable<String>
override val defaultCompilerOptions: Iterable<String>,
val project: Project
) : ScriptDefinition.FromConfigurationsBase() {
init {
@@ -230,16 +234,34 @@ class GradleKotlinScriptDefinitionWrapper(
hostConfiguration,
legacyDefinition
).with {
ScriptCompilationConfiguration.ide.acceptedLocations.put(listOf(ScriptAcceptedLocation.Project))
@Suppress("DEPRECATION_ERROR")
ScriptCompilationConfiguration.fileNamePattern.put(legacyDefinition.scriptFilePattern.pattern)
ide.kotlinScriptTemplateInfo(NewScriptFileInfo().apply{
id = "gradle-kts"
title = ".gradle.kts"
templateName = "Kotlin Script Gradle"
})
fileNamePattern.put(legacyDefinition.scriptFilePattern.pattern)
ide {
acceptedLocations.put(listOf(ScriptAcceptedLocation.Project))
kotlinScriptTemplateInfo(NewScriptFileInfo().apply {
id = "gradle-kts"
title = ".gradle.kts"
templateName = "Kotlin Script Gradle"
})
configurationResolverDelegate {
GradleScriptRefinedConfigurationProvider.getInstance(project)
}
scriptWorkspaceModelManagerDelegate {
GradleScriptRefinedConfigurationProvider.getInstance(project)
}
}
}
}
override val canDefinitionBeSwitchedOff: Boolean = false
}
}
data class KotlinGradleScriptModuleEntitySource(override val virtualFileUrl: VirtualFileUrl) : KotlinScriptEntitySource(virtualFileUrl)
class GradleScriptModel(
val virtualFile: VirtualFile,
val classPath: List<String> = listOf(),
val sourcePath: List<String> = listOf(),
val imports: List<String> = listOf(),
val javaHome: String? = null
)

View File

@@ -1,19 +1,18 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.highlighting
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.psi.PsiFile
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.registerExtension
import com.intellij.testFramework.replaceService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils
import org.jetbrains.kotlin.idea.core.script.SCRIPT_CONFIGURATIONS_SOURCES
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.idea.core.script.k2.BundledScriptConfigurationsSource
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptConfigurationHandler
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationWithSdk
import org.jetbrains.kotlin.idea.highlighter.AbstractHighlightingMetaInfoTest
import org.jetbrains.kotlin.idea.test.Directives
import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources
@@ -21,7 +20,9 @@ import org.jetbrains.kotlin.idea.test.kmp.KMPProjectDescriptorTestUtilities
import org.jetbrains.kotlin.idea.test.kmp.KMPTest
import org.jetbrains.kotlin.idea.test.kmp.KMPTestPlatform
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import java.io.File
import kotlin.coroutines.EmptyCoroutineContext
abstract class AbstractK2HighlightingMetaInfoTest : AbstractHighlightingMetaInfoTest(), KMPTest {
@@ -33,24 +34,38 @@ abstract class AbstractK2HighlightingMetaInfoTest : AbstractHighlightingMetaInfo
override fun doMultiFileTest(files: List<PsiFile>, globalDirectives: Directives) {
val psiFile = files.first()
if (psiFile is KtFile && psiFile.isScript()) {
val dependenciesSource = object : BundledScriptConfigurationsSource(project, CoroutineScope(Dispatchers.IO + SupervisorJob())) {
override suspend fun updateModules(storage: MutableEntityStorage?) {
//do nothing because adding modules is not permitted in light tests
}
}
project.registerExtension(SCRIPT_CONFIGURATIONS_SOURCES, dependenciesSource, testRootDisposable)
val script = BaseScriptModel(psiFile.virtualFile)
runWithModalProgressBlocking(project, "Testing") {
dependenciesSource.updateDependenciesAndCreateModules(setOf(script))
}
if (psiFile is KtFile) {
processKotlinScriptIfNeeded(psiFile)
}
super.doMultiFileTest(files, globalDirectives)
}
private fun processKotlinScriptIfNeeded(ktFile: KtFile) {
if (!ktFile.isScript()) return
project.replaceService(
DefaultScriptConfigurationHandler::class.java,
DefaultScriptConfigurationHandlerForTests(project), testRootDisposable
)
runWithModalProgressBlocking(project, "AbstractK2HighlightingMetaInfoTest§") {
DefaultScriptResolutionStrategy(project, this).execute(ktFile).join()
}
}
// kotlin scripts require adjusting project model which is not possible for lightweight test fixture
private class DefaultScriptConfigurationHandlerForTests(testProject: Project) :
DefaultScriptConfigurationHandler(testProject, CoroutineScope(EmptyCoroutineContext)) {
override suspend fun updateWorkspaceModel(configurationPerFile: Map<VirtualFile, ScriptConfigurationWithSdk>) {}
override fun isModuleExist(
project: Project,
scriptFile: VirtualFile,
definition: ScriptDefinition
): Boolean = true
}
override fun getProjectDescriptor(): LightProjectDescriptor =
KMPProjectDescriptorTestUtilities.createKMPProjectDescriptor(testPlatform)
?: super.getProjectDescriptor()

View File

@@ -15,15 +15,18 @@ import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.analysis.api.KaPlatformInterface
import org.jetbrains.kotlin.analysis.api.projectStructure.KaNotUnderContentRootModule
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginModeProvider.Companion.isK1Mode
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindFilter
import org.jetbrains.kotlin.idea.base.projectStructure.getKaModule
import org.jetbrains.kotlin.idea.base.projectStructure.matches
import org.jetbrains.kotlin.idea.base.util.KotlinPlatformUtils
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.script.getScriptReports
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptConfigurationsProvider
import org.jetbrains.kotlin.utils.addToStdlib.ifFalse
import kotlin.script.experimental.api.ScriptDiagnostic
@ApiStatus.Internal
@@ -76,16 +79,23 @@ private fun KtFile.shouldDefinitelyHighlight(): Boolean =
@OptIn(KaPlatformInterface::class)
private fun KtFile.calculateShouldHighlightFile(): Boolean =
shouldDefinitelyHighlight() || RootKindFilter.everything.matches(this) && getKaModule(project, useSiteModule = null) !is KaNotUnderContentRootModule
shouldDefinitelyHighlight() || RootKindFilter.everything.matches(this) && getKaModule(
project,
useSiteModule = null
) !is KaNotUnderContentRootModule
private fun KtFile.calculateShouldHighlightScript(): Boolean {
if (shouldDefinitelyHighlight()) return true
return (!KotlinPlatformUtils.isCidr // There is no Java support in CIDR. So do not highlight errors in KTS if running in CIDR.
&& !getScriptReports(this).any { it.severity == ScriptDiagnostic.Severity.FATAL }
&& isConfigurationLoaded()
&& RootKindFilter.projectSources.copy(includeScriptsOutsideSourceRoots = true).matches(this))
}
if (KotlinPlatformUtils.isCidr) return false // There is no Java support in CIDR. So do not highlight errors in KTS if running in CIDR.
if (getScriptReports(this).any { it.severity == ScriptDiagnostic.Severity.FATAL }) return false
private fun KtFile.isConfigurationLoaded(): Boolean =
ScriptConfigurationsProvider.getInstance(project)?.getScriptConfigurationResult(this) != null
val isReadyToHighlight = if (isK1Mode()) {
ScriptConfigurationsProvider.getInstance(project)?.getScriptConfigurationResult(this) != null
} else {
val strategy = DefaultScriptResolutionStrategy.getInstance(project)
strategy.isReadyToHighlight(this).also { isReady -> if (!isReady) strategy.execute(this) }
}
return isReadyToHighlight && RootKindFilter.projectSources.copy(includeScriptsOutsideSourceRoots = true).matches(this)
}

View File

@@ -28,9 +28,7 @@ class KotlinDefaultHighlightingSettingsProvider : DefaultHighlightingSettingProv
return when {
psiFile is KtFile ->
when {
psiFile.isScript() && ScriptConfigurationsProvider.getInstance(project)?.getScriptConfigurationResult(psiFile) == null ->
FileHighlightingSetting.SKIP_HIGHLIGHTING
psiFile.isScript() -> FileHighlightingSetting.FORCE_HIGHLIGHTING
psiFile.isCompiled -> FileHighlightingSetting.SKIP_INSPECTION
!KotlinSupportAvailability.isSupported(psiFile) -> FileHighlightingSetting.SKIP_HIGHLIGHTING
RootKindFilter.libraryFiles.matches(project, file) -> FileHighlightingSetting.SKIP_INSPECTION

View File

@@ -1,89 +0,0 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.diff.util.DiffUtil
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.readAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.findPsiFile
import com.intellij.psi.PsiManager
import com.intellij.testFramework.LightVirtualFileBase
import com.intellij.ui.EditorNotifications
import org.jetbrains.kotlin.idea.core.script.k2.BaseScriptModel
import org.jetbrains.kotlin.idea.core.script.k2.DependencyResolutionService
import org.jetbrains.kotlin.idea.core.script.k2.DependentScriptConfigurationsSource
import org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationsProviderImpl
import org.jetbrains.kotlin.idea.core.script.scriptConfigurationsSourceOfType
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptConfigurationsProvider
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.concurrent.ConcurrentHashMap
fun KtFile.getScriptAnnotationsList(): List<String> = annotationEntries.map { it.text }.sorted()
internal class ReloadDependenciesScriptAction : AnAction() {
val annotations = ConcurrentHashMap<VirtualFile, List<String>>()
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val editor = e.getData(CommonDataKeys.EDITOR) ?: return
val file = getKotlinScriptFile(editor) ?: return
DependencyResolutionService.getInstance(project).resolveInBackground {
project.scriptConfigurationsSourceOfType<DependentScriptConfigurationsSource>()?.updateDependenciesAndCreateModules(
listOf(BaseScriptModel(file))
)
annotations[file] = readAction {
PsiManager.getInstance(project).findFile(file)?.safeAs<KtFile>()?.getScriptAnnotationsList() ?: emptyList()
}
EditorNotifications.getInstance(project).updateNotifications(file)
}
}
override fun getActionUpdateThread() = ActionUpdateThread.BGT
override fun update(e: AnActionEvent) {
val editor = e.getData(CommonDataKeys.EDITOR)
e.presentation.isEnabledAndVisible = editor != null && getNotificationVisibility(editor)
}
private fun getNotificationVisibility(editor: Editor): Boolean {
if (DiffUtil.isDiffEditor(editor)) return false
val project = editor.project ?: return false
val file = getKotlinScriptFile(editor) ?: return false
val configSource =
ScriptConfigurationsProvider.getInstance(project).safeAs<ScriptConfigurationsProviderImpl>()?.resolveSource(file)
if (configSource !is DependentScriptConfigurationsSource) {
return false
}
val actualAnnotations = PsiManager.getInstance(project).findFile(file)?.safeAs<KtFile>()?.getScriptAnnotationsList() ?: emptyList()
val previous = annotations[file] ?: emptyList()
return if (previous.isEmpty() && actualAnnotations.isEmpty()) {
false
} else {
previous != actualAnnotations
}
}
}
private fun getKotlinScriptFile(editor: Editor): VirtualFile? {
val virtualFile = editor.virtualFile ?: return null
val ktFile = editor.project?.let { virtualFile.findPsiFile(it) as? KtFile } ?: return null
return virtualFile.takeIf {
it !is LightVirtualFileBase
&& it.isValid
&& ktFile.isScript()
}
}

View File

@@ -0,0 +1,67 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.script.k2
import com.intellij.diff.util.DiffUtil
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.readAction
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.vfs.findPsiFile
import com.intellij.ui.EditorNotifications
import org.jetbrains.kotlin.idea.core.script.alwaysVirtualFile
import org.jetbrains.kotlin.idea.core.script.k2.DependencyResolutionService
import org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptResolutionStrategy
import org.jetbrains.kotlin.idea.core.script.k2.MainKtsScriptConfigurationProvider
import org.jetbrains.kotlin.psi.KtFile
import java.util.concurrent.ConcurrentHashMap
fun KtFile.getScriptAnnotationsList(): List<String> = annotationEntries.map { it.text }.sorted()
internal class ReloadMainKtsScriptDependenciesAction : AnAction() {
private val annotations = ConcurrentHashMap<KtFile, List<String>>()
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val editor = e.getData(CommonDataKeys.EDITOR) ?: return
val ktFile = getKotlinScriptFile(editor) ?: return
DependencyResolutionService.getInstance(project).resolveInBackground {
project.serviceAsync<MainKtsScriptConfigurationProvider>().refineConfiguration(ktFile.alwaysVirtualFile)
DefaultScriptResolutionStrategy.getInstance(project).execute(ktFile)
annotations[ktFile] = readAction { ktFile.getScriptAnnotationsList() }
EditorNotifications.getInstance(project).updateNotifications(ktFile.alwaysVirtualFile)
}
}
override fun getActionUpdateThread() = ActionUpdateThread.BGT
override fun update(e: AnActionEvent) {
val editor = e.getData(CommonDataKeys.EDITOR)
e.presentation.isEnabledAndVisible = editor != null && getNotificationVisibility(editor)
}
private fun getNotificationVisibility(editor: Editor): Boolean {
val file = getKotlinScriptFile(editor) ?: return false
if (!file.name.endsWith(".main.kts")) return false
if (DiffUtil.isDiffEditor(editor)) return false
val actualAnnotations = file.getScriptAnnotationsList()
val previous = annotations[file] ?: emptyList()
return if (previous.isEmpty() && actualAnnotations.isEmpty()) {
false
} else {
previous != actualAnnotations
}
}
private fun getKotlinScriptFile(editor: Editor): KtFile? {
val virtualFile = editor.virtualFile ?: return null
return editor.project?.let { virtualFile.findPsiFile(it) as? KtFile }
}
}

View File

@@ -22,12 +22,6 @@
area="IDEA_PROJECT"
dynamic="true"/>
<extensionPoint
qualifiedName="org.jetbrains.kotlin.scriptConfigurationsSource"
interface="org.jetbrains.kotlin.idea.core.script.k2.ScriptConfigurationsSource"
area="IDEA_PROJECT"
dynamic="true"/>
<extensionPoint
qualifiedName="org.jetbrains.kotlin.scriptDiagnosticFixProvider"
interface="org.jetbrains.kotlin.idea.script.ScriptDiagnosticFixProvider"
@@ -99,6 +93,8 @@
<projectService serviceInterface="org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider"
serviceImplementation="org.jetbrains.kotlin.idea.core.script.k2.K2ScriptDefinitionProvider"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.core.script.k2.DefaultScriptConfigurationHandler"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager"
serviceImplementation="org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager"/>
@@ -123,7 +119,7 @@
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<scriptDefinitionsSource
<scriptDefinitionsSource
id="BridgeScriptDefinitionsContributor"
implementation="org.jetbrains.kotlin.idea.core.script.BridgeScriptDefinitionsContributor"/>
@@ -135,9 +131,6 @@
implementation="org.jetbrains.kotlin.idea.base.scripting.ScriptingModuleInfoProviderExtension"/>
<scriptDefinitionsSource implementation="org.jetbrains.kotlin.idea.core.script.k2.MainKtsScriptDefinitionSource"/>
<scriptConfigurationsSource implementation="org.jetbrains.kotlin.idea.core.script.k2.BundledScriptConfigurationsSource"/>
<scriptConfigurationsSource implementation="org.jetbrains.kotlin.idea.core.script.k2.DependentScriptConfigurationsSource"/>
<scriptDefinitionsSource implementation="org.jetbrains.kotlin.idea.core.script.BundledScriptDefinitionSource"/>
<scriptDefinitionsSource implementation="org.jetbrains.kotlin.idea.script.k2.ScriptTemplatesFromDependenciesDefinitionSource"/>
@@ -145,7 +138,7 @@
<actions resource-bundle="messages.KotlinBaseScriptingBundle">
<action id="LoadMainKtsConfiguration"
class="org.jetbrains.kotlin.idea.script.k2.ReloadDependenciesScriptAction"
class="org.jetbrains.kotlin.idea.script.k2.ReloadMainKtsScriptDependenciesAction"
icon="org.jetbrains.kotlin.idea.KotlinIcons.LOAD_SCRIPT_CONFIGURATION">
<add-to-group group-id="EditorContextBarMenu"/>
</action>