fix xml resolving
- replace VirtualFileListener based approach with direct PsiFile reading
This commit is contained in:
committed by
Yan Zhulanow
parent
35b1cb4fc7
commit
c24fccc659
+30
-13
@@ -40,6 +40,13 @@ import org.xml.sax.helpers.DefaultHandler
|
|||||||
import org.xml.sax.Attributes
|
import org.xml.sax.Attributes
|
||||||
import org.jetbrains.kotlin.resolve.android.AndroidConst.*
|
import org.jetbrains.kotlin.resolve.android.AndroidConst.*
|
||||||
import com.intellij.psi.PsiFileFactory
|
import com.intellij.psi.PsiFileFactory
|
||||||
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
|
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
||||||
|
import java.util.Queue
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import org.xml.sax.InputSource
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import com.intellij.openapi.diagnostic.Log
|
||||||
|
|
||||||
abstract class AndroidUIXmlParser {
|
abstract class AndroidUIXmlParser {
|
||||||
|
|
||||||
@@ -53,18 +60,18 @@ abstract class AndroidUIXmlParser {
|
|||||||
"android.view.View",
|
"android.view.View",
|
||||||
"android.widget.*")
|
"android.widget.*")
|
||||||
|
|
||||||
abstract val searchPath: String?
|
protected abstract val searchPath: String?
|
||||||
abstract val androidAppPackage: String
|
protected abstract val androidAppPackage: String
|
||||||
|
|
||||||
val saxParser = initSAX()
|
private val saxParser = initSAX()
|
||||||
|
|
||||||
val fileCache = HashMap<VirtualFile, String>()
|
private val fileCache = HashMap<PsiFile, String>()
|
||||||
var lastCachedPsi: JetFile? = null
|
private var lastCachedPsi: JetFile? = null
|
||||||
val fileModificationTime = HashMap<VirtualFile, Long>()
|
private val fileModificationTime = HashMap<PsiFile, Long>()
|
||||||
|
|
||||||
val filesToProcess = ConcurrentLinkedQueue<VirtualFile>()
|
protected val filesToProcess: Queue<PsiFile> = ConcurrentLinkedQueue()
|
||||||
var listenerSetUp = false
|
protected var listenerSetUp: Boolean = false
|
||||||
volatile var invalidateCaches = false
|
protected volatile var invalidateCaches: Boolean = false
|
||||||
|
|
||||||
public fun parseToString(): String? {
|
public fun parseToString(): String? {
|
||||||
val cacheState = doParse()
|
val cacheState = doParse()
|
||||||
@@ -73,6 +80,7 @@ abstract class AndroidUIXmlParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun parseToPsi(project: Project): JetFile? {
|
public fun parseToPsi(project: Project): JetFile? {
|
||||||
|
populateQueue(project)
|
||||||
val cacheState = doParse()
|
val cacheState = doParse()
|
||||||
if (cacheState == null) return null
|
if (cacheState == null) return null
|
||||||
return if (cacheState == CacheAction.MISS || lastCachedPsi == null) {
|
return if (cacheState == CacheAction.MISS || lastCachedPsi == null) {
|
||||||
@@ -126,7 +134,7 @@ abstract class AndroidUIXmlParser {
|
|||||||
return kw
|
return kw
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseSingleFileWithCache(file: VirtualFile): Pair<String, CacheAction> {
|
private fun parseSingleFileWithCache(file: PsiFile): Pair<String, CacheAction> {
|
||||||
val lastRecorded = fileModificationTime[file] ?: -1
|
val lastRecorded = fileModificationTime[file] ?: -1
|
||||||
if (file.getModificationStamp() > lastRecorded)
|
if (file.getModificationStamp() > lastRecorded)
|
||||||
return Pair(parseSingleFile(file), CacheAction.MISS)
|
return Pair(parseSingleFile(file), CacheAction.MISS)
|
||||||
@@ -134,17 +142,19 @@ abstract class AndroidUIXmlParser {
|
|||||||
return Pair(fileCache[file]!!, CacheAction.HIT)
|
return Pair(fileCache[file]!!, CacheAction.HIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseSingleFile(file: VirtualFile): String {
|
private fun parseSingleFile(file: PsiFile): String {
|
||||||
val ids: MutableCollection<AndroidWidget> = ArrayList()
|
val ids: MutableCollection<AndroidWidget> = ArrayList()
|
||||||
val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })
|
val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })
|
||||||
fileModificationTime[file] = file.getModificationStamp()
|
fileModificationTime[file] = file.getModificationStamp()
|
||||||
try {
|
try {
|
||||||
saxParser.parse(file.getInputStream()!!, handler)
|
val source = InputSource(ByteArrayInputStream(file.getText()!!.getBytes("utf-8")))
|
||||||
|
saxParser.parse(source, handler)
|
||||||
val res = produceKotlinProperties(KotlinStringWriter(), ids).toString()
|
val res = produceKotlinProperties(KotlinStringWriter(), ids).toString()
|
||||||
fileCache[file] = res
|
fileCache[file] = res
|
||||||
return res
|
return res
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
fileCache[file] = ""
|
Log.print(e.getMessage())
|
||||||
|
invalidateCaches()
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,6 +187,13 @@ abstract class AndroidUIXmlParser {
|
|||||||
invalidateCaches = false
|
invalidateCaches = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun populateQueue(project: Project) {
|
||||||
|
val fileManager = VirtualFileManager.getInstance()
|
||||||
|
val watchDir = fileManager.findFileByUrl("file://" + searchPath)
|
||||||
|
val psiManager = PsiManager.getInstance(project)
|
||||||
|
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList()?.map { psiManager.findFile(it) } ?.mapNotNull { it })
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun lazySetup()
|
protected abstract fun lazySetup()
|
||||||
|
|
||||||
protected fun readManifest(): AndroidManifest {
|
protected fun readManifest(): AndroidManifest {
|
||||||
|
|||||||
+1
-3
@@ -25,9 +25,7 @@ class CliAndroidUIXmlParser(val project: Project, override val searchPath: Strin
|
|||||||
override var androidAppPackage: String = ""
|
override var androidAppPackage: String = ""
|
||||||
|
|
||||||
override fun lazySetup() {
|
override fun lazySetup() {
|
||||||
val fileManager = VirtualFileManager.getInstance()
|
populateQueue(project)
|
||||||
val watchDir = fileManager.findFileByUrl("file://" + searchPath)
|
|
||||||
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0))
|
|
||||||
androidAppPackage = readManifest()._package
|
androidAppPackage = readManifest()._package
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,34 +23,14 @@ import java.util.ArrayList
|
|||||||
import com.intellij.openapi.vfs.VirtualFileAdapter
|
import com.intellij.openapi.vfs.VirtualFileAdapter
|
||||||
import com.intellij.openapi.vfs.VirtualFileEvent
|
import com.intellij.openapi.vfs.VirtualFileEvent
|
||||||
|
|
||||||
class IDEAndroidUIXmlParser(project: Project): AndroidUIXmlParser() {
|
class IDEAndroidUIXmlParser(val project: Project): AndroidUIXmlParser() {
|
||||||
override val searchPath: String? = project.getBasePath() + "/res/layout/"
|
override val searchPath: String? = project.getBasePath() + "/res/layout/"
|
||||||
override var androidAppPackage: String = ""
|
override var androidAppPackage: String = ""
|
||||||
|
|
||||||
override protected fun lazySetup() {
|
override protected fun lazySetup() {
|
||||||
if (listenerSetUp) return
|
if (listenerSetUp) return
|
||||||
androidAppPackage = readManifest()._package
|
androidAppPackage = readManifest()._package
|
||||||
val fileManager = VirtualFileManager.getInstance()
|
populateQueue(project)
|
||||||
val watchDir = fileManager.findFileByUrl("file://" + searchPath)
|
|
||||||
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0))
|
|
||||||
fileManager.addVirtualFileListener(object : VirtualFileAdapter() {
|
|
||||||
override fun contentsChanged(event: VirtualFileEvent) {
|
|
||||||
if (event.getParent() == watchDir)
|
|
||||||
filesToProcess.add(event.getFile())
|
|
||||||
}
|
|
||||||
override fun fileCreated(event: VirtualFileEvent) {
|
|
||||||
if (event.getParent() == watchDir)
|
|
||||||
super<VirtualFileAdapter>.fileCreated(event)
|
|
||||||
}
|
|
||||||
override fun fileDeleted(event: VirtualFileEvent) {
|
|
||||||
if (event.getParent() == watchDir) {
|
|
||||||
// ignore potential synchronisation issues - it doesn't really matter if invalidation and
|
|
||||||
// file processing will be handled in different passes
|
|
||||||
invalidateCaches = true
|
|
||||||
filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
listenerSetUp = true
|
listenerSetUp = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user