replace sax with psi based android ui xml parsing in plugin
This commit is contained in:
+18
-24
@@ -47,6 +47,8 @@ import com.intellij.psi.PsiFile
|
||||
import org.xml.sax.InputSource
|
||||
import java.io.ByteArrayInputStream
|
||||
import com.intellij.openapi.diagnostic.Log
|
||||
import org.xml.sax.SAXException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
|
||||
abstract class AndroidUIXmlParser {
|
||||
|
||||
@@ -63,15 +65,22 @@ abstract class AndroidUIXmlParser {
|
||||
protected abstract val searchPath: String?
|
||||
protected abstract val androidAppPackage: String
|
||||
|
||||
private val saxParser = initSAX()
|
||||
protected val saxParser: SAXParser = initSAX()
|
||||
|
||||
protected fun initSAX(): SAXParser {
|
||||
val saxFactory = SAXParserFactory.newInstance()
|
||||
saxFactory?.setNamespaceAware(true)
|
||||
return saxFactory!!.newSAXParser()
|
||||
}
|
||||
|
||||
private val fileCache = HashMap<PsiFile, String>()
|
||||
private var lastCachedPsi: JetFile? = null
|
||||
private val fileModificationTime = HashMap<PsiFile, Long>()
|
||||
protected val fileModificationTime: HashMap<PsiFile, Long> = HashMap()
|
||||
|
||||
protected val filesToProcess: Queue<PsiFile> = ConcurrentLinkedQueue()
|
||||
protected var listenerSetUp: Boolean = false
|
||||
protected volatile var invalidateCaches: Boolean = false
|
||||
|
||||
protected val LOG: Logger = Logger.getInstance(this.javaClass)
|
||||
|
||||
public fun parseToString(): String? {
|
||||
val cacheState = doParse()
|
||||
@@ -102,11 +111,6 @@ abstract class AndroidUIXmlParser {
|
||||
return file.extension == "xml"
|
||||
}
|
||||
|
||||
private fun initSAX(): SAXParser {
|
||||
val saxFactory = SAXParserFactory.newInstance()
|
||||
saxFactory?.setNamespaceAware(true)
|
||||
return saxFactory!!.newSAXParser()
|
||||
}
|
||||
|
||||
private fun searchForUIXml(path: String): Collection<File> {
|
||||
return searchForUIXml(arrayListOf(File(path)))
|
||||
@@ -143,26 +147,17 @@ abstract class AndroidUIXmlParser {
|
||||
}
|
||||
|
||||
private fun parseSingleFile(file: PsiFile): String {
|
||||
val ids: MutableCollection<AndroidWidget> = ArrayList()
|
||||
val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })
|
||||
val res = parseSingleFileImpl(file)
|
||||
fileModificationTime[file] = file.getModificationStamp()
|
||||
try {
|
||||
val source = InputSource(ByteArrayInputStream(file.getText()!!.getBytes("utf-8")))
|
||||
saxParser.parse(source, handler)
|
||||
val res = produceKotlinProperties(KotlinStringWriter(), ids).toString()
|
||||
fileCache[file] = res
|
||||
return res
|
||||
} catch (e: Exception) {
|
||||
Log.print(e.getMessage())
|
||||
invalidateCaches()
|
||||
return ""
|
||||
}
|
||||
fileCache[file] = res
|
||||
return res
|
||||
}
|
||||
|
||||
abstract fun parseSingleFileImpl(file: PsiFile): String
|
||||
|
||||
private fun doParse(): CacheAction? {
|
||||
if (searchPath == null || searchPath == "") return null
|
||||
lazySetup()
|
||||
if (invalidateCaches) invalidateCaches()
|
||||
var overallCacheMiss = false
|
||||
var file = filesToProcess.poll()
|
||||
while (file != null) {
|
||||
@@ -184,7 +179,6 @@ abstract class AndroidUIXmlParser {
|
||||
fileCache.clear()
|
||||
fileModificationTime.clear()
|
||||
lastCachedPsi = null
|
||||
invalidateCaches = false
|
||||
}
|
||||
|
||||
protected fun populateQueue(project: Project) {
|
||||
@@ -216,7 +210,7 @@ abstract class AndroidUIXmlParser {
|
||||
}
|
||||
}
|
||||
|
||||
private fun produceKotlinProperties(kw: KotlinStringWriter, ids: Collection<AndroidWidget>): StringBuffer {
|
||||
protected fun produceKotlinProperties(kw: KotlinStringWriter, ids: Collection<AndroidWidget>): StringBuffer {
|
||||
for (id in ids) {
|
||||
val body = arrayListOf("return findViewById(0) as ${id.className}")
|
||||
kw.writeImmutableExtensionProperty(receiver = "Activity",
|
||||
|
||||
+19
@@ -19,14 +19,33 @@ package org.jetbrains.jet.lang.resolve.android
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import java.util.ArrayList
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import java.io.ByteArrayInputStream
|
||||
import org.xml.sax.InputSource
|
||||
import javax.xml.parsers.SAXParser
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
|
||||
class CliAndroidUIXmlParser(val project: Project, override val searchPath: String?): AndroidUIXmlParser() {
|
||||
|
||||
override var androidAppPackage: String = ""
|
||||
|
||||
|
||||
override fun lazySetup() {
|
||||
populateQueue(project)
|
||||
androidAppPackage = readManifest()._package
|
||||
}
|
||||
|
||||
override fun parseSingleFileImpl(file: PsiFile): String {
|
||||
val ids: MutableCollection<AndroidWidget> = ArrayList()
|
||||
val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })
|
||||
try {
|
||||
val source = InputSource(ByteArrayInputStream(file.getText()!!.getBytes("utf-8")))
|
||||
saxParser.parse(source, handler)
|
||||
return produceKotlinProperties(KotlinStringWriter(), ids).toString()
|
||||
} catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.android
|
||||
|
||||
import com.intellij.psi.XmlElementVisitor
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.xml.XmlElement
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
|
||||
class AndroidXmlVisitor(val elementCallback: (String, String)-> Unit): XmlElementVisitor() {
|
||||
|
||||
override fun visitElement(element: PsiElement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitXmlElement(element: XmlElement?) {
|
||||
element?.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitXmlTag(tag: XmlTag?) {
|
||||
val idPrefix = "@+id/"
|
||||
val attribute = tag?.getAttribute("android:id")
|
||||
if (attribute != null && attribute.getValue() != null) {
|
||||
elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName())
|
||||
}
|
||||
tag?.acceptChildren(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import java.util.ArrayList
|
||||
import com.intellij.openapi.vfs.VirtualFileAdapter
|
||||
import com.intellij.openapi.vfs.VirtualFileEvent
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.jet.lang.resolve.android.AndroidWidget
|
||||
import org.jetbrains.jet.lang.resolve.android.KotlinStringWriter
|
||||
|
||||
class IDEAndroidUIXmlParser(val project: Project): AndroidUIXmlParser() {
|
||||
override val searchPath: String? = project.getBasePath() + "/res/layout/"
|
||||
@@ -33,5 +36,11 @@ class IDEAndroidUIXmlParser(val project: Project): AndroidUIXmlParser() {
|
||||
populateQueue(project)
|
||||
listenerSetUp = true
|
||||
}
|
||||
|
||||
override fun parseSingleFileImpl(file: PsiFile): String {
|
||||
val ids: MutableCollection<AndroidWidget> = ArrayList()
|
||||
file.accept(AndroidXmlVisitor({ id, wClass -> ids.add(AndroidWidget(id, wClass))}))
|
||||
return produceKotlinProperties(KotlinStringWriter(), ids).toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user