diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt index a5370fb0677..ab7655e1b21 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt @@ -77,7 +77,9 @@ class ScriptDependenciesManager internal constructor( @TestOnly fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) { val scriptDefinition = virtualFile.findScriptDefinition(project)!! - SyncScriptDependenciesLoader(project).updateDependencies(virtualFile, scriptDefinition) + val loader = SyncScriptDependenciesLoader(project) + loader.updateDependencies(virtualFile, scriptDefinition) + loader.notifyRootsChanged() } } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt index 1969a2a469a..f6f43321658 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt @@ -69,6 +69,8 @@ class ScriptDependenciesUpdater( updateDependencies(file, scriptDef) + makeRootsChangeIfNeeded() + return cache[file] ?: ScriptDependencies.Empty } @@ -80,6 +82,12 @@ class ScriptDependenciesUpdater( loader.updateDependencies(file, scriptDef) } + private fun makeRootsChangeIfNeeded() { + if (fileAttributeLoader.notifyRootsChanged()) return + if (syncLoader.notifyRootsChanged()) return + if (asyncLoader.notifyRootsChanged()) return + } + private fun listenForChangesInScripts() { project.messageBus.connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener { override fun fileOpened(source: FileEditorManager, file: VirtualFile) { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt index ef61188c784..a2059cca3e8 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.core.script.dependencies import com.intellij.openapi.application.runReadAction +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 @@ -25,11 +26,13 @@ import kotlin.script.experimental.dependencies.AsyncDependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver class AsyncScriptDependenciesLoader internal constructor(project: Project) : ScriptDependenciesLoader(project) { - private val backgroundTaskLock = ReentrantReadWriteLock() + private val lock = ReentrantReadWriteLock() + + private var notifyRootChange: Boolean = false private var backgroundTasksQueue: LoaderBackgroundTask? = null override fun loadDependencies(file: VirtualFile, scriptDef: KotlinScriptDefinition) { - backgroundTaskLock.write { + lock.write { if (backgroundTasksQueue == null) { backgroundTasksQueue = LoaderBackgroundTask() backgroundTasksQueue!!.addTask(file) @@ -42,6 +45,28 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr override fun shouldShowNotification(): Boolean = !KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled + override fun notifyRootsChanged(): Boolean { + lock.write { + if (notifyRootChange) return false + + if (backgroundTasksQueue == null) { + submitMakeRootsChange() + return true + } + + notifyRootChange = true + + backgroundTasksQueue!!.addOnFinishTask { + lock.write { + notifyRootChange = false + } + submitMakeRootsChange() + } + } + + return false + } + private fun runDependenciesUpdate(file: VirtualFile) { val scriptDef = runReadAction { file.findScriptDefinition(project) } ?: return // runBlocking is using there to avoid loading dependencies asynchronously @@ -72,6 +97,8 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr private inner class LoaderBackgroundTask { private val sequenceOfFiles: ConcurrentLinkedQueue = ConcurrentLinkedQueue() + private var onFinish: (() -> Unit)? = null + fun start() { if (shouldShowNotification()) { BackgroundTaskUtil.executeOnPooledThread(project, Runnable { @@ -91,10 +118,15 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr sequenceOfFiles.add(file) } + fun addOnFinishTask(task: () -> Unit) { + onFinish = task + } + private fun loadDependencies(indicator: ProgressIndicator?) { while (true) { if (indicator?.isCanceled == true || sequenceOfFiles.isEmpty()) { - backgroundTaskLock.write { + lock.write { + onFinish?.invoke() backgroundTasksQueue = null } return diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt index 599a3478071..203110295af 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt @@ -22,7 +22,7 @@ class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDepend val rootsChanged = cache.hasNotCachedRoots(deserialized) cache.save(file, deserialized) if (rootsChanged) { - notifyRootsChanged() + shouldNotifyRootsChanged = true } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt index fbe3223ffac..81d85ddf0f0 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt @@ -37,6 +37,8 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { protected abstract fun loadDependencies(file: VirtualFile, scriptDef: KotlinScriptDefinition) protected abstract fun shouldShowNotification(): Boolean + protected var shouldNotifyRootsChanged = false + protected val contentLoader = ScriptContentLoader(project) protected val cache: ScriptDependenciesCache = ServiceManager.getService(project, ScriptDependenciesCache::class.java) @@ -87,15 +89,20 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { } if (rootsChanged) { - notifyRootsChanged() + shouldNotifyRootsChanged = true } } - protected fun notifyRootsChanged() { + open fun notifyRootsChanged(): Boolean = submitMakeRootsChange() + + protected fun submitMakeRootsChange(): Boolean { + if (!shouldNotifyRootsChanged) return false + val doNotifyRootsChanged = Runnable { runWriteAction { if (project.isDisposed) return@runWriteAction + shouldNotifyRootsChanged = false ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true) ScriptDependenciesModificationTracker.getInstance(project).incModificationCount() } @@ -106,5 +113,7 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { } else { TransactionGuard.getInstance().submitTransactionLater(project, doNotifyRootsChanged) } + + return true } }