Refactoring of ScriptDependenciesUpdater

Extract classes for sync and async dependencies loading
This commit is contained in:
Natalia Selezneva
2018-04-28 13:14:35 +03:00
parent 97848f2812
commit 082916be70
8 changed files with 322 additions and 212 deletions
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.script package org.jetbrains.kotlin.script
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
@@ -78,7 +77,6 @@ class ScriptContentLoader(private val project: Project) {
catch (e: Throwable) { catch (e: Throwable) {
e.asResolveFailure(scriptDef) e.asResolveFailure(scriptDef)
} }
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
return result return result
} }
@@ -99,7 +99,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
definitions = definitionsByContributor.values.flattenTo(mutableListOf()).asSequence() definitions = definitionsByContributor.values.flattenTo(mutableListOf()).asSequence()
clearCache() clearCache()
// TODO: clear by script type/definition // TODO: clear by script type/definition
ServiceManager.getService(project, ScriptDependenciesUpdater::class.java).clear() ServiceManager.getService(project, ScriptDependenciesCache::class.java).clear()
} }
private fun ScriptDefinitionContributor.safeGetDefinitions(): List<KotlinScriptDefinition> { private fun ScriptDefinitionContributor.safeGetDefinitions(): List<KotlinScriptDefinition> {
@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader
import org.jetbrains.kotlin.script.ScriptDefinitionProvider import org.jetbrains.kotlin.script.ScriptDefinitionProvider
import org.jetbrains.kotlin.script.ScriptDependenciesProvider import org.jetbrains.kotlin.script.ScriptDependenciesProvider
import org.jetbrains.kotlin.script.findScriptDefinition import org.jetbrains.kotlin.script.findScriptDefinition
@@ -78,8 +79,7 @@ class ScriptDependenciesManager internal constructor(
fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) { fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) {
with(getInstance(project)) { with(getInstance(project)) {
val scriptDefinition = ScriptDefinitionProvider.getInstance(project).findScriptDefinition(virtualFile)!! val scriptDefinition = ScriptDefinitionProvider.getInstance(project).findScriptDefinition(virtualFile)!!
cacheUpdater.updateSync(virtualFile, scriptDefinition) SyncScriptDependenciesLoader(virtualFile, scriptDefinition, project, shouldNotifyRootsChanged = true).updateDependencies()
cacheUpdater.notifyRootsChanged()
} }
} }
} }
@@ -18,103 +18,52 @@ package org.jetbrains.kotlin.idea.core.script
import com.intellij.openapi.application.Application import com.intellij.openapi.application.Application
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.project.isProjectOrWorkspaceFile import com.intellij.openapi.project.isProjectOrWorkspaceFile
import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
import com.intellij.openapi.util.EmptyRunnable
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.openapi.wm.WindowManager
import com.intellij.openapi.wm.ex.StatusBarEx
import com.intellij.openapi.wm.ex.WindowManagerEx
import kotlinx.coroutines.experimental.CoroutineDispatcher
import kotlinx.coroutines.experimental.asCoroutineDispatcher
import kotlinx.coroutines.experimental.launch
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.core.script.dependencies.FromFileAttributeScriptDependenciesLoader
import org.jetbrains.kotlin.idea.core.util.cancelOnDisposal import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptDependenciesLoader
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.script.* import org.jetbrains.kotlin.script.ScriptDefinitionProvider
import java.util.concurrent.ConcurrentHashMap import org.jetbrains.kotlin.script.findScriptDefinition
import java.util.concurrent.Executors
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
class ScriptDependenciesUpdater( class ScriptDependenciesUpdater(
private val project: Project, private val project: Project,
private val cache: ScriptDependenciesCache, private val cache: ScriptDependenciesCache,
private val scriptDefinitionProvider: ScriptDefinitionProvider private val scriptDefinitionProvider: ScriptDefinitionProvider
) { ) {
private val requests = ConcurrentHashMap<String, ModStampedRequest>()
private val contentLoader = ScriptContentLoader(project)
private val asyncUpdatesDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
private val legacyUpdatesDispatcher =
Executors.newFixedThreadPool(
(Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
).asCoroutineDispatcher()
private val modifiedScripts = mutableSetOf<VirtualFile>() private val modifiedScripts = mutableSetOf<VirtualFile>()
init { init {
listenToVfsChanges() listenToVfsChanges()
} }
private class TimeStampedJob(val actualJob: Task.Backgroundable, val timeStamp: TimeStamp) {
fun stampBy(virtualFile: VirtualFile) = ModStampedRequest(virtualFile.modificationStamp, this)
}
private class ModStampedRequest(
val modificationStamp: Long,
val job: TimeStampedJob?
) {
fun cancel() {
val actualJob = job?.actualJob ?: return
val frame = (WindowManager.getInstance() as? WindowManagerEx)?.findFrameFor(actualJob.project)
val statusBar = frame?.statusBar as? StatusBarEx ?: return
statusBar.backgroundProcesses.find { it.first == actualJob }?.second?.cancel()
}
}
fun getCurrentDependencies(file: VirtualFile): ScriptDependencies { fun getCurrentDependencies(file: VirtualFile): ScriptDependencies {
cache[file]?.let { return it } cache[file]?.let { return it }
tryLoadingFromDisk(file) val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return ScriptDependencies.Empty
performUpdate(file)
FromFileAttributeScriptDependenciesLoader(file, scriptDef, project).updateDependencies()
ScriptDependenciesLoader.updateDependencies(file, scriptDef, project, shouldNotifyRootsChanged = false)
return cache[file] ?: ScriptDependencies.Empty return cache[file] ?: ScriptDependencies.Empty
} }
fun reloadModifiedScripts() { fun reloadModifiedScripts() {
for (it in modifiedScripts.filter { cache[it] != null }) { for (it in modifiedScripts.filter { cache[it] != null }) {
performUpdate(it) val scriptDef = scriptDefinitionProvider.findScriptDefinition(it) ?: return
ScriptDependenciesLoader.updateDependencies(it, scriptDef, project, shouldNotifyRootsChanged = true)
} }
modifiedScripts.clear() modifiedScripts.clear()
} }
private fun tryLoadingFromDisk(file: VirtualFile): Boolean {
val deserializedDependencies = file.scriptDependencies ?: return false
saveToCache(deserializedDependencies, file)
return true
}
private fun saveToCache(deserialized: ScriptDependencies, file: VirtualFile) {
val rootsChanged = cache.hasNotCachedRoots(deserialized)
cache.save(file, deserialized)
if (rootsChanged) {
notifyRootsChanged()
}
}
fun requestUpdate(files: Iterable<VirtualFile>) { fun requestUpdate(files: Iterable<VirtualFile>) {
files.forEach { file -> files.forEach { file ->
if (!file.isValid) { if (!file.isValid) {
@@ -125,137 +74,6 @@ class ScriptDependenciesUpdater(
} }
} }
private fun performUpdate(file: VirtualFile) {
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) ?: return
when (scriptDef.dependencyResolver) {
is AsyncDependenciesResolver, is LegacyResolverWrapper -> {
updateAsync(file, scriptDef)
}
else -> updateSync(file, scriptDef)
}
}
private fun updateAsync(
file: VirtualFile,
scriptDefinition: KotlinScriptDefinition
) {
val path = file.path
val lastRequest = requests[path]
if (!shouldSendNewRequest(file, lastRequest)) {
return
}
lastRequest?.cancel()
requests[path] = sendRequest(file, scriptDefinition).stampBy(file)
return
}
private fun shouldSendNewRequest(file: VirtualFile, previousRequest: ModStampedRequest?): Boolean {
if (previousRequest == null) return true
return file.modificationStamp != previousRequest.modificationStamp
}
private fun sendRequest(
file: VirtualFile,
scriptDef: KotlinScriptDefinition
): TimeStampedJob {
val currentTimeStamp = TimeStamps.next()
val newJob = object : Task.Backgroundable(project, "Kotlin: Loading dependencies for ${file.name} ...", true) {
override fun run(indicator: ProgressIndicator) {
if (updateSync(file, scriptDef)) {
notifyRootsChanged()
}
}
}
newJob.queue()
return TimeStampedJob(newJob, currentTimeStamp)
}
private fun launchAsyncUpdate(
dispatcher: CoroutineDispatcher,
file: VirtualFile,
currentTimeStamp: TimeStamp,
scriptDef: KotlinScriptDefinition,
doResolve: suspend () -> DependenciesResolver.ResolveResult
) = launch(dispatcher + project.cancelOnDisposal) {
val result = try {
doResolve()
} catch (t: Throwable) {
t.asResolveFailure(scriptDef)
}
processResult(file, currentTimeStamp, result, scriptDef)
}
private fun processResult(
file: VirtualFile,
currentTimeStamp: TimeStamp,
result: DependenciesResolver.ResolveResult,
scriptDef: KotlinScriptDefinition
) {
val lastRequest = requests[file.path]
val lastTimeStamp = lastRequest?.job?.timeStamp
val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp
if (isLastSentRequest) {
if (lastRequest != null) {
// no job running atm unless there is a job started while we process this result
requests.replace(file.path, lastRequest, ModStampedRequest(lastRequest.modificationStamp, job = null))
}
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
val resultingDependencies = result.dependencies?.adjustByDefinition(scriptDef) ?: return
if (saveNewDependencies(resultingDependencies, file, result.reports.any { it.severity == ScriptReport.Severity.FATAL })) {
notifyRootsChanged()
}
}
}
fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean {
val result = contentLoader.loadContentsAndResolveDependencies(scriptDef, file)
val newDeps = result.dependencies?.adjustByDefinition(scriptDef) ?: ScriptDependencies.Empty
return saveNewDependencies(newDeps, file, result.reports.any { it.severity == ScriptReport.Severity.FATAL })
}
private fun saveNewDependencies(
new: ScriptDependencies,
file: VirtualFile,
hasFatalErrors: Boolean
): Boolean {
val rootsChanged = cache.hasNotCachedRoots(new)
if (cache.save(file, new)) {
if (hasFatalErrors) {
file.scriptDependencies = null
} else {
file.scriptDependencies = new
}
}
return rootsChanged
}
fun notifyRootsChanged() {
val rootsChangesRunnable = {
runWriteAction {
if (project.isDisposed) return@runWriteAction
ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true)
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
}
}
val application = ApplicationManager.getApplication()
if (application.isUnitTestMode) {
rootsChangesRunnable()
} else {
launch(EDT(project)) {
rootsChangesRunnable()
}
}
}
private fun listenToVfsChanges() { private fun listenToVfsChanges() {
project.messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() { project.messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() {
val projectFileIndex = ProjectRootManager.getInstance(project).fileIndex val projectFileIndex = ProjectRootManager.getInstance(project).fileIndex
@@ -279,21 +97,6 @@ class ScriptDependenciesUpdater(
} }
}) })
} }
fun clear() {
cache.clear()
requests.clear()
}
}
private data class TimeStamp(private val stamp: Long) {
operator fun compareTo(other: TimeStamp) = this.stamp.compareTo(other.stamp)
}
private object TimeStamps {
private var current: Long = 0
fun next() = TimeStamp(current++)
} }
@set: TestOnly @set: TestOnly
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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 kotlinx.coroutines.experimental.*
import org.jetbrains.kotlin.idea.core.util.cancelOnDisposal
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.LegacyResolverWrapper
import org.jetbrains.kotlin.script.asResolveFailure
import java.util.concurrent.Executors
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
@Suppress("EXPERIMENTAL_FEATURE_WARNING")
class AsyncScriptDependenciesLoader(
file: VirtualFile,
scriptDef: KotlinScriptDefinition,
project: Project
) : ScriptDependenciesLoader(file, scriptDef, project, true) {
override fun loadDependencies() {
if (!shouldSendNewRequest(lastRequest)) {
return
}
lastRequest?.cancel()
lastRequest = sendRequest().stampBy(file)
runBlocking {
lastRequest?.job?.actualJob?.join()
}
}
override fun shouldUseBackgroundThread() = true
private var lastRequest: ModStampedRequest? = null
private val asyncUpdatesDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
private val legacyUpdatesDispatcher =
Executors.newFixedThreadPool(
(Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
).asCoroutineDispatcher()
private fun shouldSendNewRequest(previousRequest: ModStampedRequest?): Boolean {
if (previousRequest == null) return true
return file.modificationStamp != previousRequest.modificationStamp
}
private fun sendRequest(): TimeStampedJob {
val currentTimeStamp = TimeStamps.next()
val dependenciesResolver = scriptDef.dependencyResolver
val scriptContents = contentLoader.getScriptContents(scriptDef, file)
val environment = contentLoader.getEnvironment(scriptDef)
val newJob = if (dependenciesResolver is AsyncDependenciesResolver) {
launchAsyncUpdate(asyncUpdatesDispatcher, currentTimeStamp) {
dependenciesResolver.resolveAsync(scriptContents, environment)
}
} else {
assert(dependenciesResolver is LegacyResolverWrapper)
launchAsyncUpdate(legacyUpdatesDispatcher, currentTimeStamp) {
dependenciesResolver.resolve(scriptContents, environment)
}
}
return TimeStampedJob(newJob, currentTimeStamp)
}
private fun launchAsyncUpdate(
dispatcher: CoroutineDispatcher,
currentTimeStamp: TimeStamp,
doResolve: suspend () -> DependenciesResolver.ResolveResult
): Job = launch(dispatcher + project.cancelOnDisposal) {
val result = try {
doResolve()
} catch (t: Throwable) {
t.asResolveFailure(scriptDef)
}
processResult(currentTimeStamp, result)
}
private fun processResult(
currentTimeStamp: TimeStamp,
result: DependenciesResolver.ResolveResult
) {
val lastTimeStamp = lastRequest?.job?.timeStamp
val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp
if (isLastSentRequest) {
if (lastRequest != null) {
// no job running atm unless there is a job started while we process this result
lastRequest = ModStampedRequest(lastRequest!!.modificationStamp, job = null)
}
processResult(result)
}
}
private class ModStampedRequest(val modificationStamp: Long, val job: TimeStampedJob?) {
fun cancel() = job?.actualJob?.cancel()
}
private class TimeStampedJob(val actualJob: Job, val timeStamp: TimeStamp) {
fun stampBy(virtualFile: VirtualFile) =
ModStampedRequest(
virtualFile.modificationStamp,
this
)
}
private data class TimeStamp(private val stamp: Long) {
operator fun compareTo(other: TimeStamp) = this.stamp.compareTo(other.stamp)
}
private object TimeStamps {
private var current: Long = 0
fun next() =
TimeStamp(current++)
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.scriptDependencies
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import kotlin.script.experimental.dependencies.ScriptDependencies
class FromFileAttributeScriptDependenciesLoader(
file: VirtualFile,
scriptDef: KotlinScriptDefinition,
project: Project
) : ScriptDependenciesLoader(file, scriptDef, project, true) {
override fun loadDependencies() {
val deserializedDependencies = file.scriptDependencies ?: return
saveToCache(deserializedDependencies)
}
private fun saveToCache(deserialized: ScriptDependencies) {
val rootsChanged = cache.hasNotCachedRoots(deserialized)
cache.save(file, deserialized)
if (rootsChanged) {
notifyRootsChanged()
}
}
override fun shouldUseBackgroundThread() = false
}
@@ -0,0 +1,122 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
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 com.intellij.util.containers.SLRUMap
import kotlinx.coroutines.experimental.launch
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesCache
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
import org.jetbrains.kotlin.idea.core.script.scriptDependencies
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.script.*
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
abstract class ScriptDependenciesLoader(
protected val file: VirtualFile,
protected val scriptDef: KotlinScriptDefinition,
protected val project: Project,
private val shouldNotifyRootsChanged: Boolean
) {
companion object {
private val loaders = SLRUMap<VirtualFile, ScriptDependenciesLoader>(10, 10)
fun updateDependencies(
file: VirtualFile,
scriptDef: KotlinScriptDefinition,
project: Project,
shouldNotifyRootsChanged: Boolean
) {
val existingLoader = loaders[file]
if (existingLoader != null) return existingLoader.updateDependencies()
val newLoader = when (scriptDef.dependencyResolver) {
is AsyncDependenciesResolver,
is LegacyResolverWrapper -> AsyncScriptDependenciesLoader(file, scriptDef, project)
else -> SyncScriptDependenciesLoader(file, scriptDef, project, shouldNotifyRootsChanged)
}
loaders.put(file, newLoader)
newLoader.updateDependencies()
}
}
fun updateDependencies() {
if (shouldUseBackgroundThread()) {
object : Task.Backgroundable(project, "Kotlin: Loading dependencies for ${file.name} ...", true) {
override fun run(indicator: ProgressIndicator) {
loadDependencies()
}
}.queue()
} else {
loadDependencies()
}
}
protected abstract fun loadDependencies()
protected abstract fun shouldUseBackgroundThread(): Boolean
protected val contentLoader = ScriptContentLoader(project)
protected val cache: ScriptDependenciesCache = ServiceManager.getService(project, ScriptDependenciesCache::class.java)
protected fun processResult(result: DependenciesResolver.ResolveResult) {
saveDependencies(result)
}
private fun saveDependencies(result: DependenciesResolver.ResolveResult) {
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
val newDependencies = result.dependencies?.adjustByDefinition(scriptDef) ?: ScriptDependencies.Empty
val rootsChanged = cache.hasNotCachedRoots(newDependencies)
if (cache.save(file, newDependencies)) {
if (result.reports.any { it.severity == ScriptReport.Severity.FATAL }) {
file.scriptDependencies = null
} else {
file.scriptDependencies = newDependencies
}
}
if (rootsChanged) {
notifyRootsChanged()
}
loaders.remove(file)
}
@Suppress("EXPERIMENTAL_FEATURE_WARNING")
protected fun notifyRootsChanged() {
if (!shouldNotifyRootsChanged) return
val rootsChangesRunnable = {
runWriteAction {
if (project.isDisposed) return@runWriteAction
ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true)
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
}
}
val application = ApplicationManager.getApplication()
if (application.isUnitTestMode) {
rootsChangesRunnable()
} else {
launch(EDT(project)) {
rootsChangesRunnable()
}
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.script.KotlinScriptDefinition
class SyncScriptDependenciesLoader(
file: VirtualFile,
scriptDef: KotlinScriptDefinition,
project: Project,
shouldNotifyRootsChanged: Boolean
) : ScriptDependenciesLoader(file, scriptDef, project, shouldNotifyRootsChanged) {
override fun loadDependencies() {
val result = contentLoader.loadContentsAndResolveDependencies(scriptDef, file)
processResult(result)
}
override fun shouldUseBackgroundThread(): Boolean = false
}