Refactor the mechanism how script configurations are updated
Introduce file attributes cache, which is only applicable when no dependencies are cached in memory cache Refactor ScriptDependenciesCache to memory cache that is able to get configuration from cache and checks if it is up to date Move all public methods to ScriptDependenciesManager Introduce ScriptClassRootsManager that checks if root change event should be called after script configuration update
This commit is contained in:
@@ -431,7 +431,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
|
||||
if (externalImportsProvider != null) {
|
||||
myEnvironment.getSourceFiles().forEach(
|
||||
file -> {
|
||||
ScriptCompilationConfigurationWrapper refinedConfiguration = ErrorHandlingKt.valueOrNull(externalImportsProvider.getScriptConfigurationResult(file));
|
||||
ScriptCompilationConfigurationWrapper refinedConfiguration = externalImportsProvider.getScriptConfiguration(file);
|
||||
if (refinedConfiguration != null) {
|
||||
files.addAll(refinedConfiguration.getDependenciesClassPath());
|
||||
}
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ sealed class ScriptDependenciesInfo(val project: Project) : IdeaModuleInfo, Bina
|
||||
class ForProject(project: Project) : ScriptDependenciesInfo(project) {
|
||||
override val sdk: Sdk?
|
||||
get() {
|
||||
return ScriptDependenciesManager.getInstance(project).getAllScriptsSdks().firstOrNull()
|
||||
return ScriptDependenciesManager.getInstance(project).getFirstScriptsSdk()
|
||||
?: ScriptDependenciesManager.getScriptDefaultSdk(project)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.idea.caches.project.NotUnderContentRootModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.idea.util.isRunningInCidrIde
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
@@ -70,7 +70,7 @@ object KotlinHighlightingUtil {
|
||||
@Suppress("DEPRECATION")
|
||||
private fun shouldHighlightScript(ktFile: KtFile): Boolean {
|
||||
if (isRunningInCidrIde) return false // There is no Java support in CIDR. So do not highlight errors in KTS if running in CIDR.
|
||||
if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(ktFile)) return false
|
||||
if (!ScriptDependenciesManager.getInstance(ktFile.project).isConfigurationCached(ktFile)) return false
|
||||
if (IdeScriptReportSink.getReports(ktFile).any { it.severity == ScriptDiagnostic.Severity.FATAL }) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -16,13 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.ui.EditorNotifications
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
||||
@@ -34,15 +30,6 @@ class IdeScriptReportSink(val project: Project) : ScriptReportSink {
|
||||
|
||||
// TODO: persist errors between launches?
|
||||
scriptFile.scriptDiagnostics = reports
|
||||
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
if (scriptFile.isValid && !project.isDisposed) {
|
||||
PsiManager.getInstance(project).findFile(scriptFile)?.let { psiFile ->
|
||||
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
|
||||
EditorNotifications.getInstance(project).updateNotifications(scriptFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.TransactionGuard
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.util.EmptyRunnable
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
/**
|
||||
* Utility for postponing indexing of new roots at the end of some bulk operation.
|
||||
*/
|
||||
internal class ScriptClassRootsManager(val project: Project) {
|
||||
private var newRootsPresent: Boolean = false
|
||||
private val concurrentTransactions = AtomicInteger()
|
||||
|
||||
fun checkNonCachedRoots(
|
||||
cache: ScriptConfigurationMemoryCache,
|
||||
file: VirtualFile,
|
||||
configuration: ScriptCompilationConfigurationWrapper
|
||||
) {
|
||||
checkInTransaction()
|
||||
if (cache.hasNotCachedRoots(configuration)) {
|
||||
synchronized(this) {
|
||||
debug(file) { "new class roots found: $configuration" }
|
||||
checkInTransaction()
|
||||
newRootsPresent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkInTransaction() {
|
||||
check(concurrentTransactions.get() > 0)
|
||||
}
|
||||
|
||||
inline fun transaction(body: () -> Unit) {
|
||||
startTransaction()
|
||||
try {
|
||||
body()
|
||||
} finally {
|
||||
commit()
|
||||
}
|
||||
}
|
||||
|
||||
fun startTransaction() {
|
||||
concurrentTransactions.incrementAndGet()
|
||||
}
|
||||
|
||||
fun commit() {
|
||||
concurrentTransactions.decrementAndGet()
|
||||
|
||||
// run indexing even in inner transaction
|
||||
// (outer transaction may be async, so it would be better to not wait it)
|
||||
startIndexingIfNeeded()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun startIndexingIfNeeded() {
|
||||
if (!newRootsPresent) return
|
||||
newRootsPresent = false
|
||||
|
||||
val doNotifyRootsChanged = Runnable {
|
||||
runWriteAction {
|
||||
if (project.isDisposed) return@runWriteAction
|
||||
|
||||
debug { "roots change event" }
|
||||
|
||||
ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true)
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
TransactionGuard.submitTransaction(project, doNotifyRootsChanged)
|
||||
} else {
|
||||
TransactionGuard.getInstance().submitTransactionLater(project, doNotifyRootsChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
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.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.ui.EditorNotifications
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager.Companion.toVfsRoots
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.*
|
||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
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.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
class ScriptConfigurationManagerImpl internal constructor(
|
||||
private val project: Project
|
||||
) : ScriptConfigurationManager, ScriptDependenciesManager {
|
||||
private val rootsManager = ScriptClassRootsManager(project)
|
||||
|
||||
private val memoryCache = ScriptConfigurationMemoryCache(project)
|
||||
private val fileAttributesCache = ScriptConfigurationFileAttributeCache()
|
||||
|
||||
private val fromRefinedLoader = FromRefinedConfigurationLoader()
|
||||
private val loaders = arrayListOf(
|
||||
OutsiderFileDependenciesLoader(this),
|
||||
fromRefinedLoader,
|
||||
fileAttributesCache
|
||||
)
|
||||
|
||||
private val backgroundLoader = BackgroundLoader(project, rootsManager, ::reloadConfigurationAsync)
|
||||
|
||||
private val listener = ScriptsListener(project, this)
|
||||
|
||||
/**
|
||||
* Save configurations into cache.
|
||||
* Start indexing for new class/source roots.
|
||||
* Re-highlight opened scripts with changed configuration.
|
||||
*/
|
||||
override fun saveCompilationConfigurationAfterImport(files: List<Pair<VirtualFile, ScriptCompilationConfigurationResult>>) {
|
||||
rootsManager.transaction {
|
||||
for ((file, result) in files) {
|
||||
saveConfiguration(file, result, skipNotification = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start configuration update for files if configuration isn't up to date.
|
||||
* Start indexing for new class/source roots.
|
||||
*
|
||||
* @return true if update was started for any file, false if all configurations are cached
|
||||
*/
|
||||
override fun updateConfigurationsIfNotCached(files: List<KtFile>): Boolean {
|
||||
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return false
|
||||
|
||||
val notCached = files.filterNot { isConfigurationUpToDate(it.originalFile.virtualFile) }
|
||||
if (notCached.isNotEmpty()) {
|
||||
rootsManager.transaction {
|
||||
for (file in notCached) {
|
||||
reloadConfiguration(file)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if configuration is already cached for [file] (in cache or FileAttributes).
|
||||
* Don't check if file was changed after the last update.
|
||||
* Supposed to be used to switch highlighting off for scripts without configuration.
|
||||
* to avoid all file being highlighted in red.
|
||||
*/
|
||||
override fun isConfigurationCached(file: KtFile): Boolean {
|
||||
return isConfigurationCached(file.originalFile.virtualFile)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear configuration caches
|
||||
* Start re-highlighting for opened scripts
|
||||
*/
|
||||
override fun clearConfigurationCachesAndRehighlight() {
|
||||
clearAndRehighlight()
|
||||
}
|
||||
|
||||
@Deprecated("Use getScriptClasspath(KtFile) instead")
|
||||
override fun getScriptClasspath(file: VirtualFile): List<VirtualFile> {
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return emptyList()
|
||||
return getScriptClasspath(ktFile)
|
||||
}
|
||||
|
||||
override fun getScriptClasspath(file: KtFile): List<VirtualFile> =
|
||||
toVfsRoots(getConfiguration(file)?.dependenciesClassPath.orEmpty())
|
||||
|
||||
override fun getConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? {
|
||||
val virtualFile = file.originalFile.virtualFile
|
||||
|
||||
val cached = getCachedConfiguration(virtualFile)
|
||||
if (cached != null) {
|
||||
return cached
|
||||
}
|
||||
|
||||
if (ScriptDefinitionsManager.getInstance(project).isReady() && !isConfigurationUpToDate(virtualFile)) {
|
||||
rootsManager.transaction {
|
||||
reloadConfiguration(file)
|
||||
}
|
||||
}
|
||||
|
||||
return getCachedConfiguration(virtualFile)
|
||||
}
|
||||
|
||||
override fun getScriptDependenciesClassFilesScope(file: VirtualFile) = scriptDependenciesClassFilesScope(file)
|
||||
override fun getScriptSdk(file: VirtualFile) = scriptSdk(file)
|
||||
|
||||
override fun getFirstScriptsSdk() = memoryCache.firstScriptSdk
|
||||
|
||||
override fun getAllScriptsDependenciesClassFilesScope() = memoryCache.allDependenciesClassFilesScope
|
||||
override fun getAllScriptDependenciesSourcesScope() = memoryCache.allDependenciesSourcesScope
|
||||
|
||||
override fun getAllScriptsDependenciesClassFiles() = memoryCache.allDependenciesClassFiles
|
||||
override fun getAllScriptDependenciesSources() = memoryCache.allDependenciesSources
|
||||
|
||||
@TestOnly
|
||||
fun updateScriptDependenciesSynchronously(file: PsiFile) {
|
||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||
assert(file is KtFile) {
|
||||
"PsiFile should be a KtFile, otherwise script dependencies cannot be loaded"
|
||||
}
|
||||
|
||||
if (isConfigurationUpToDate(file.virtualFile)) return
|
||||
|
||||
rootsManager.transaction {
|
||||
val result = fromRefinedLoader.loadDependencies(true, file as KtFile, scriptDefinition)
|
||||
if (result != null) {
|
||||
saveConfiguration(file.originalFile.virtualFile, result, skipNotification = true, skipSaveToAttributes = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadConfiguration(file: KtFile) {
|
||||
val virtualFile = file.originalFile.virtualFile
|
||||
|
||||
memoryCache.setUpToDate(virtualFile)
|
||||
|
||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||
|
||||
val syncLoaders = loaders.filterNot { it.isAsync(file, scriptDefinition) }
|
||||
reloadConfigurationBy(file, scriptDefinition, syncLoaders)
|
||||
|
||||
val asyncLoaders = loaders - syncLoaders
|
||||
if (asyncLoaders.isNotEmpty()) {
|
||||
backgroundLoader.scheduleAsync(file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadConfigurationAsync(file: KtFile) {
|
||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||
|
||||
val asyncLoaders = loaders.filter { it.isAsync(file, scriptDefinition) }
|
||||
|
||||
if (asyncLoaders.size > 1) {
|
||||
LOG.warn("There are more than one async compilation configuration loader. " +
|
||||
"This mean that the last one will overwrite the results of the previous ones: " +
|
||||
asyncLoaders.joinToString { it.javaClass.name })
|
||||
}
|
||||
|
||||
reloadConfigurationBy(file, scriptDefinition, asyncLoaders)
|
||||
}
|
||||
|
||||
private fun reloadConfigurationBy(file: KtFile, scriptDefinition: ScriptDefinition, loaders: List<ScriptDependenciesLoader>) {
|
||||
val firstLoad = memoryCache.getCachedConfiguration(file.originalFile.virtualFile) == null
|
||||
|
||||
loaders.forEach { loader ->
|
||||
val result = loader.loadDependencies(firstLoad, file, scriptDefinition)
|
||||
if (result != null) {
|
||||
return saveConfiguration(file.originalFile.virtualFile, result, loader.skipNotification, loader.skipSaveToAttributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save [newResult] for [file] into caches and update highlih.
|
||||
* Should be called inside `rootsManager.transaction { ... }`.
|
||||
*
|
||||
* @param skipNotification forces loading new configuration even if auto reload is disabled.
|
||||
* @param skipSaveToAttributes skips saving to FileAttributes (used in [ScriptConfigurationFileAttributeCache] only).
|
||||
*
|
||||
* @sample ScriptDependenciesManager.getConfiguration
|
||||
*/
|
||||
private fun saveConfiguration(
|
||||
file: VirtualFile,
|
||||
newResult: ScriptCompilationConfigurationResult,
|
||||
skipNotification: Boolean = false,
|
||||
skipSaveToAttributes: Boolean = false
|
||||
) {
|
||||
debug(file) { "configuration received = $newResult" }
|
||||
|
||||
saveReports(file, newResult.reports)
|
||||
|
||||
val newConfiguration = newResult.valueOrNull()
|
||||
if (newConfiguration != null) {
|
||||
val oldConfiguration = getCachedConfiguration(file)
|
||||
if (oldConfiguration == newConfiguration) {
|
||||
file.removeScriptDependenciesNotificationPanel(project)
|
||||
} else {
|
||||
val autoReload = skipNotification
|
||||
|| oldConfiguration == null
|
||||
|| KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled
|
||||
|| ApplicationManager.getApplication().isUnitTestMode
|
||||
|
||||
if (autoReload) {
|
||||
if (oldConfiguration != null) {
|
||||
file.removeScriptDependenciesNotificationPanel(project)
|
||||
}
|
||||
saveChangedConfiguration(file, newConfiguration, skipSaveToAttributes)
|
||||
} else {
|
||||
debug(file) {
|
||||
"configuration changed, notification is shown: old = $oldConfiguration, new = $newConfiguration"
|
||||
}
|
||||
file.addScriptDependenciesNotificationPanel(
|
||||
newConfiguration, project,
|
||||
onClick = {
|
||||
file.removeScriptDependenciesNotificationPanel(project)
|
||||
rootsManager.transaction {
|
||||
saveChangedConfiguration(file, it, skipSaveToAttributes)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveChangedConfiguration(
|
||||
file: VirtualFile,
|
||||
newConfiguration: ScriptCompilationConfigurationWrapper?,
|
||||
skipSaveToAttributes: Boolean
|
||||
) {
|
||||
debug(file) { "configuration changed = $newConfiguration" }
|
||||
|
||||
if (newConfiguration != null) {
|
||||
rootsManager.checkNonCachedRoots(memoryCache, file, newConfiguration)
|
||||
|
||||
if (!skipSaveToAttributes) {
|
||||
debug(file) { "configuration saved to file attributes: $newConfiguration" }
|
||||
|
||||
fileAttributesCache.save(file, newConfiguration)
|
||||
}
|
||||
|
||||
memoryCache.replaceConfiguration(file, newConfiguration)
|
||||
memoryCache.clearClassRootsCaches()
|
||||
}
|
||||
|
||||
updateHighlighting(listOf(file))
|
||||
}
|
||||
|
||||
private fun saveReports(
|
||||
file: VirtualFile,
|
||||
newReports: List<ScriptDiagnostic>
|
||||
) {
|
||||
val oldReports = IdeScriptReportSink.getReports(file)
|
||||
if (oldReports != newReports) {
|
||||
debug(file) { "new script reports = $newReports" }
|
||||
|
||||
ServiceManager.getService(project, ScriptReportSink::class.java).attachReports(file, newReports)
|
||||
|
||||
GlobalScope.launch(EDT(project)) {
|
||||
if (project.isDisposed) return@launch
|
||||
|
||||
EditorNotifications.getInstance(project).updateAllNotifications()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHighlighting(files: List<VirtualFile>) {
|
||||
if (files.isEmpty()) return
|
||||
|
||||
GlobalScope.launch(EDT(project)) {
|
||||
if (project.isDisposed) return@launch
|
||||
|
||||
val openFiles = FileEditorManager.getInstance(project).openFiles
|
||||
val openScripts = files.filter { it.isValid && openFiles.contains(it) }
|
||||
|
||||
openScripts.forEach {
|
||||
PsiManager.getInstance(project).findFile(it)?.let { psiFile ->
|
||||
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCachedConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? =
|
||||
memoryCache.getCachedConfiguration(file)
|
||||
|
||||
private fun isConfigurationCached(file: VirtualFile): Boolean {
|
||||
return getCachedConfiguration(file) != null || file in fileAttributesCache
|
||||
}
|
||||
|
||||
private fun isConfigurationUpToDate(file: VirtualFile): Boolean {
|
||||
return isConfigurationCached(file) && memoryCache.isConfigurationUpToDate(file)
|
||||
}
|
||||
|
||||
private fun clearAndRehighlight() {
|
||||
updateHighlighting(memoryCache.clearConfigurationCaches())
|
||||
}
|
||||
|
||||
private fun scriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope {
|
||||
return memoryCache.scriptsDependenciesClasspathScopeCache[file] ?: GlobalSearchScope.EMPTY_SCOPE
|
||||
}
|
||||
|
||||
private fun scriptSdk(file: VirtualFile): Sdk? {
|
||||
return memoryCache.scriptsSdksCache[file]
|
||||
}
|
||||
}
|
||||
+74
-82
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.ProjectTopics
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -23,12 +22,10 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.NonClasspathDirectoriesScope
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||
import com.intellij.util.containers.SLRUMap
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationMemoryCache.Companion.MAX_SCRIPTS_CACHED
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
@@ -36,9 +33,8 @@ import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
class ScriptConfigurationMemoryCache internal constructor(private val project: Project) {
|
||||
|
||||
companion object {
|
||||
const val MAX_SCRIPTS_CACHED = 50
|
||||
@@ -48,29 +44,37 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
val connection = project.messageBus.connect()
|
||||
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
|
||||
override fun rootsChanged(event: ModuleRootEvent) {
|
||||
clearCaches()
|
||||
clearClassRootsCaches()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val cacheLock = ReentrantReadWriteLock()
|
||||
|
||||
private val scriptDependenciesCache = SLRUCacheWithLock<VirtualFile, ScriptCompilationConfigurationResult>()
|
||||
private val scriptsModificationStampsCache = SLRUCacheWithLock<KtFile, Long>()
|
||||
private val scriptDependenciesCache = SLRUCacheWithLock<VirtualFile, ScriptCompilationConfigurationWrapper>()
|
||||
private val scriptsModificationStampsCache = SLRUCacheWithLock<VirtualFile, Long>()
|
||||
|
||||
operator fun get(file: VirtualFile): ScriptCompilationConfigurationResult? = scriptDependenciesCache.get(file)
|
||||
fun getCachedConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? = scriptDependenciesCache.get(file)
|
||||
|
||||
fun shouldRunDependenciesUpdate(file: KtFile): Boolean {
|
||||
return scriptsModificationStampsCache.replace(file, file.modificationStamp) != file.modificationStamp
|
||||
fun isConfigurationUpToDate(file: VirtualFile): Boolean {
|
||||
return scriptsModificationStampsCache.get(file) == file.modificationStamp
|
||||
}
|
||||
|
||||
private val scriptsDependenciesClasspathScopeCache: MutableMap<VirtualFile, GlobalSearchScope> =
|
||||
fun setUpToDate(file: VirtualFile) {
|
||||
scriptsModificationStampsCache.replace(file, file.modificationStamp)
|
||||
}
|
||||
|
||||
fun replaceConfiguration(file: VirtualFile, new: ScriptCompilationConfigurationWrapper) {
|
||||
scriptDependenciesCache.replace(file, new)
|
||||
}
|
||||
|
||||
val scriptsDependenciesClasspathScopeCache: MutableMap<VirtualFile, GlobalSearchScope> =
|
||||
ConcurrentFactoryMap.createWeakMap { file ->
|
||||
val compilationConfiguration = getCachedConfigurationOrLoad(file)
|
||||
?: return@createWeakMap null
|
||||
val compilationConfiguration = getConfiguration(file)
|
||||
?: return@createWeakMap GlobalSearchScope.EMPTY_SCOPE
|
||||
|
||||
val roots = compilationConfiguration.dependenciesClassPath
|
||||
val sdk = getScriptSdk(file)
|
||||
val sdk = scriptsSdksCache[file]
|
||||
|
||||
@Suppress("FoldInitializerAndIfToElvis")
|
||||
if (sdk == null) {
|
||||
@@ -83,29 +87,19 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
)
|
||||
}
|
||||
|
||||
fun scriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope {
|
||||
return scriptsDependenciesClasspathScopeCache[file] ?: GlobalSearchScope.EMPTY_SCOPE
|
||||
}
|
||||
|
||||
private val scriptsSdksCache: MutableMap<VirtualFile, Sdk?> =
|
||||
val scriptsSdksCache: MutableMap<VirtualFile, Sdk?> =
|
||||
ConcurrentFactoryMap.createWeakMap { file ->
|
||||
val compilationConfiguration = getCachedConfigurationOrLoad(file)
|
||||
val compilationConfiguration = getConfiguration(file)
|
||||
return@createWeakMap getScriptSdk(compilationConfiguration) ?: ScriptDependenciesManager.getScriptDefaultSdk(project)
|
||||
}
|
||||
|
||||
fun getScriptSdk(file: VirtualFile): Sdk? {
|
||||
return scriptsSdksCache[file]
|
||||
}
|
||||
private fun getConfiguration(file: VirtualFile): ScriptCompilationConfigurationWrapper? {
|
||||
val configuration = getCachedConfiguration(file)
|
||||
|
||||
private fun getCachedConfigurationOrLoad(file: VirtualFile): ScriptCompilationConfigurationWrapper? {
|
||||
val compilationConfiguration = scriptDependenciesCache.get(file)?.valueOrNull()
|
||||
if (configuration != null) return configuration
|
||||
|
||||
if (compilationConfiguration != null) {
|
||||
return compilationConfiguration
|
||||
}
|
||||
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return null
|
||||
return ScriptDependenciesManager.getInstance(project).getRefinedCompilationConfiguration(ktFile)?.valueOrNull()
|
||||
val ktFile = runReadAction { PsiManager.getInstance(project).findFile(file) as? KtFile } ?: return null
|
||||
return ScriptDependenciesManager.getInstance(project).getConfiguration(ktFile)
|
||||
}
|
||||
|
||||
private fun getScriptSdk(compilationConfiguration: ScriptCompilationConfigurationWrapper?): Sdk? {
|
||||
@@ -119,15 +113,21 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
return getAllProjectSdks().find { it.homeDirectory == javaHome }
|
||||
}
|
||||
|
||||
val allSdks by ClearableLazyValue(cacheLock) {
|
||||
val firstScriptSdk: Sdk?
|
||||
get() {
|
||||
val firstCachedScript = scriptDependenciesCache.getAll().firstOrNull()?.key ?: return null
|
||||
return scriptsSdksCache[firstCachedScript]
|
||||
}
|
||||
|
||||
private val allSdks by ClearableLazyValue(cacheLock) {
|
||||
scriptDependenciesCache.getAll()
|
||||
.mapNotNull { getScriptSdk(it.key) }
|
||||
.mapNotNull { scriptsSdksCache[it.key] }
|
||||
.distinct()
|
||||
}
|
||||
|
||||
private val allNonIndexedSdks by ClearableLazyValue(cacheLock) {
|
||||
scriptDependenciesCache.getAll()
|
||||
.mapNotNull { getScriptSdk(it.key) }
|
||||
.mapNotNull { scriptsSdksCache[it.key] }
|
||||
.filterNonModuleSdk()
|
||||
.distinct()
|
||||
}
|
||||
@@ -137,7 +137,7 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
.flatMap { it.rootProvider.getFiles(OrderRootType.CLASSES).toList() }
|
||||
|
||||
val scriptDependenciesClasspath = scriptDependenciesCache.getAll()
|
||||
.flatMap { it.value.valueOrNull()?.dependenciesClassPath ?: emptyList() }.distinct()
|
||||
.flatMap { it.value.dependenciesClassPath }.distinct()
|
||||
|
||||
sdkFiles + ScriptDependenciesManager.toVfsRoots(scriptDependenciesClasspath)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
.flatMap { it.rootProvider.getFiles(OrderRootType.SOURCES).toList() }
|
||||
|
||||
val scriptDependenciesSources = scriptDependenciesCache.getAll()
|
||||
.flatMap { it.value.valueOrNull()?.dependenciesSources ?: emptyList() }.distinct()
|
||||
.flatMap { it.value.dependenciesSources }.distinct()
|
||||
sdkSources + ScriptDependenciesManager.toVfsRoots(scriptDependenciesSources)
|
||||
}
|
||||
|
||||
@@ -164,12 +164,20 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
return filterNot { moduleSdks.contains(it) }
|
||||
}
|
||||
|
||||
private fun onChange(files: List<VirtualFile>) {
|
||||
clearCaches()
|
||||
updateHighlighting(files)
|
||||
fun clearConfigurationCaches(): List<VirtualFile> {
|
||||
debug { "configuration caches cleared" }
|
||||
|
||||
val keys = scriptDependenciesCache.getAll().map { it.key }.toList()
|
||||
|
||||
scriptDependenciesCache.clear()
|
||||
scriptsModificationStampsCache.clear()
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
private fun clearCaches() {
|
||||
fun clearClassRootsCaches() {
|
||||
debug { "class roots caches cleared" }
|
||||
|
||||
this::allSdks.clearValue()
|
||||
this::allNonIndexedSdks.clearValue()
|
||||
|
||||
@@ -180,6 +188,7 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
this::allDependenciesSourcesScope.clearValue()
|
||||
|
||||
scriptsDependenciesClasspathScopeCache.clear()
|
||||
scriptsSdksCache.clear()
|
||||
|
||||
val kotlinScriptDependenciesClassFinder =
|
||||
Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).extensions
|
||||
@@ -187,53 +196,36 @@ class ScriptsCompilationConfigurationCache(private val project: Project) {
|
||||
.single()
|
||||
|
||||
kotlinScriptDependenciesClassFinder.clearCache()
|
||||
}
|
||||
|
||||
private fun updateHighlighting(files: List<VirtualFile>) {
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
|
||||
GlobalScope.launch(EDT(project)) {
|
||||
files.filter { it.isValid }.forEach {
|
||||
PsiManager.getInstance(project).findFile(it)?.let { psiFile ->
|
||||
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasNotCachedRoots(compilationConfiguration: ScriptCompilationConfigurationWrapper): Boolean {
|
||||
val scriptSdk = getScriptSdk(compilationConfiguration) ?: ScriptDependenciesManager.getScriptDefaultSdk(project)
|
||||
return (scriptSdk != null && !allSdks.contains(scriptSdk)) ||
|
||||
!allDependenciesClassFiles.containsAll(ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesClassPath)) ||
|
||||
!allDependenciesSources.containsAll(ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesSources))
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
val keys = scriptDependenciesCache.getAll().map { it.key }.toList()
|
||||
|
||||
scriptDependenciesCache.clear()
|
||||
scriptsModificationStampsCache.clear()
|
||||
|
||||
updateHighlighting(keys)
|
||||
}
|
||||
|
||||
fun save(file: VirtualFile, new: ScriptCompilationConfigurationResult): Boolean {
|
||||
val old = scriptDependenciesCache.replace(file, new)
|
||||
val changed = new != old
|
||||
if (changed) {
|
||||
onChange(listOf(file))
|
||||
val wasSdkChanged = scriptSdk != null && !allSdks.contains(scriptSdk)
|
||||
if (wasSdkChanged) {
|
||||
debug { "sdk was changed: $compilationConfiguration" }
|
||||
return true
|
||||
}
|
||||
|
||||
return changed
|
||||
val newClassRoots = ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesClassPath)
|
||||
for (newClassRoot in newClassRoots) {
|
||||
if (!allDependenciesClassFiles.contains(newClassRoot)) {
|
||||
debug { "class root was changed: $newClassRoot" }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val newSourceRoots = ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesSources)
|
||||
for (newSourceRoot in newSourceRoots) {
|
||||
if (!allDependenciesSources.contains(newSourceRoot)) {
|
||||
debug { "source root was changed: $newSourceRoot" }
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun delete(file: VirtualFile): Boolean {
|
||||
val changed = scriptDependenciesCache.remove(file)
|
||||
if (changed) {
|
||||
onChange(listOf(file))
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R> KProperty0<R>.clearValue() {
|
||||
@@ -268,8 +260,8 @@ private class SLRUCacheWithLock<K, V> {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
|
||||
val cache = SLRUMap<K, V>(
|
||||
ScriptsCompilationConfigurationCache.MAX_SCRIPTS_CACHED,
|
||||
ScriptsCompilationConfigurationCache.MAX_SCRIPTS_CACHED
|
||||
MAX_SCRIPTS_CACHED,
|
||||
MAX_SCRIPTS_CACHED
|
||||
)
|
||||
|
||||
fun get(value: K): V? = lock.write {
|
||||
+1
-11
@@ -36,7 +36,6 @@ import com.intellij.openapi.projectRoots.ex.PathUtilEx
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.EditorNotifications
|
||||
import com.intellij.util.containers.SLRUMap
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
|
||||
@@ -191,13 +190,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
|
||||
scriptDefinitionsCacheLock.write { scriptDefinitionsCache.clear() }
|
||||
|
||||
// TODO: clear by script type/definition
|
||||
ServiceManager.getService(project, ScriptsCompilationConfigurationCache::class.java).clear()
|
||||
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
if (!project.isDisposed) {
|
||||
EditorNotifications.getInstance(project).updateAllNotifications()
|
||||
}
|
||||
}
|
||||
ScriptDependenciesManager.getInstance(project).clearConfigurationCachesAndRehighlight()
|
||||
}
|
||||
|
||||
private fun ScriptDefinitionsSource.safeGetDefinitions(): List<ScriptDefinition> {
|
||||
@@ -218,9 +211,6 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val LOG = Logger.getInstance("ScriptTemplatesProviders")
|
||||
|
||||
// TODO: consider rewriting to return sequence
|
||||
fun loadDefinitionsFromTemplates(
|
||||
templateClassNames: List<String>,
|
||||
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.util.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.getScriptOriginalFile
|
||||
import java.io.*
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
var KtFile.scriptDependencies: ScriptDependencies?
|
||||
get() = this.getScriptOriginalFile()?.virtualFile?.scriptDependencies
|
||||
set(value) {
|
||||
this.getScriptOriginalFile()?.virtualFile?.scriptDependencies = value
|
||||
}
|
||||
|
||||
var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute(
|
||||
name = "kotlin-script-dependencies",
|
||||
version = 3,
|
||||
read = {
|
||||
ScriptDependencies(
|
||||
classpath = readFileList(),
|
||||
imports = readStringList(),
|
||||
javaHome = readNullable(DataInput::readFile),
|
||||
scripts = readFileList(),
|
||||
sources = readFileList()
|
||||
)
|
||||
},
|
||||
write = {
|
||||
with(it) {
|
||||
writeFileList(classpath)
|
||||
writeStringList(imports)
|
||||
writeNullable(javaHome, DataOutput::writeFile)
|
||||
writeFileList(scripts)
|
||||
writeFileList(sources)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
var KtFile.scriptCompilationConfiguration: ScriptCompilationConfiguration?
|
||||
get() = this.getScriptOriginalFile()?.virtualFile?.scriptCompilationConfiguration
|
||||
set(value) {
|
||||
this.getScriptOriginalFile()?.virtualFile?.scriptCompilationConfiguration = value
|
||||
}
|
||||
|
||||
var VirtualFile.scriptCompilationConfiguration: ScriptCompilationConfiguration? by cachedFileAttribute(
|
||||
name = "kotlin-script-compilation-configuration",
|
||||
version = 1,
|
||||
read = {
|
||||
val size = readInt()
|
||||
val bytes = ByteArray(size)
|
||||
read(bytes, 0, size)
|
||||
val bis = ByteArrayInputStream(bytes)
|
||||
ObjectInputStream(bis).use { ois ->
|
||||
ois.readObject() as ScriptCompilationConfiguration
|
||||
}
|
||||
},
|
||||
write = {
|
||||
val os = ByteArrayOutputStream()
|
||||
ObjectOutputStream(os).use { oos ->
|
||||
oos.writeObject(it)
|
||||
}
|
||||
val bytes = os.toByteArray()
|
||||
writeInt(bytes.size)
|
||||
write(bytes)
|
||||
}
|
||||
)
|
||||
+66
-43
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.JavaSdkType
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
@@ -25,18 +24,17 @@ import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
import kotlin.script.experimental.api.makeFailureResult
|
||||
|
||||
// NOTE: this service exists exclusively because ScriptDependencyManager
|
||||
// cannot be registered as implementing two services (state would be duplicated)
|
||||
@@ -45,40 +43,73 @@ class IdeScriptDependenciesProvider(
|
||||
project: Project
|
||||
) : ScriptDependenciesProvider(project) {
|
||||
override fun getScriptConfigurationResult(file: KtFile): ScriptCompilationConfigurationResult? {
|
||||
return scriptDependenciesManager.getRefinedCompilationConfiguration(file)
|
||||
val configuration = getScriptConfiguration(file)
|
||||
val reports = IdeScriptReportSink.getReports(file)
|
||||
if (configuration == null && reports.isNotEmpty()) {
|
||||
return makeFailureResult(reports)
|
||||
}
|
||||
return configuration?.asSuccess(reports)
|
||||
}
|
||||
|
||||
override fun getScriptConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? {
|
||||
return scriptDependenciesManager.getConfiguration(file)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
|
||||
class ScriptDependenciesManager internal constructor(
|
||||
private val cacheUpdater: ScriptsCompilationConfigurationUpdater,
|
||||
private val cache: ScriptsCompilationConfigurationCache,
|
||||
private val project: Project
|
||||
) {
|
||||
/**
|
||||
* Facade for loading and caching Kotlin script files configuration.
|
||||
*
|
||||
* Loaded configuration will be cached in [memoryCache] and [fileAttributesCache].
|
||||
* This service also starts indexing of new dependency roots and runs highlighting
|
||||
* of opened files.
|
||||
*/
|
||||
interface ScriptConfigurationManager {
|
||||
/**
|
||||
* Save configurations into cache.
|
||||
* Start indexing for new class/source roots.
|
||||
* Re-highlight opened scripts with changed configuration.
|
||||
*/
|
||||
fun saveCompilationConfigurationAfterImport(files: List<Pair<VirtualFile, ScriptCompilationConfigurationResult>>)
|
||||
|
||||
/**
|
||||
* Start configuration update for files if configuration isn't up to date.
|
||||
* Start indexing for new class/source roots.
|
||||
*
|
||||
* @return true if update was started for any file, false if all configurations are cached
|
||||
*/
|
||||
fun updateConfigurationsIfNotCached(files: List<KtFile>): Boolean
|
||||
|
||||
/**
|
||||
* Check if configuration is already cached for [file] (in cache or FileAttributes).
|
||||
* Don't check if file was changed after the last update.
|
||||
* Supposed to be used to switch highlighting off for scripts without configuration.
|
||||
* to avoid all file being highlighted in red.
|
||||
*/
|
||||
fun isConfigurationCached(file: KtFile): Boolean
|
||||
|
||||
/**
|
||||
* Clear configuration caches
|
||||
* Start re-highlighting for opened scripts
|
||||
*/
|
||||
fun clearConfigurationCachesAndRehighlight()
|
||||
|
||||
@Deprecated("Use getScriptClasspath(KtFile) instead")
|
||||
fun getScriptClasspath(file: VirtualFile): List<VirtualFile> {
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return emptyList()
|
||||
return getScriptClasspath(ktFile)
|
||||
}
|
||||
fun getScriptClasspath(file: VirtualFile): List<VirtualFile>
|
||||
|
||||
fun getScriptClasspath(file: KtFile): List<VirtualFile> =
|
||||
toVfsRoots(cacheUpdater.getCurrentCompilationConfiguration(file)?.valueOrNull()?.dependenciesClassPath.orEmpty())
|
||||
|
||||
fun getRefinedCompilationConfiguration(file: KtFile): ScriptCompilationConfigurationResult? =
|
||||
cacheUpdater.getCurrentCompilationConfiguration(file)
|
||||
|
||||
fun getScriptDependenciesClassFilesScope(file: VirtualFile) = cache.scriptDependenciesClassFilesScope(file)
|
||||
fun getScriptSdk(file: VirtualFile) = cache.getScriptSdk(file)
|
||||
|
||||
fun getAllScriptsSdks() = cache.allSdks
|
||||
|
||||
fun getAllScriptsDependenciesClassFilesScope() = cache.allDependenciesClassFilesScope
|
||||
fun getAllScriptDependenciesSourcesScope() = cache.allDependenciesSourcesScope
|
||||
|
||||
fun getAllScriptsDependenciesClassFiles() = cache.allDependenciesClassFiles
|
||||
fun getAllScriptDependenciesSources() = cache.allDependenciesSources
|
||||
fun getScriptClasspath(file: KtFile): List<VirtualFile>
|
||||
fun getConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper?
|
||||
fun getScriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope
|
||||
fun getScriptSdk(file: VirtualFile): Sdk?
|
||||
fun getFirstScriptsSdk(): Sdk?
|
||||
fun getAllScriptsDependenciesClassFilesScope(): GlobalSearchScope
|
||||
fun getAllScriptDependenciesSourcesScope(): GlobalSearchScope
|
||||
fun getAllScriptsDependenciesClassFiles(): List<VirtualFile>
|
||||
fun getAllScriptDependenciesSources(): List<VirtualFile>
|
||||
}
|
||||
|
||||
@Deprecated("Use ScriptConfigurationManager instead")
|
||||
interface ScriptDependenciesManager : ScriptConfigurationManager {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ScriptDependenciesManager =
|
||||
@@ -93,7 +124,7 @@ class ScriptDependenciesManager internal constructor(
|
||||
return anyJavaSdk
|
||||
}
|
||||
|
||||
log.warn(
|
||||
LOG.warn(
|
||||
"Default Script SDK is null: " +
|
||||
"projectSdk = ${ProjectRootManager.getInstance(project).projectSdk}, " +
|
||||
"all sdks = ${getAllProjectSdks().joinToString("\n")}"
|
||||
@@ -118,17 +149,9 @@ class ScriptDependenciesManager internal constructor(
|
||||
return res
|
||||
}
|
||||
|
||||
internal val log = Logger.getInstance(ScriptDependenciesManager::class.java)
|
||||
|
||||
@TestOnly
|
||||
fun updateScriptDependenciesSynchronously(file: PsiFile, project: Project) {
|
||||
val loader = SyncScriptDependenciesLoader(project)
|
||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||
assert(file is KtFile) {
|
||||
"PsiFile should be a KtFile, otherwise script dependencies cannot be loaded"
|
||||
}
|
||||
loader.loadDependencies(file as KtFile, scriptDefinition)
|
||||
loader.notifyRootsChanged()
|
||||
(getInstance(project) as ScriptConfigurationManagerImpl).updateScriptDependenciesSynchronously(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -16,7 +16,7 @@ import com.intellij.ui.EditorNotificationPanel
|
||||
import com.intellij.ui.HyperlinkLabel
|
||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
|
||||
fun VirtualFile.removeScriptDependenciesNotificationPanel(project: Project) {
|
||||
withSelectedEditor(project) { manager ->
|
||||
@@ -28,9 +28,9 @@ fun VirtualFile.removeScriptDependenciesNotificationPanel(project: Project) {
|
||||
}
|
||||
|
||||
fun VirtualFile.addScriptDependenciesNotificationPanel(
|
||||
compilationConfigurationResult: ScriptCompilationConfigurationResult,
|
||||
compilationConfigurationResult: ScriptCompilationConfigurationWrapper,
|
||||
project: Project,
|
||||
onClick: (ScriptCompilationConfigurationResult) -> Unit
|
||||
onClick: (ScriptCompilationConfigurationWrapper) -> Unit
|
||||
) {
|
||||
withSelectedEditor(project) { manager ->
|
||||
val existingPanel = notificationPanel
|
||||
@@ -61,8 +61,8 @@ private fun VirtualFile.withSelectedEditor(project: Project, f: FileEditor.(File
|
||||
private var FileEditor.notificationPanel: NewScriptDependenciesNotificationPanel? by UserDataProperty<FileEditor, NewScriptDependenciesNotificationPanel>(Key.create("script.dependencies.panel"))
|
||||
|
||||
private class NewScriptDependenciesNotificationPanel(
|
||||
onClick: (ScriptCompilationConfigurationResult) -> Unit,
|
||||
val compilationConfigurationResult: ScriptCompilationConfigurationResult,
|
||||
onClick: (ScriptCompilationConfigurationWrapper) -> Unit,
|
||||
val compilationConfigurationResult: ScriptCompilationConfigurationWrapper,
|
||||
project: Project
|
||||
) : EditorNotificationPanel() {
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class ScriptTrafficLightRendererContributor : TrafficLightRendererContributor {
|
||||
if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) {
|
||||
status.reasonWhySuspended = "Loading kotlin script definitions"
|
||||
status.errorAnalyzingFinished = false
|
||||
} else if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) {
|
||||
} else if (!ScriptDependenciesManager.getInstance(project).isConfigurationCached(file)) {
|
||||
status.reasonWhySuspended = "Loading kotlin script dependencies"
|
||||
status.errorAnalyzingFinished = false
|
||||
}
|
||||
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.util.Alarm
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.AsyncScriptDependenciesLoader
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.FromFileAttributeScriptDependenciesLoader
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.OutsiderFileDependenciesLoader
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.isNonScript
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
|
||||
class ScriptsCompilationConfigurationUpdater(
|
||||
private val project: Project,
|
||||
private val cache: ScriptsCompilationConfigurationCache
|
||||
) {
|
||||
private val scriptsQueue = Alarm(Alarm.ThreadToUse.SWING_THREAD, project)
|
||||
private val scriptChangesListenerDelay = 1400
|
||||
|
||||
private val loaders = arrayListOf(
|
||||
FromFileAttributeScriptDependenciesLoader(project),
|
||||
OutsiderFileDependenciesLoader(project),
|
||||
AsyncScriptDependenciesLoader(project),
|
||||
SyncScriptDependenciesLoader(project)
|
||||
)
|
||||
|
||||
init {
|
||||
listenForChangesInScripts()
|
||||
}
|
||||
|
||||
fun getCurrentCompilationConfiguration(file: KtFile): ScriptCompilationConfigurationResult? {
|
||||
val virtualFile = file.originalFile.virtualFile
|
||||
|
||||
cache[virtualFile]?.let { return it }
|
||||
|
||||
// Try-catch block is a temporary workaround for ProcessCanceledException
|
||||
// that may happen during VirtualFile to PsiFile transformation
|
||||
try {
|
||||
updateDependencies(file)
|
||||
} finally {
|
||||
makeRootsChangeIfNeeded()
|
||||
}
|
||||
|
||||
return cache[virtualFile]
|
||||
}
|
||||
|
||||
fun updateDependenciesIfNeeded(files: List<KtFile>): Boolean {
|
||||
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return false
|
||||
|
||||
var wasDependenciesUpdateStarted = false
|
||||
for (file in files) {
|
||||
if (!areDependenciesCached(file)) {
|
||||
wasDependenciesUpdateStarted = true
|
||||
updateDependencies(file)
|
||||
}
|
||||
}
|
||||
|
||||
if (wasDependenciesUpdateStarted) {
|
||||
makeRootsChangeIfNeeded()
|
||||
}
|
||||
|
||||
return wasDependenciesUpdateStarted
|
||||
}
|
||||
|
||||
private fun updateDependencies(file: KtFile) {
|
||||
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return
|
||||
if (!cache.shouldRunDependenciesUpdate(file)) return
|
||||
|
||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||
loaders.filter { it.isApplicable(file, scriptDefinition) }.forEach { it.loadDependencies(file, scriptDefinition) }
|
||||
}
|
||||
|
||||
private fun makeRootsChangeIfNeeded() {
|
||||
loaders.firstOrNull {
|
||||
it.notifyRootsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun listenForChangesInScripts() {
|
||||
project.messageBus.connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener {
|
||||
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
|
||||
runScriptDependenciesUpdateIfNeeded(file)
|
||||
}
|
||||
|
||||
override fun selectionChanged(event: FileEditorManagerEvent) {
|
||||
event.newFile?.let { runScriptDependenciesUpdateIfNeeded(it) }
|
||||
}
|
||||
|
||||
private fun runScriptDependenciesUpdateIfNeeded(file: VirtualFile) {
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
updateDependencies(ktFile)
|
||||
makeRootsChangeIfNeeded()
|
||||
}
|
||||
})
|
||||
|
||||
EditorFactory.getInstance().eventMulticaster.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
val document = event.document
|
||||
val file = FileDocumentManager.getInstance().getFile(document)?.takeIf { it.isInLocalFileSystem } ?: return
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
// only update dependencies for scripts that were touched recently
|
||||
if (cache[file] == null) {
|
||||
return
|
||||
}
|
||||
|
||||
scriptsQueue.cancelAllRequests()
|
||||
|
||||
scriptsQueue.addRequest(
|
||||
{
|
||||
FileDocumentManager.getInstance().saveDocument(document)
|
||||
updateDependencies(ktFile)
|
||||
makeRootsChangeIfNeeded()
|
||||
},
|
||||
scriptChangesListenerDelay,
|
||||
true
|
||||
)
|
||||
}
|
||||
}, project.messageBus.connect())
|
||||
}
|
||||
|
||||
private fun getKtFileToStartConfigurationUpdate(file: VirtualFile): KtFile? {
|
||||
if (project.isDisposed || !file.isValid || file.isNonScript()) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (
|
||||
ApplicationManager.getApplication().isUnitTestMode &&
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled == true
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return null
|
||||
if (ProjectRootsUtil.isInProjectSource(ktFile, includeScriptsOutsideSourceRoots = true)) {
|
||||
return ktFile
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun areDependenciesCached(file: VirtualFile): Boolean {
|
||||
return cache[file] != null || file.scriptDependencies != null || file.scriptCompilationConfiguration != null
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ScriptsCompilationConfigurationUpdater =
|
||||
ServiceManager.getService(project, ScriptsCompilationConfigurationUpdater::class.java)
|
||||
|
||||
fun areDependenciesCached(file: KtFile): Boolean {
|
||||
return getInstance(file.project).areDependenciesCached(file.virtualFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@set: TestOnly
|
||||
var Application.isScriptDependenciesUpdaterDisabled by NotNullableUserDataProperty(
|
||||
Key.create("SCRIPT_DEPENDENCIES_UPDATER_DISABLED"),
|
||||
false
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.util.Alarm
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.isNonScript
|
||||
|
||||
class ScriptsListener(
|
||||
private val project: Project,
|
||||
private val scriptsManager: ScriptConfigurationManagerImpl
|
||||
) {
|
||||
private val scriptsQueue = Alarm(Alarm.ThreadToUse.SWING_THREAD, project)
|
||||
private val scriptChangesListenerDelay = 1400
|
||||
|
||||
init {
|
||||
listenForChangesInScripts()
|
||||
}
|
||||
|
||||
private fun listenForChangesInScripts() {
|
||||
project.messageBus.connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener {
|
||||
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
|
||||
runScriptDependenciesUpdateIfNeeded(file)
|
||||
}
|
||||
|
||||
override fun selectionChanged(event: FileEditorManagerEvent) {
|
||||
event.newFile?.let { runScriptDependenciesUpdateIfNeeded(it) }
|
||||
}
|
||||
|
||||
private fun runScriptDependenciesUpdateIfNeeded(file: VirtualFile) {
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
scriptsManager.updateConfigurationsIfNotCached(listOf(ktFile))
|
||||
}
|
||||
})
|
||||
|
||||
EditorFactory.getInstance().eventMulticaster.addDocumentListener(object : DocumentListener {
|
||||
override fun documentChanged(event: DocumentEvent) {
|
||||
val document = event.document
|
||||
val file = FileDocumentManager.getInstance().getFile(document)?.takeIf { it.isInLocalFileSystem } ?: return
|
||||
val ktFile = getKtFileToStartConfigurationUpdate(file) ?: return
|
||||
|
||||
scriptsQueue.cancelAllRequests()
|
||||
|
||||
scriptsQueue.addRequest(
|
||||
{ scriptsManager.updateConfigurationsIfNotCached(listOf(ktFile)) },
|
||||
scriptChangesListenerDelay,
|
||||
true
|
||||
)
|
||||
}
|
||||
}, project.messageBus.connect())
|
||||
}
|
||||
|
||||
private fun getKtFileToStartConfigurationUpdate(file: VirtualFile): KtFile? {
|
||||
if (project.isDisposed || !file.isValid || file.isNonScript()) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (
|
||||
ApplicationManager.getApplication().isUnitTestMode &&
|
||||
ApplicationManager.getApplication().isScriptDependenciesUpdaterDisabled == true
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return null
|
||||
if (ProjectRootsUtil.isInProjectSource(ktFile, includeScriptsOutsideSourceRoots = true)) {
|
||||
return ktFile
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.coroutines.Runnable
|
||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||
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.KtFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
|
||||
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
|
||||
class AsyncScriptDependenciesLoader internal constructor(project: Project) : ScriptDependenciesLoader(project) {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
|
||||
private var notifyRootChange: Boolean = false
|
||||
private var backgroundTasksQueue: LoaderBackgroundTask? = null
|
||||
|
||||
override fun isApplicable(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): Boolean {
|
||||
return isAsyncDependencyResolver(scriptDefinition)
|
||||
}
|
||||
|
||||
override fun loadDependencies(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
) {
|
||||
lock.write {
|
||||
if (backgroundTasksQueue == null) {
|
||||
backgroundTasksQueue = LoaderBackgroundTask()
|
||||
backgroundTasksQueue!!.addTask(file)
|
||||
backgroundTasksQueue!!.start()
|
||||
} else {
|
||||
backgroundTasksQueue!!.addTask(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldShowNotification(): Boolean = !KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled
|
||||
|
||||
override fun notifyRootsChanged(): Boolean {
|
||||
lock.write {
|
||||
if (notifyRootChange) return false
|
||||
|
||||
if (backgroundTasksQueue == null) {
|
||||
return submitMakeRootsChange()
|
||||
}
|
||||
|
||||
notifyRootChange = true
|
||||
|
||||
backgroundTasksQueue!!.addOnFinishTask {
|
||||
lock.write {
|
||||
notifyRootChange = false
|
||||
}
|
||||
submitMakeRootsChange()
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun runDependenciesUpdate(file: KtFile) {
|
||||
val scriptDef = file.findScriptDefinition() ?: return
|
||||
|
||||
debug(file) { "start async dependencies loading" }
|
||||
|
||||
val result = refineScriptCompilationConfiguration(KtFileScriptSource(file), scriptDef, project)
|
||||
|
||||
debug(file) { "finish async dependencies loading" }
|
||||
|
||||
processRefinedConfiguration(result, file.originalFile.virtualFile)
|
||||
}
|
||||
|
||||
private inner class LoaderBackgroundTask {
|
||||
private val sequenceOfFiles: ConcurrentLinkedQueue<KtFile> = ConcurrentLinkedQueue()
|
||||
private var forceStop : Boolean = false
|
||||
private var startedSilently : Boolean = false
|
||||
|
||||
private var onFinish: (() -> Unit)? = null
|
||||
|
||||
fun start() {
|
||||
if (shouldShowNotification()) {
|
||||
startSilently()
|
||||
} else {
|
||||
startWithProgress()
|
||||
}
|
||||
}
|
||||
|
||||
private fun restartWithProgress() {
|
||||
forceStop = true
|
||||
startWithProgress()
|
||||
forceStop = false
|
||||
}
|
||||
|
||||
private fun startSilently() {
|
||||
startedSilently = true
|
||||
BackgroundTaskUtil.executeOnPooledThread(project, Runnable {
|
||||
loadDependencies(EmptyProgressIndicator())
|
||||
})
|
||||
}
|
||||
|
||||
private fun startWithProgress() {
|
||||
startedSilently = false
|
||||
object : Task.Backgroundable(project, "Kotlin: Loading script dependencies...", true) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
loadDependencies(indicator)
|
||||
}
|
||||
|
||||
}.queue()
|
||||
}
|
||||
|
||||
fun addTask(file: KtFile) {
|
||||
if (sequenceOfFiles.contains(file)) return
|
||||
|
||||
debug(file) { "added to update queue" }
|
||||
|
||||
sequenceOfFiles.add(file)
|
||||
|
||||
// If the queue is longer than 3, show progress and cancel button
|
||||
if (sequenceOfFiles.size > 3 && startedSilently) {
|
||||
restartWithProgress()
|
||||
}
|
||||
}
|
||||
|
||||
fun addOnFinishTask(task: () -> Unit) {
|
||||
onFinish = task
|
||||
}
|
||||
|
||||
private fun loadDependencies(indicator: ProgressIndicator?) {
|
||||
while (true) {
|
||||
if (forceStop) return
|
||||
if (indicator?.isCanceled == true || sequenceOfFiles.isEmpty()) {
|
||||
lock.write {
|
||||
onFinish?.invoke()
|
||||
backgroundTasksQueue = null
|
||||
}
|
||||
return
|
||||
}
|
||||
runDependenciesUpdate(sequenceOfFiles.poll())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptClassRootsManager
|
||||
import org.jetbrains.kotlin.idea.core.script.debug
|
||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
internal class BackgroundLoader(
|
||||
private val project: Project,
|
||||
private val rootsManager: ScriptClassRootsManager,
|
||||
private val loadDependencies: (KtFile) -> Unit
|
||||
) {
|
||||
private var task: Task? = null
|
||||
|
||||
@Synchronized
|
||||
fun scheduleAsync(file: KtFile) {
|
||||
if (task == null) {
|
||||
startBatch(file)
|
||||
} else {
|
||||
task!!.addTask(file)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun startBatch(file: KtFile) {
|
||||
rootsManager.startTransaction()
|
||||
task = Task()
|
||||
task!!.addTask(file)
|
||||
task!!.start()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun endBatch() {
|
||||
task = null
|
||||
rootsManager.commit()
|
||||
}
|
||||
|
||||
private inner class Task {
|
||||
private val sequenceOfFiles: ConcurrentLinkedQueue<KtFile> = ConcurrentLinkedQueue()
|
||||
private var forceStop: Boolean = false
|
||||
private var startedSilently: Boolean = false
|
||||
|
||||
fun start() {
|
||||
if (KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled) {
|
||||
startWithProgress()
|
||||
} else {
|
||||
startSilently()
|
||||
}
|
||||
}
|
||||
|
||||
private fun restartWithProgress() {
|
||||
forceStop = true
|
||||
startWithProgress()
|
||||
forceStop = false
|
||||
}
|
||||
|
||||
private fun startSilently() {
|
||||
startedSilently = true
|
||||
BackgroundTaskUtil.executeOnPooledThread(project, Runnable {
|
||||
loadDependencies(EmptyProgressIndicator())
|
||||
})
|
||||
}
|
||||
|
||||
private fun startWithProgress() {
|
||||
startedSilently = false
|
||||
object : com.intellij.openapi.progress.Task.Backgroundable(project, "Kotlin: Loading script dependencies...", true) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
loadDependencies(indicator)
|
||||
}
|
||||
}.queue()
|
||||
}
|
||||
|
||||
fun addTask(file: KtFile) {
|
||||
if (file in sequenceOfFiles) return
|
||||
|
||||
debug(file) { "added to update queue" }
|
||||
|
||||
sequenceOfFiles.add(file)
|
||||
|
||||
// If the queue is longer than 3, show progress and cancel button
|
||||
if (sequenceOfFiles.size > 3 && startedSilently) {
|
||||
restartWithProgress()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadDependencies(indicator: ProgressIndicator?) {
|
||||
while (true) {
|
||||
if (forceStop) return
|
||||
if (indicator?.isCanceled == true || sequenceOfFiles.isEmpty()) {
|
||||
endBatch()
|
||||
return
|
||||
}
|
||||
|
||||
loadDependencies(sequenceOfFiles.poll())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.script.scriptCompilationConfiguration
|
||||
import org.jetbrains.kotlin.idea.core.script.scriptDependencies
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
|
||||
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
|
||||
class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
|
||||
|
||||
override fun isApplicable(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): Boolean {
|
||||
return file.scriptDependencies != null || file.scriptCompilationConfiguration != null
|
||||
}
|
||||
|
||||
override fun loadDependencies(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
) {
|
||||
val virtualFile = file.originalFile.virtualFile
|
||||
virtualFile.scriptCompilationConfiguration?.let {
|
||||
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(KtFileScriptSource(file), it).apply {
|
||||
debug(virtualFile) { "refined configuration from fileAttributes = $it" }
|
||||
}
|
||||
} ?: virtualFile.scriptDependencies?.let {
|
||||
ScriptCompilationConfigurationWrapper.FromLegacy(KtFileScriptSource(file), it, scriptDefinition).apply {
|
||||
debug(virtualFile) { "dependencies from fileAttributes = $it" }
|
||||
}
|
||||
}?.let {
|
||||
if (areDependenciesValid(virtualFile, it)) {
|
||||
saveToCache(virtualFile, it.asSuccess(), skipSaveToAttributes = true)
|
||||
} else {
|
||||
virtualFile.scriptCompilationConfiguration = null
|
||||
virtualFile.scriptDependencies = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldShowNotification(): Boolean = false
|
||||
|
||||
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfigurationWrapper.FromLegacy): Boolean {
|
||||
return configuration.dependenciesClassPath.all {
|
||||
if (it.exists()) {
|
||||
true
|
||||
} else {
|
||||
debug(file) {
|
||||
"classpath root saved to file attribute doesn't exist: ${it.path}"
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import org.jetbrains.kotlin.idea.core.script.debug
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.LegacyResolverWrapper
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
|
||||
class FromRefinedConfigurationLoader internal constructor() : ScriptDependenciesLoader {
|
||||
override fun isAsync(file: KtFile, scriptDefinition: ScriptDefinition): Boolean {
|
||||
return scriptDefinition.asLegacyOrNull<KotlinScriptDefinition>()?.dependencyResolver?.let {
|
||||
it is AsyncDependenciesResolver || it is LegacyResolverWrapper
|
||||
} ?: false
|
||||
}
|
||||
|
||||
override fun loadDependencies(
|
||||
firstLoad: Boolean,
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): ScriptCompilationConfigurationResult? {
|
||||
debug(file) { "start dependencies loading" }
|
||||
|
||||
val result = refineScriptCompilationConfiguration(KtFileScriptSource(file), scriptDefinition, file.project)
|
||||
|
||||
debug(file) { "finish dependencies loading" }
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-20
@@ -5,34 +5,31 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManagerImpl
|
||||
import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils
|
||||
import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportWrapper
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
|
||||
class OutsiderFileDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
|
||||
override fun isApplicable(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): Boolean {
|
||||
val virtualFile = file.virtualFile ?: return false
|
||||
return OutsidersPsiFileSupportWrapper.isOutsiderFile(virtualFile)
|
||||
}
|
||||
class OutsiderFileDependenciesLoader(private val manager: ScriptConfigurationManagerImpl) : ScriptDependenciesLoader {
|
||||
override val skipSaveToAttributes: Boolean
|
||||
get() = true
|
||||
|
||||
override val skipNotification: Boolean
|
||||
get() = true
|
||||
|
||||
override fun loadDependencies(
|
||||
firstLoad: Boolean,
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
) {
|
||||
val virtualFile = file.virtualFile ?: return
|
||||
val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, virtualFile) ?: return
|
||||
val psiFileOrigin = PsiManager.getInstance(project).findFile(fileOrigin) as? KtFile ?: return
|
||||
val compilationConfiguration =
|
||||
ScriptDependenciesManager.getInstance(project).getRefinedCompilationConfiguration(psiFileOrigin) ?: return
|
||||
saveToCache(virtualFile, compilationConfiguration)
|
||||
}
|
||||
): ScriptCompilationConfigurationResult? {
|
||||
val virtualFile = file.virtualFile ?: return null
|
||||
val project = file.project
|
||||
|
||||
override fun shouldShowNotification(): Boolean = false
|
||||
val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, virtualFile) ?: return null
|
||||
val psiFileOrigin = PsiManager.getInstance(project).findFile(fileOrigin) as? KtFile ?: return null
|
||||
return manager.getConfiguration(psiFileOrigin)?.asSuccess()
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.script.debug
|
||||
import org.jetbrains.kotlin.idea.core.util.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper.FromCompilationConfiguration
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper.FromLegacy
|
||||
import java.io.*
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
class ScriptConfigurationFileAttributeCache : ScriptDependenciesLoader {
|
||||
operator fun contains(file: VirtualFile): Boolean =
|
||||
file.scriptDependencies != null || file.scriptCompilationConfiguration != null
|
||||
|
||||
override val skipSaveToAttributes: Boolean
|
||||
get() = true
|
||||
|
||||
override val skipNotification: Boolean
|
||||
get() = true
|
||||
|
||||
override fun loadDependencies(
|
||||
firstLoad: Boolean,
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): ScriptCompilationConfigurationResult? {
|
||||
if (!firstLoad) return null
|
||||
|
||||
val virtualFile = file.originalFile.virtualFile
|
||||
|
||||
val configurationFromAttributes =
|
||||
virtualFile.scriptCompilationConfiguration?.let {
|
||||
FromCompilationConfiguration(KtFileScriptSource(file), it)
|
||||
} ?: virtualFile.scriptDependencies?.let {
|
||||
FromLegacy(KtFileScriptSource(file), it, scriptDefinition)
|
||||
} ?: return null
|
||||
|
||||
|
||||
debug(virtualFile) { "configuration from fileAttributes = $configurationFromAttributes" }
|
||||
|
||||
if (!areDependenciesValid(virtualFile, configurationFromAttributes)) {
|
||||
save(virtualFile, null)
|
||||
return null
|
||||
}
|
||||
|
||||
return configurationFromAttributes.asSuccess()
|
||||
}
|
||||
|
||||
private fun areDependenciesValid(file: VirtualFile, configuration: ScriptCompilationConfigurationWrapper): Boolean {
|
||||
return configuration.dependenciesClassPath.all {
|
||||
if (it.exists()) {
|
||||
true
|
||||
} else {
|
||||
debug(file) {
|
||||
"classpath root saved to file attribute doesn't exist: ${it.path}"
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun save(file: VirtualFile, value: ScriptCompilationConfigurationWrapper?) {
|
||||
if (value == null) {
|
||||
file.scriptDependencies = null
|
||||
file.scriptCompilationConfiguration = null
|
||||
} else {
|
||||
if (value is ScriptCompilationConfigurationWrapper.FromLegacy) {
|
||||
file.scriptDependencies = value.legacyDependencies
|
||||
} else {
|
||||
if (file.scriptDependencies != null) file.scriptDependencies = null
|
||||
file.scriptCompilationConfiguration = value.configuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute(
|
||||
name = "kotlin-script-dependencies",
|
||||
version = 3,
|
||||
read = {
|
||||
ScriptDependencies(
|
||||
classpath = readFileList(),
|
||||
imports = readStringList(),
|
||||
javaHome = readNullable(DataInput::readFile),
|
||||
scripts = readFileList(),
|
||||
sources = readFileList()
|
||||
)
|
||||
},
|
||||
write = {
|
||||
with(it) {
|
||||
writeFileList(classpath)
|
||||
writeStringList(imports)
|
||||
writeNullable(javaHome, DataOutput::writeFile)
|
||||
writeFileList(scripts)
|
||||
writeFileList(sources)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private var VirtualFile.scriptCompilationConfiguration: ScriptCompilationConfiguration? by cachedFileAttribute(
|
||||
name = "kotlin-script-compilation-configuration",
|
||||
version = 1,
|
||||
read = {
|
||||
val size = readInt()
|
||||
val bytes = ByteArray(size)
|
||||
read(bytes, 0, size)
|
||||
val bis = ByteArrayInputStream(bytes)
|
||||
ObjectInputStream(bis).use { ois ->
|
||||
ois.readObject() as ScriptCompilationConfiguration
|
||||
}
|
||||
},
|
||||
write = {
|
||||
val os = ByteArrayOutputStream()
|
||||
ObjectOutputStream(os).use { oos ->
|
||||
oos.writeObject(it)
|
||||
}
|
||||
val bytes = os.toByteArray()
|
||||
writeInt(bytes.size)
|
||||
write(bytes)
|
||||
}
|
||||
)
|
||||
|
||||
+13
-150
@@ -5,160 +5,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.TransactionGuard
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.util.EmptyRunnable
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.core.script.*
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.LegacyResolverWrapper
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
|
||||
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
|
||||
abstract class ScriptDependenciesLoader(protected val project: Project) {
|
||||
// TODO: rename - this is not only about dependencies anymore
|
||||
internal interface ScriptDependenciesLoader {
|
||||
fun isAsync(file: KtFile, scriptDefinition: ScriptDefinition) = false
|
||||
|
||||
abstract fun isApplicable(file: KtFile, scriptDefinition: ScriptDefinition): Boolean
|
||||
abstract fun loadDependencies(file: KtFile, scriptDefinition: ScriptDefinition)
|
||||
val skipSaveToAttributes: Boolean
|
||||
get() = false
|
||||
|
||||
protected abstract fun shouldShowNotification(): Boolean
|
||||
val skipNotification: Boolean
|
||||
get() = false
|
||||
|
||||
protected var shouldNotifyRootsChanged = false
|
||||
|
||||
protected val cache: ScriptsCompilationConfigurationCache = ServiceManager.getService(project, ScriptsCompilationConfigurationCache::class.java)
|
||||
|
||||
private val reporter: ScriptReportSink = ServiceManager.getService(project, ScriptReportSink::class.java)
|
||||
|
||||
protected fun processRefinedConfiguration(result: ScriptCompilationConfigurationResult, file: VirtualFile) {
|
||||
debug(file) { "refined script compilation configuration from ${this.javaClass} received = $result" }
|
||||
|
||||
val oldResult = cache[file]
|
||||
|
||||
if (oldResult == null) {
|
||||
save(result, file)
|
||||
attachReportsIfChanged(result, file)
|
||||
return
|
||||
}
|
||||
|
||||
if (oldResult != result) {
|
||||
if (shouldShowNotification()
|
||||
&& oldResult.valueOrNull() != result.valueOrNull() // Only compilation configuration changed
|
||||
&& !ApplicationManager.getApplication().isUnitTestMode
|
||||
) {
|
||||
debug(file) {
|
||||
"dependencies changed, notification is shown: old = $oldResult, new = $result"
|
||||
}
|
||||
file.addScriptDependenciesNotificationPanel(result, project) {
|
||||
save(it, file)
|
||||
attachReportsIfChanged(result, file)
|
||||
submitMakeRootsChange()
|
||||
}
|
||||
} else {
|
||||
debug(file) {
|
||||
"dependencies changed, new dependencies are applied automatically: old = $oldResult, new = $result"
|
||||
}
|
||||
save(result, file)
|
||||
attachReportsIfChanged(result, file)
|
||||
}
|
||||
} else {
|
||||
attachReportsIfChanged(result, file)
|
||||
|
||||
if (shouldShowNotification()) {
|
||||
file.removeScriptDependenciesNotificationPanel(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachReportsIfChanged(result: ResultWithDiagnostics<*>, file: VirtualFile) {
|
||||
reporter.attachReports(file, result.reports)
|
||||
}
|
||||
|
||||
private fun save(compilationConfigurationResult: ScriptCompilationConfigurationResult?, file: VirtualFile) {
|
||||
if (shouldShowNotification()) {
|
||||
file.removeScriptDependenciesNotificationPanel(project)
|
||||
}
|
||||
if (compilationConfigurationResult != null) {
|
||||
saveToCache(file, compilationConfigurationResult)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun saveToCache(
|
||||
file: VirtualFile, compilationConfigurationResult: ScriptCompilationConfigurationResult, skipSaveToAttributes: Boolean = false
|
||||
) {
|
||||
val rootsChanged = compilationConfigurationResult.valueOrNull()?.let { cache.hasNotCachedRoots(it) } ?: false
|
||||
if (cache.save(file, compilationConfigurationResult)
|
||||
&& !skipSaveToAttributes
|
||||
&& compilationConfigurationResult is ResultWithDiagnostics.Success
|
||||
) {
|
||||
debug(file) {
|
||||
"refined configuration is saved to file attributes: $compilationConfigurationResult"
|
||||
}
|
||||
if (compilationConfigurationResult.value is ScriptCompilationConfigurationWrapper.FromLegacy)
|
||||
file.scriptDependencies = compilationConfigurationResult.value.legacyDependencies
|
||||
else
|
||||
file.scriptCompilationConfiguration = compilationConfigurationResult.value.configuration
|
||||
}
|
||||
|
||||
if (rootsChanged) {
|
||||
shouldNotifyRootsChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open fun notifyRootsChanged(): Boolean = submitMakeRootsChange()
|
||||
|
||||
protected fun submitMakeRootsChange(): Boolean {
|
||||
if (!shouldNotifyRootsChanged) return false
|
||||
|
||||
val doNotifyRootsChanged = Runnable {
|
||||
runWriteAction {
|
||||
if (project.isDisposed) return@runWriteAction
|
||||
|
||||
debug(null) { "root change event for ${this.javaClass}" }
|
||||
|
||||
shouldNotifyRootsChanged = false
|
||||
ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true)
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
TransactionGuard.submitTransaction(project, doNotifyRootsChanged)
|
||||
} else {
|
||||
TransactionGuard.getInstance().submitTransactionLater(project, doNotifyRootsChanged)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun isAsyncDependencyResolver(scriptDef: ScriptDefinition): Boolean =
|
||||
scriptDef.asLegacyOrNull<KotlinScriptDefinition>()?.dependencyResolver?.let {
|
||||
it is AsyncDependenciesResolver || it is LegacyResolverWrapper
|
||||
} ?: false
|
||||
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.script")
|
||||
|
||||
internal fun debug(file: VirtualFile? = null, message: () -> String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("[KOTLIN SCRIPT] ${file?.path} " + message())
|
||||
}
|
||||
}
|
||||
|
||||
internal fun debug(file: KtFile, message: () -> String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("[KOTLIN SCRIPT] ${file.originalFile.virtualFile?.path} " + message())
|
||||
}
|
||||
}
|
||||
fun loadDependencies(
|
||||
firstLoad: Boolean,
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): ScriptCompilationConfigurationResult?
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
|
||||
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
|
||||
|
||||
class SyncScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
|
||||
override fun isApplicable(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
): Boolean {
|
||||
return !isAsyncDependencyResolver(scriptDefinition)
|
||||
}
|
||||
|
||||
override fun loadDependencies(
|
||||
file: KtFile,
|
||||
scriptDefinition: ScriptDefinition
|
||||
) {
|
||||
debug(file) { "start sync dependencies loading" }
|
||||
val result = refineScriptCompilationConfiguration(KtFileScriptSource(file), scriptDefinition, project)
|
||||
debug(file) { "finish sync dependencies loading" }
|
||||
processRefinedConfiguration(result, file.originalFile.virtualFile)
|
||||
}
|
||||
|
||||
override fun shouldShowNotification(): Boolean = false
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
|
||||
@set: org.jetbrains.annotations.TestOnly
|
||||
var Application.isScriptDependenciesUpdaterDisabled by NotNullableUserDataProperty(
|
||||
Key.create("SCRIPT_DEPENDENCIES_UPDATER_DISABLED"),
|
||||
false
|
||||
)
|
||||
|
||||
internal val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.script")
|
||||
|
||||
internal fun debug(file: KtFile, message: () -> String) {
|
||||
debug(file.originalFile.virtualFile, message)
|
||||
}
|
||||
|
||||
internal fun debug(file: VirtualFile? = null, message: () -> String) {
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("[KOTLIN SCRIPT] ${file?.let { file.path + " "} ?: ""}" + message())
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.idea.util.JavaParametersBuilder
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
class KtScratchExecutionSession(
|
||||
private val file: ScratchFile,
|
||||
@@ -166,7 +165,7 @@ class KtScratchExecutionSession(
|
||||
}
|
||||
|
||||
ScriptDependenciesManager.getInstance(originalFile.project)
|
||||
.getRefinedCompilationConfiguration(originalFile)?.valueOrNull()?.let {
|
||||
.getConfiguration(originalFile)?.let {
|
||||
javaParameters.classPath.addAll(it.dependenciesClassPath.map { f -> f.absolutePath })
|
||||
}
|
||||
|
||||
|
||||
@@ -297,13 +297,7 @@
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.IdeScriptDependenciesProvider"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationCache"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationCache"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater"/>
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManagerImpl"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.scripting.resolve.ScriptReportSink"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink"/>
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
|
||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
||||
@@ -136,7 +136,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
|
||||
|
||||
val usedScripts = findScriptsWithUsages(declaration)
|
||||
if (usedScripts.isNotEmpty()) {
|
||||
if (ScriptsCompilationConfigurationUpdater.getInstance(declaration.project).updateDependenciesIfNeeded(usedScripts)) {
|
||||
if (ScriptDependenciesManager.getInstance(declaration.project).updateConfigurationsIfNotCached(usedScripts)) {
|
||||
return TOO_MANY_OCCURRENCES
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() {
|
||||
|
||||
@@ -66,8 +65,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
|
||||
|
||||
val scriptExtraImports = contextFile.takeIf { it.isScript() }?.let { ktFile ->
|
||||
val scriptDependencies = ScriptDependenciesProvider.getInstance(ktFile.project)
|
||||
?.getScriptConfigurationResult(ktFile.originalFile as KtFile)
|
||||
?.valueOrNull()
|
||||
?.getScriptConfiguration(ktFile.originalFile as KtFile)
|
||||
scriptDependencies?.defaultImports?.map { ImportPath.fromString(it) }
|
||||
}.orEmpty()
|
||||
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdaterKt;
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptUtilsKt;
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
@@ -42,12 +42,12 @@ public abstract class AbstractConfigureProjectByChangingFileTest<C extends Kotli
|
||||
ApplicationManager.getApplication().runWriteAction(
|
||||
() -> FileTypeManager.getInstance().associateExtension(GroovyFileType.GROOVY_FILE_TYPE, "gradle")
|
||||
);
|
||||
ScriptsCompilationConfigurationUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), true);
|
||||
ScriptUtilsKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
ScriptsCompilationConfigurationUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), false);
|
||||
ScriptUtilsKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), false);
|
||||
moduleInfoFile = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
+5
-2
@@ -12,6 +12,7 @@ import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
|
||||
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
@@ -22,17 +23,19 @@ open class ScriptDependenciesProvider constructor(
|
||||
@Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR)
|
||||
fun getScriptDependencies(file: VirtualFile): ScriptDependencies? {
|
||||
val ktFile = PsiManager.getInstance(project).findFile(file) as? KtFile ?: return null
|
||||
return getScriptConfigurationResult(ktFile)?.valueOrNull()?.legacyDependencies
|
||||
return getScriptConfiguration(ktFile)?.legacyDependencies
|
||||
}
|
||||
|
||||
@Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR)
|
||||
fun getScriptDependencies(file: PsiFile): ScriptDependencies? {
|
||||
if (file !is KtFile) return null
|
||||
return getScriptConfigurationResult(file)?.valueOrNull()?.legacyDependencies
|
||||
return getScriptConfiguration(file)?.legacyDependencies
|
||||
}
|
||||
|
||||
open fun getScriptConfigurationResult(file: KtFile): ScriptCompilationConfigurationResult? = null
|
||||
|
||||
open fun getScriptConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? = getScriptConfigurationResult(file)?.valueOrNull()
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): ScriptDependenciesProvider? =
|
||||
ServiceManager.getService(project, ScriptDependenciesProvider::class.java)
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResu
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
import kotlin.script.experimental.api.valueOr
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
fun PsiFile.findScriptCompilationConfiguration(): ScriptCompilationConfiguration? {
|
||||
// Do not use psiFile.script, see comments in findScriptDefinition
|
||||
@@ -21,7 +20,7 @@ fun PsiFile.findScriptCompilationConfiguration(): ScriptCompilationConfiguration
|
||||
|
||||
val provider = ScriptDependenciesProvider.getInstance(project)
|
||||
// Ignoring the error here, assuming that it will be reported elsewhere anyway (this is important scenario in IDE)
|
||||
return provider?.getScriptConfigurationResult(this)?.valueOrNull()?.configuration
|
||||
return provider?.getScriptConfiguration(this)?.configuration
|
||||
?: findScriptDefinition()?.compilationConfiguration
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.psi.KtImportInfo
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
class ScriptExtraImportsProviderExtension : ExtraImportsProviderExtension {
|
||||
|
||||
@@ -30,8 +29,7 @@ class ScriptExtraImportsProviderExtension : ExtraImportsProviderExtension {
|
||||
override fun getExtraImports(ktFile: KtFile): Collection<KtImportInfo> =
|
||||
ktFile.takeIf { it.isScript() }?.let { file ->
|
||||
val refinedConfiguration = ScriptDependenciesProvider.getInstance(file.project)
|
||||
?.getScriptConfigurationResult(file.originalFile as KtFile)
|
||||
?.valueOrNull()
|
||||
?.getScriptConfiguration(file.originalFile as KtFile)
|
||||
refinedConfiguration?.defaultImports?.map {
|
||||
ScriptExtraImportImpl(
|
||||
ImportPath.fromString(it)
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ class LazyScriptDescriptor(
|
||||
val res = ArrayList<ClassDescriptor>()
|
||||
|
||||
val importedScriptsFiles = ScriptDependenciesProvider.getInstance(scriptInfo.script.project)
|
||||
?.getScriptConfigurationResult(scriptInfo.script.containingKtFile)?.valueOrNull()?.importedScripts
|
||||
?.getScriptConfiguration(scriptInfo.script.containingKtFile)?.importedScripts
|
||||
if (importedScriptsFiles != null) {
|
||||
val findImportedScriptDescriptor = ImportedScriptDescriptorsFinder()
|
||||
importedScriptsFiles.mapNotNullTo(res) {
|
||||
|
||||
+1
-2
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
data class ScriptsCompilationDependencies(
|
||||
val classpath: List<File>,
|
||||
@@ -42,7 +41,7 @@ fun collectScriptsCompilationDependencies(
|
||||
while (true) {
|
||||
val newRemainingSources = ArrayList<KtFile>()
|
||||
for (source in remainingSources) {
|
||||
val refinedConfiguration = importsProvider.getScriptConfigurationResult(source)?.valueOrNull()
|
||||
val refinedConfiguration = importsProvider.getScriptConfiguration(source)
|
||||
if (refinedConfiguration != null) {
|
||||
collectedClassPath.addAll(refinedConfiguration.dependenciesClassPath)
|
||||
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
||||
sourceFiles.first(),
|
||||
sourceDependencies
|
||||
) { ktFile ->
|
||||
dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration
|
||||
dependenciesProvider?.getScriptConfiguration(ktFile)?.configuration
|
||||
?: context.baseScriptCompilationConfiguration
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ private fun compileImpl(
|
||||
|
||||
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
||||
val getScriptConfiguration = { ktFile: KtFile ->
|
||||
(dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration ?: context.baseScriptCompilationConfiguration)
|
||||
(dependenciesProvider?.getScriptConfiguration(ktFile)?.configuration ?: context.baseScriptCompilationConfiguration)
|
||||
.with {
|
||||
// Adjust definitions so all compiler dependencies are saved in the resulting compilation configuration, so evaluation
|
||||
// performed with the expected classpath
|
||||
|
||||
+1
-2
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.compilerOptions
|
||||
import kotlin.script.experimental.api.dependencies
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.jdkHome
|
||||
@@ -244,7 +243,7 @@ private fun CompilerConfiguration.updateWithRefinedConfigurations(
|
||||
) {
|
||||
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
||||
val updatedCompilerOptions = sourceFiles.flatMap {
|
||||
dependenciesProvider?.getScriptConfigurationResult(it)?.valueOrNull()?.configuration?.get(
|
||||
dependenciesProvider?.getScriptConfiguration(it)?.configuration?.get(
|
||||
ScriptCompilationConfiguration.compilerOptions
|
||||
) ?: emptyList()
|
||||
}
|
||||
|
||||
+1
-2
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.script.experimental.api.valueOrNull
|
||||
|
||||
// WARNING: not thread safe, assuming external synchronization
|
||||
|
||||
@@ -71,7 +70,7 @@ open class GenericReplCompiler(
|
||||
}
|
||||
|
||||
val newDependencies =
|
||||
ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptConfigurationResult(psiFile)?.valueOrNull()
|
||||
ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptConfiguration(psiFile)
|
||||
?.legacyDependencies
|
||||
var classpathAddendum: List<File>? = null
|
||||
if (compilerState.lastDependencies != newDependencies) {
|
||||
|
||||
Reference in New Issue
Block a user