Add script files changes monitoring, logic for initialization during index rebuilding
This commit is contained in:
committed by
Pavel V. Talanov
parent
8dac72f465
commit
5bea5bcc37
@@ -69,6 +69,13 @@ class KotlinScriptExternalDependenciesUnion(val dependencies: Iterable<KotlinScr
|
||||
override val sources: Iterable<File> get() = dependencies.flatMap { it.sources }
|
||||
}
|
||||
|
||||
fun Iterable<File>.isSameClasspathAs(other: Iterable<File>): Boolean {
|
||||
val c1 = map { it.canonicalPath }.toHashSet()
|
||||
val c2 = other.map { it.canonicalPath }.toHashSet()
|
||||
return c1.size == c2.size &&
|
||||
c1.zip(c2).all { it.first == it.second }
|
||||
}
|
||||
|
||||
data class ScriptParameter(val name: Name, val type: KotlinType)
|
||||
|
||||
fun <TF> getFileName(file: TF): String = when (file) {
|
||||
|
||||
+31
@@ -49,6 +49,7 @@ class KotlinScriptExternalImportsProvider(val project: Project, private val scri
|
||||
}
|
||||
}
|
||||
|
||||
// optimized for initial caching, additional handling of possible duplicates to save a call to distinct
|
||||
fun <TF> cacheExternalImports(files: Iterable<TF>): Unit = cacheLock.write {
|
||||
val uncached = hashSetOf<String>()
|
||||
files.forEach { file ->
|
||||
@@ -71,6 +72,36 @@ class KotlinScriptExternalImportsProvider(val project: Project, private val scri
|
||||
}
|
||||
}
|
||||
|
||||
// optimized for update, no special duplicates handling
|
||||
fun <TF: Any> updateExternalImportsCache(files: Iterable<TF>): Iterable<TF> = cacheLock.write {
|
||||
files.mapNotNull { file ->
|
||||
val path = getFilePath(file)
|
||||
val scriptDef = scriptDefinitionProvider.findScriptDefinition(file)
|
||||
if (scriptDef != null) {
|
||||
val deps = scriptDef.getDependenciesFor(file, project)
|
||||
val oldDeps = cache[path]
|
||||
when {
|
||||
deps != null && (oldDeps == null ||
|
||||
!deps.classpath.isSameClasspathAs(oldDeps.classpath) || !deps.sources.isSameClasspathAs(oldDeps.sources)) -> {
|
||||
// changed or new
|
||||
cache.put(path, deps)
|
||||
cacheOfNulls.remove(path)
|
||||
file
|
||||
}
|
||||
deps != null -> {
|
||||
// same as before
|
||||
null
|
||||
}
|
||||
else -> {
|
||||
if (cache.remove(path) != null || cacheOfNulls.remove(path)) file // cleared
|
||||
else null // same as before
|
||||
}
|
||||
}
|
||||
}
|
||||
else null // not a script
|
||||
}
|
||||
}
|
||||
|
||||
fun invalidateCaches() {
|
||||
cacheLock.write {
|
||||
cache.keys.toList().apply {
|
||||
|
||||
+36
-5
@@ -17,24 +17,33 @@
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.openapi.util.EmptyRunnable
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.indexing.IndexableSetContributor
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.FileLibraryScope
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.script.*
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
class KotlinScriptConfigurationManager(
|
||||
private val project: Project,
|
||||
private val dumbService: DumbService,
|
||||
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider,
|
||||
private val scriptExternalImportsProvider: KotlinScriptExternalImportsProvider?
|
||||
) {
|
||||
@@ -47,11 +56,28 @@ class KotlinScriptConfigurationManager(
|
||||
reloadScriptDefinitions()
|
||||
// TODO: sort out read/write action business and if possible make it lazy (e.g. move to getAllScriptsClasspath)
|
||||
runReadAction { cacheAllScriptsExtraImports() }
|
||||
|
||||
project.messageBus.connect().subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() {
|
||||
override fun after(events: List<VFileEvent>) {
|
||||
val isChanged = scriptExternalImportsProvider?.updateExternalImportsCache( events.mapNotNull { it.file })?.any() ?: false
|
||||
if (isChanged) {
|
||||
// TODO: consider more fine-grained update
|
||||
cacheLock.write {
|
||||
allScriptsClasspathCache = null
|
||||
}
|
||||
notifyRootsChanged()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var allScriptsClasspathCache: List<VirtualFile>? = null
|
||||
private val cacheLock = ReentrantReadWriteLock()
|
||||
|
||||
private fun notifyRootsChanged() {
|
||||
runWriteAction { ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true) }
|
||||
}
|
||||
|
||||
fun getScriptClasspath(file: VirtualFile): List<VirtualFile> =
|
||||
scriptExternalImportsProvider
|
||||
?.getExternalImports(file)
|
||||
@@ -61,12 +87,17 @@ class KotlinScriptConfigurationManager(
|
||||
|
||||
fun getAllScriptsClasspath(): List<VirtualFile> = cacheLock.read {
|
||||
if (allScriptsClasspathCache == null) {
|
||||
allScriptsClasspathCache =
|
||||
(scriptExternalImportsProvider?.getKnownCombinedClasspath() ?: emptyList())
|
||||
.distinct()
|
||||
.mapNotNull { it.classpathEntryToVfs() }
|
||||
dumbService.runWhenSmart {
|
||||
cacheLock.write {
|
||||
allScriptsClasspathCache =
|
||||
(scriptExternalImportsProvider?.getKnownCombinedClasspath() ?: emptyList())
|
||||
.distinct()
|
||||
.mapNotNull { it.classpathEntryToVfs() }
|
||||
}
|
||||
notifyRootsChanged()
|
||||
}
|
||||
}
|
||||
return allScriptsClasspathCache!!
|
||||
return allScriptsClasspathCache ?: emptyList()
|
||||
}
|
||||
|
||||
private fun File.classpathEntryToVfs(): VirtualFile =
|
||||
|
||||
Reference in New Issue
Block a user