Cache Android XML parse results using VfsModificationTracker

This commit is contained in:
Yan Zhulanow
2015-02-25 16:44:04 +03:00
parent d7fdb8b513
commit 20fc298113
2 changed files with 95 additions and 30 deletions
@@ -19,9 +19,10 @@ package org.jetbrains.kotlin.lang.resolve.android
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiElement
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.util.*
import com.intellij.openapi.vfs.impl.*
import com.intellij.openapi.vfs.*
public abstract class AndroidResourceManager(val project: Project) {
@@ -60,6 +61,11 @@ public abstract class AndroidResourceManager(val project: Project) {
.sortBy { it.getName() }
}
inner class NoLayoutXmlFound : Exception("No android UI xmls found in " + androidModuleInfo?.mainResDirectory)
fun getMainLayoutDirectory(): VirtualFile? {
val info = androidModuleInfo
if (info == null) return null
return VirtualFileManager.getInstance().findFileByUrl("file://" + info.mainResDirectory)
}
}
@@ -28,13 +28,8 @@ import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetFile
import javax.xml.parsers.SAXParser
import java.util.HashMap
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.VirtualFileAdapter
import com.intellij.openapi.vfs.VirtualFileEvent
import com.intellij.openapi.project.Project
import java.util.concurrent.ConcurrentLinkedQueue
import com.intellij.openapi.util.Key
import com.intellij.testFramework.LightVirtualFile
import com.intellij.psi.PsiManager
import java.io.FileInputStream
@@ -53,7 +48,10 @@ import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValueProvider.Result
import java.util.concurrent.atomic.AtomicInteger
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.util.*
import com.intellij.openapi.vfs.impl.*
import com.intellij.openapi.vfs.*
import kotlin.properties.*
public abstract class AndroidUIXmlProcessor(protected val project: Project) {
@@ -64,29 +62,36 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
"android.view.View",
"android.widget.*")
//TODO
private val cachedSources = cachedValue {
Result.create(parse(), ProjectRootModificationTracker.getInstance(project))
}
private val cachedJetFiles = cachedValue {
val psiManager = PsiManager.getInstance(project)
val applicationPackage = resourceManager.androidModuleInfo?.applicationPackage
val jetFiles = cachedSources.getValue().mapIndexed { (index, text) ->
val virtualFile = LightVirtualFile(AndroidConst.SYNTHETIC_FILENAME + index + ".kt", text)
val jetFile = psiManager.findFile(virtualFile) as JetFile
if (applicationPackage != null) {
jetFile.putUserData(AndroidConst.ANDROID_USER_PACKAGE, applicationPackage)
}
jetFile
}
Result.create(jetFiles, cachedSources)
}
public abstract val resourceManager: AndroidResourceManager
private val vfsTracker: VfsModificationTracker by Delegates.lazy {
VfsModificationTracker(project, resourceManager.getMainLayoutDirectory())
}
private val cachedSources: CachedValue<List<String>> by Delegates.lazy {
cachedValue {
Result.create(parse(), vfsTracker)
}
}
private val cachedJetFiles: CachedValue<List<JetFile>> by Delegates.lazy {
cachedValue {
val psiManager = PsiManager.getInstance(project)
val applicationPackage = resourceManager.androidModuleInfo?.applicationPackage
val jetFiles = cachedSources.getValue().mapIndexed { (index, text) ->
val virtualFile = LightVirtualFile(AndroidConst.SYNTHETIC_FILENAME + index + ".kt", text)
val jetFile = psiManager.findFile(virtualFile) as JetFile
if (applicationPackage != null) {
jetFile.putUserData(AndroidConst.ANDROID_USER_PACKAGE, applicationPackage)
}
jetFile
}
Result.create(jetFiles, cachedSources)
}
}
protected val LOG: Logger = Logger.getInstance(javaClass)
public fun parse(): List<String> {
@@ -132,3 +137,57 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
}
}
private class VfsModificationTracker(project: Project, resDirectory: VirtualFile?): SimpleModificationTracker() {
{
val connection = project.getMessageBus().connect();
connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter(
object : VirtualFileListener {
fun incModificationCountIfLayout(file: VirtualFile) {
if (resDirectory == null) {
incModificationCount()
} else {
val probablyLayoutDir = file.getParent()
val probablyResDir = file.getParent()?.getParent()
if (resDirectory == probablyResDir && probablyLayoutDir?.getName()?.startsWith("layout") ?: false) {
incModificationCount()
}
}
}
override fun contentsChanged(event: VirtualFileEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun propertyChanged(event: VirtualFilePropertyEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun fileCreated(event: VirtualFileEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun fileDeleted(event: VirtualFileEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun fileMoved(event: VirtualFileMoveEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun fileCopied(event: VirtualFileCopyEvent) {
incModificationCountIfLayout(event.getFile())
}
override fun beforePropertyChange(event: VirtualFilePropertyEvent) {}
override fun beforeContentsChange(event: VirtualFileEvent) {}
override fun beforeFileDeletion(event: VirtualFileEvent) {}
override fun beforeFileMovement(event: VirtualFileMoveEvent) {}
}
))
}
}