mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
[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:
committed by
intellij-monorepo-bot
parent
8c93fe043a
commit
0595001d12
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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> =
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, ':')
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user