Optimize AndroidPsiTreeChangePreprocessor counter updating
This commit is contained in:
+65
-29
@@ -21,55 +21,91 @@ import com.intellij.openapi.roots.ProjectRootManager
|
|||||||
import com.intellij.openapi.util.SimpleModificationTracker
|
import com.intellij.openapi.util.SimpleModificationTracker
|
||||||
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.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl
|
import com.intellij.psi.impl.PsiTreeChangeEventImpl
|
||||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
||||||
|
import com.intellij.psi.xml.XmlAttribute
|
||||||
|
import com.intellij.psi.xml.XmlAttributeValue
|
||||||
import com.intellij.psi.xml.XmlFile
|
import com.intellij.psi.xml.XmlFile
|
||||||
|
import com.intellij.psi.xml.XmlToken
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
||||||
|
|
||||||
public class AndroidPsiTreeChangePreprocessor : PsiTreeChangePreprocessor, SimpleModificationTracker() {
|
public class AndroidPsiTreeChangePreprocessor : PsiTreeChangePreprocessor, SimpleModificationTracker() {
|
||||||
|
|
||||||
companion object {
|
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
||||||
|
if (event.code in HANDLED_EVENTS) {
|
||||||
|
val child = event.child
|
||||||
|
|
||||||
|
// We should get more precise event notification (not just "that file was changed somehow")
|
||||||
|
if (child == null && event.code == PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkIfLayoutFile(child)) {
|
||||||
|
incModificationCount()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = event.file ?: return
|
||||||
|
if (!checkIfLayoutFile(file)) return
|
||||||
|
|
||||||
|
val xmlAttribute = findXmlAttribute(child)
|
||||||
|
if (xmlAttribute != null) {
|
||||||
|
val name = xmlAttribute.name
|
||||||
|
if (name != "android:id" && name != "class") return
|
||||||
|
}
|
||||||
|
|
||||||
|
incModificationCount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
private val HANDLED_EVENTS = setOf(
|
private val HANDLED_EVENTS = setOf(
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED,
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED,
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
||||||
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED)
|
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED)
|
||||||
}
|
|
||||||
|
|
||||||
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
private fun checkIfLayoutFile(element: PsiElement): Boolean {
|
||||||
if (event.getCode() in HANDLED_EVENTS) {
|
val xmlFile = element as? XmlFile ?: return false
|
||||||
val file = event.getFile() ?: (event.getChild() as? XmlFile)
|
|
||||||
if (file != null) {
|
|
||||||
val project = file.getProject()
|
|
||||||
|
|
||||||
val projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex()
|
val projectFileIndex = ProjectRootManager.getInstance(xmlFile.project).fileIndex
|
||||||
val module = projectFileIndex.getModuleForFile(file.getVirtualFile())
|
val module = projectFileIndex.getModuleForFile(xmlFile.virtualFile)
|
||||||
if (module != null) {
|
|
||||||
val resourceManager = AndroidLayoutXmlFileManager.getInstance(module)
|
|
||||||
val resDirectories = resourceManager.getModuleResDirectories()
|
|
||||||
val baseDirectory = file.getParent()?.getParent()?.getVirtualFile()
|
|
||||||
|
|
||||||
// File from the res/ directory was modified
|
if (module != null) {
|
||||||
if (baseDirectory in resDirectories && file.isLayoutXmlFile()) {
|
val resourceManager = AndroidLayoutXmlFileManager.getInstance(module)
|
||||||
incModificationCount()
|
val resDirectories = resourceManager.getModuleResDirectories()
|
||||||
}
|
val baseDirectory = xmlFile.parent?.parent?.virtualFile
|
||||||
|
|
||||||
|
if (baseDirectory in resDirectories && xmlFile.isLayoutXmlFile()) {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findXmlAttribute(element: PsiElement?): XmlAttribute? {
|
||||||
|
return when (element) {
|
||||||
|
is XmlToken, is XmlAttributeValue -> findXmlAttribute(element.parent)
|
||||||
|
is XmlAttribute -> element
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun AndroidLayoutXmlFileManager.getModuleResDirectories(): List<VirtualFile> {
|
||||||
|
val info = androidModuleInfo ?: return listOf()
|
||||||
|
|
||||||
|
val fileManager = VirtualFileManager.getInstance()
|
||||||
|
return info.resDirectories.map { fileManager.findFileByUrl("file://$it") }.filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiFile.isLayoutXmlFile(): Boolean {
|
||||||
|
if (fileType != XmlFileType.INSTANCE) return false
|
||||||
|
return parent?.name?.startsWith("layout") ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun AndroidLayoutXmlFileManager.getModuleResDirectories(): List<VirtualFile> {
|
|
||||||
val info = androidModuleInfo ?: return listOf()
|
|
||||||
|
|
||||||
val fileManager = VirtualFileManager.getInstance()
|
|
||||||
return info.resDirectories.map { fileManager.findFileByUrl("file://" + it)!! }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiFile.isLayoutXmlFile(): Boolean {
|
|
||||||
if (getFileType() != XmlFileType.INSTANCE) return false
|
|
||||||
return getParent()?.getName()?.startsWith("layout") ?: false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user