Fire one 'roots changed' event after all scripts dependencies loaded

^KT-29474
This commit is contained in:
Natalia Selezneva
2019-02-15 11:04:25 +03:00
parent 6bc6dea916
commit 8331d9789e
5 changed files with 58 additions and 7 deletions
@@ -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()
}
}
}
@@ -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) {
@@ -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<VirtualFile> = 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
@@ -22,7 +22,7 @@ class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDepend
val rootsChanged = cache.hasNotCachedRoots(deserialized)
cache.save(file, deserialized)
if (rootsChanged) {
notifyRootsChanged()
shouldNotifyRootsChanged = true
}
}
@@ -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
}
}