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.PsiFile
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager 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) { public abstract class AndroidResourceManager(val project: Project) {
@@ -60,6 +61,11 @@ public abstract class AndroidResourceManager(val project: Project) {
.sortBy { it.getName() } .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 org.jetbrains.kotlin.psi.JetFile
import javax.xml.parsers.SAXParser import javax.xml.parsers.SAXParser
import java.util.HashMap 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 com.intellij.openapi.project.Project
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import com.intellij.openapi.util.Key
import com.intellij.testFramework.LightVirtualFile import com.intellij.testFramework.LightVirtualFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import java.io.FileInputStream import java.io.FileInputStream
@@ -53,7 +48,10 @@ import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValueProvider.Result
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import com.intellij.openapi.roots.ProjectRootModificationTracker 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) { public abstract class AndroidUIXmlProcessor(protected val project: Project) {
@@ -64,29 +62,36 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
"android.view.View", "android.view.View",
"android.widget.*") "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 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) protected val LOG: Logger = Logger.getInstance(javaClass)
public fun parse(): List<String> { 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) {}
}
))
}
}