From a569c36ef9c15a7981e9f147e5588789f65f9fd9 Mon Sep 17 00:00:00 2001 From: Istvan Meszaros Date: Thu, 19 Mar 2026 12:05:44 +0100 Subject: [PATCH 1/3] KTIJ-35157 Scripts: importScripts doesn't import files Implemented imported script resolution in DefaultKotlinScriptEntityProvider, and added a new implementation of K2IdeScriptAdditionalIdeaDependenciesProvider. --- .../intellij.kotlin.base.scripting.xml | 3 ++ .../DefaultKotlinScriptEntityProvider.kt | 20 +++++++++++++ .../configurations/MainKtsEntityProvider.kt | 7 ----- ...DefaultKotlinScriptDependenciesProvider.kt | 28 +++++++++++++++++++ .../k2/modules/KotlinScriptEntityProvider.kt | 16 +++++++++++ 5 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/DefaultKotlinScriptDependenciesProvider.kt diff --git a/plugins/kotlin/base/scripting/scripting.k2/resources/intellij.kotlin.base.scripting.xml b/plugins/kotlin/base/scripting/scripting.k2/resources/intellij.kotlin.base.scripting.xml index 0d8af835f96d8..a04aa87fc1673 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/resources/intellij.kotlin.base.scripting.xml +++ b/plugins/kotlin/base/scripting/scripting.k2/resources/intellij.kotlin.base.scripting.xml @@ -82,6 +82,9 @@ order="last" implementation="org.jetbrains.kotlin.idea.core.script.k2.definitions.BundledScriptDefinitionSource"/> + + diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt index 1841d077b76b9..5dfb71ca57a1c 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt @@ -1,6 +1,8 @@ // 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.configurations +import com.google.common.collect.TreeMultimap +import com.google.common.graph.Traverser import com.intellij.openapi.application.smartReadAction import com.intellij.openapi.components.Service import com.intellij.openapi.components.service @@ -12,6 +14,7 @@ import com.intellij.platform.workspace.storage.EntitySource import com.intellij.platform.workspace.storage.MutableEntityStorage import kotlinx.coroutines.CoroutineScope import org.jetbrains.kotlin.idea.core.script.k2.getOrCreateScriptConfigurationId +import org.jetbrains.kotlin.idea.core.script.k2.highlighting.KotlinScriptResolutionService import org.jetbrains.kotlin.idea.core.script.k2.modules.KotlinScriptEntity import org.jetbrains.kotlin.idea.core.script.k2.modules.KotlinScriptEntityProvider import org.jetbrains.kotlin.idea.core.script.k2.modules.KotlinScriptLibraryEntity @@ -35,6 +38,17 @@ import kotlin.script.experimental.jvm.jvm class DefaultKotlinScriptEntityProvider( override val project: Project, val coroutineScope: CoroutineScope ) : KotlinScriptEntityProvider(project) { + + private val visitedScripts = TreeMultimap.create(COMPARATOR, COMPARATOR) + private val visitedScriptsTraverser = Traverser.forTree { visitedScripts.get(it) } + + fun getImportedScripts(kts: VirtualFile): List = visitedScriptsTraverser.breadthFirst(kts) - kts + + override suspend fun removeKotlinScriptEntity(virtualFile: VirtualFile) { + visitedScripts.removeAll(virtualFile) + super.removeKotlinScriptEntity(virtualFile) + } + override suspend fun updateWorkspaceModel( virtualFile: VirtualFile, definition: ScriptDefinition ) { @@ -55,6 +69,12 @@ class DefaultKotlinScriptEntityProvider( } } + val scriptsToResolve = result.importedScripts - visitedScripts.keys() + if (scriptsToResolve.isNotEmpty()) { + visitedScripts.putAll(virtualFile, scriptsToResolve) + KotlinScriptResolutionService.getInstance(project).process(scriptsToResolve) + } + fun updateStorage(storage: MutableEntityStorage) { val configuration = result.valueOrNull()?.configuration ?: return val definition = findScriptDefinition(project, VirtualFileScriptSource(virtualFile)) diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt index 41c03ab3100ef..b74cb9ac8d8bb 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt @@ -138,14 +138,7 @@ class MainKtsEntityProvider( } } - private val ScriptCompilationConfigurationResult.importedScripts: List - get() { - val importedScripts = this.valueOrNull()?.importedScripts ?: return emptyList() - return importedScripts.mapNotNull { (it as? VirtualFileScriptSource)?.virtualFile }.filterNot { it.isNonScript() } - } - companion object { - private val COMPARATOR = Comparator { left, right -> left.path.compareTo(right.path) } @JvmStatic fun getInstance(project: Project): MainKtsEntityProvider = project.service() diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/DefaultKotlinScriptDependenciesProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/DefaultKotlinScriptDependenciesProvider.kt new file mode 100644 index 0000000000000..862f866eb8069 --- /dev/null +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/DefaultKotlinScriptDependenciesProvider.kt @@ -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.idea.core.script.k2.modules + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.platform.backend.workspace.toVirtualFileUrl +import com.intellij.platform.backend.workspace.workspaceModel +import org.jetbrains.kotlin.idea.core.script.k2.configurations.DefaultKotlinScriptEntityProvider + +class DefaultKotlinScriptDependenciesProvider : K2IdeScriptAdditionalIdeaDependenciesProvider { + override fun getRelatedModules( + file: VirtualFile, project: Project + ): List { + return DefaultKotlinScriptEntityProvider.getInstance(project).getImportedScripts(file) + } + + override fun getRelatedLibraries( + file: VirtualFile, project: Project + ): List { + val currentSnapshot = project.workspaceModel.currentSnapshot + val index = currentSnapshot.getVirtualFileUrlIndex() + val manager = project.workspaceModel.getVirtualFileUrlManager() + + return getRelatedModules(file, project).flatMap { + index.findEntitiesByUrl(it.toVirtualFileUrl(manager)) + }.filterIsInstance().flatMap { it.dependencies.mapNotNull { currentSnapshot.resolve(it) } } + } +} \ No newline at end of file diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/KotlinScriptEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/KotlinScriptEntityProvider.kt index bced466062f6c..dabee13717468 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/KotlinScriptEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/modules/KotlinScriptEntityProvider.kt @@ -11,6 +11,10 @@ import com.intellij.platform.workspace.storage.ImmutableEntityStorage import com.intellij.platform.workspace.storage.MutableEntityStorage import com.intellij.platform.workspace.storage.url.VirtualFileUrl import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.isNonScript +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import kotlin.script.experimental.api.valueOrNull /** * Base contract for providing and maintaining [KotlinScriptEntity] instances in the Workspace Model. @@ -39,6 +43,12 @@ abstract class KotlinScriptEntityProvider( protected val VirtualFile.virtualFileUrl: VirtualFileUrl get() = toVirtualFileUrl(project.workspaceModel.getVirtualFileUrlManager()) + protected val ScriptCompilationConfigurationResult.importedScripts: List + get() { + val importedScripts = this.valueOrNull()?.importedScripts ?: return emptyList() + return importedScripts.mapNotNull { (it as? VirtualFileScriptSource)?.virtualFile }.filterNot { it.isNonScript() } + } + /** * Finds a [KotlinScriptEntity] associated with the given [virtualFile] in the current snapshot. * @@ -81,4 +91,10 @@ abstract class KotlinScriptEntityProvider( updater(it) } } + + protected companion object { + + @JvmStatic + protected val COMPARATOR = Comparator { left, right -> left.path.compareTo(right.path) } + } } From 5b0706283bafcee2f96746ecb0333a0ffce8b399 Mon Sep 17 00:00:00 2001 From: Istvan Meszaros Date: Thu, 19 Mar 2026 13:03:25 +0100 Subject: [PATCH 2/3] KTIJ-35157 Scripts: importScripts doesn't import files Fixed an issue that could cause resolution to fail for a script that imports another script and the script configuration for the imported script was reloaded at least once previously. --- .../configurations/DefaultKotlinScriptEntityProvider.kt | 9 +++++---- .../script/k2/configurations/MainKtsEntityProvider.kt | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt index 5dfb71ca57a1c..85050c070fb02 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt @@ -69,10 +69,11 @@ class DefaultKotlinScriptEntityProvider( } } - val scriptsToResolve = result.importedScripts - visitedScripts.keys() - if (scriptsToResolve.isNotEmpty()) { - visitedScripts.putAll(virtualFile, scriptsToResolve) - KotlinScriptResolutionService.getInstance(project).process(scriptsToResolve) + result.importedScripts.let { scriptsToResolve -> + if (scriptsToResolve.isNotEmpty()) { + visitedScripts.putAll(virtualFile, scriptsToResolve) + KotlinScriptResolutionService.getInstance(project).process(scriptsToResolve - visitedScripts.keys()) + } } fun updateStorage(storage: MutableEntityStorage) { diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt index b74cb9ac8d8bb..6dd5c0027b165 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt @@ -62,10 +62,11 @@ class MainKtsEntityProvider( if (project.workspaceModel.currentSnapshot.containsScriptEntity(scriptUrl)) return val mainKtsConfiguration = resolveMainKtsConfiguration(virtualFile, definition) - val scriptsToResolve = mainKtsConfiguration.importedScripts - visitedScripts.keys() - if (scriptsToResolve.isNotEmpty()) { - visitedScripts.putAll(virtualFile, scriptsToResolve) - KotlinScriptResolutionService.getInstance(project).process(scriptsToResolve) + mainKtsConfiguration.importedScripts.let { scriptsToResolve -> + if (scriptsToResolve.isNotEmpty()) { + visitedScripts.putAll(virtualFile, scriptsToResolve) + KotlinScriptResolutionService.getInstance(project).process(scriptsToResolve - visitedScripts.keys()) + } } fun updateStorage(storage: MutableEntityStorage) { From 616db9038195eee8e4980bcc183b303d2c853274 Mon Sep 17 00:00:00 2001 From: Istvan Meszaros Date: Thu, 19 Mar 2026 13:43:22 +0100 Subject: [PATCH 3/3] KTIJ-35157 Scripts: importScripts doesn't import files Avoid potential endless loop in case of import cycle. --- .../k2/configurations/DefaultKotlinScriptEntityProvider.kt | 2 +- .../idea/core/script/k2/configurations/MainKtsEntityProvider.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt index 85050c070fb02..374cc47a56224 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/DefaultKotlinScriptEntityProvider.kt @@ -40,7 +40,7 @@ class DefaultKotlinScriptEntityProvider( ) : KotlinScriptEntityProvider(project) { private val visitedScripts = TreeMultimap.create(COMPARATOR, COMPARATOR) - private val visitedScriptsTraverser = Traverser.forTree { visitedScripts.get(it) } + private val visitedScriptsTraverser = Traverser.forGraph { visitedScripts.get(it) } fun getImportedScripts(kts: VirtualFile): List = visitedScriptsTraverser.breadthFirst(kts) - kts diff --git a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt index 6dd5c0027b165..29f4ad862fc95 100644 --- a/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt +++ b/plugins/kotlin/base/scripting/scripting.k2/src/org/jetbrains/kotlin/idea/core/script/k2/configurations/MainKtsEntityProvider.kt @@ -42,7 +42,7 @@ class MainKtsEntityProvider( val coroutineScope: CoroutineScope ) : KotlinScriptEntityProvider(project) { private val visitedScripts = TreeMultimap.create(COMPARATOR, COMPARATOR) - private val visitedScriptsTraverser = Traverser.forTree { visitedScripts.get(it) } + private val visitedScriptsTraverser = Traverser.forGraph { visitedScripts.get(it) } fun getImportedScripts(mainKts: VirtualFile): List = visitedScriptsTraverser.breadthFirst(mainKts) - mainKts