mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 15:56:48 +08:00
Namespace based completion in attribute value completion provider
This commit is contained in:
+2
-2
@@ -43,8 +43,8 @@ interface ResourceTableRegistry : XmlRegistry<ResourceTable> {
|
||||
*
|
||||
* @param name The package name for the resource table.
|
||||
*/
|
||||
fun forPackage(name: String, vararg dirs: File): ResourceTable
|
||||
|
||||
fun forPackage(name: String, vararg dirs: File): ResourceTable?
|
||||
|
||||
/**
|
||||
* Remove the resource table entry for the given package name.
|
||||
*
|
||||
|
||||
+13
-12
@@ -42,31 +42,32 @@ internal object DefaultResourceTableRegistry : ResourceTableRegistry {
|
||||
private val tables = ConcurrentHashMap<String, ResourceTable>()
|
||||
private val platformTables = ConcurrentHashMap<String, ResourceTable>()
|
||||
|
||||
override fun forPackage(name: String, vararg dirs: File): ResourceTable {
|
||||
override fun forPackage(name: String, vararg dirs: File): ResourceTable? {
|
||||
|
||||
if (name == PCK_ANDROID) {
|
||||
return platformResourceTable(dirs.iterator().next())
|
||||
}
|
||||
|
||||
return tables[name]
|
||||
?: createTable(*dirs).also {
|
||||
?: createTable(*dirs)?.also {
|
||||
tables[name] = it
|
||||
it.packages.firstOrNull()?.name = name
|
||||
}
|
||||
}
|
||||
|
||||
private fun platformResourceTable(dir: File): ResourceTable {
|
||||
var table = platformTables[dir.path]
|
||||
if (table != null) {
|
||||
return table
|
||||
}
|
||||
|
||||
table = createTable(dir)
|
||||
platformTables[dir.path] = table
|
||||
return table
|
||||
private fun platformResourceTable(dir: File): ResourceTable? {
|
||||
return platformTables[dir.path]
|
||||
?: createTable(dir)?.also {
|
||||
platformTables[dir.path] = it
|
||||
it.packages.firstOrNull()?.name = PCK_ANDROID
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTable(vararg resDirs: File): ResourceTable {
|
||||
private fun createTable(vararg resDirs: File): ResourceTable? {
|
||||
if (resDirs.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
log.info("Creating resource table for resource directories $resDirs")
|
||||
|
||||
val logger = BlameLogger(IDELogger)
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ import org.eclipse.lemminx.dom.DOMDocument
|
||||
abstract class IXmlCompletionProvider {
|
||||
|
||||
companion object {
|
||||
const val NAMESPACE_PREFIX = "http://schemas.android.com/apk/res"
|
||||
const val NAMESPACE_PREFIX = "http://schemas.android.com/apk/res/"
|
||||
const val NAMESPACE_AUTO = "http://schemas.android.com/apk/res-auto"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+78
-31
@@ -24,14 +24,16 @@ import com.android.aapt.Resources.Attribute.FormatFlags.DIMENSION
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.ENUM
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.FLAGS
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.INTEGER
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.REFERENCE_VALUE
|
||||
import com.android.aapt.Resources.Attribute.FormatFlags.STRING
|
||||
import com.android.aaptcompiler.AaptResourceType
|
||||
import com.android.aaptcompiler.AaptResourceType.ATTR
|
||||
import com.android.aaptcompiler.AaptResourceType.BOOL
|
||||
import com.android.aaptcompiler.AaptResourceType.DIMEN
|
||||
import com.android.aaptcompiler.AaptResourceType.UNKNOWN
|
||||
import com.android.aaptcompiler.AttributeResource
|
||||
import com.android.aaptcompiler.ConfigDescription
|
||||
import com.android.aaptcompiler.ResourcePathData
|
||||
import com.android.aaptcompiler.ResourceTable
|
||||
import com.itsaky.androidide.aapt.findEntries
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem
|
||||
@@ -44,6 +46,7 @@ import com.itsaky.androidide.lsp.xml.providers.completion.IXmlCompletionProvider
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType
|
||||
import com.itsaky.androidide.lsp.xml.utils.XmlUtils.NodeType.ATTRIBUTE_VALUE
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
|
||||
import com.itsaky.androidide.xml.resources.ResourceTableRegistry.Companion.COMPLETION_FRAMEWORK_RES_LOOKUP_KEY
|
||||
import org.eclipse.lemminx.dom.DOMDocument
|
||||
|
||||
@@ -75,60 +78,73 @@ class AttrValueCompletionProvider : IXmlCompletionProvider() {
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
val attrs =
|
||||
Lookup.DEFAULT.lookup(COMPLETION_FRAMEWORK_RES_LOOKUP_KEY)
|
||||
?.findPackage("android")
|
||||
?.findGroup(ATTR)
|
||||
val namespace =
|
||||
attr.namespaceURI
|
||||
?: run {
|
||||
log.warn("Cannot get attributes list from resource table")
|
||||
log.warn("Unknown namespace for attribute", attr)
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
val entry =
|
||||
attrs.findEntry(attrName)?.findValue(ConfigDescription())?.value
|
||||
?: run {
|
||||
log.warn("Cannot find entry for attribute: $attrName")
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
if (entry !is AttributeResource) {
|
||||
val tables = findResourceTables(namespace)
|
||||
if (tables.isEmpty()) {
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
val list = mutableListOf<CompletionItem>()
|
||||
val pck = namespace.substringAfter(NAMESPACE_PREFIX)
|
||||
|
||||
if (entry.typeMask == REFERENCE_VALUE) {
|
||||
for (table in tables) {
|
||||
val attrs = table.findPackage(pck)?.findGroup(ATTR) ?: continue
|
||||
val entry = attrs.findEntry(attrName)?.findValue(ConfigDescription())?.value ?: continue
|
||||
if (entry !is AttributeResource) {
|
||||
continue
|
||||
}
|
||||
|
||||
addFromTable(table, entry, pck, prefix, list)
|
||||
}
|
||||
|
||||
return CompletionResult(list)
|
||||
}
|
||||
|
||||
private fun addFromTable(
|
||||
table: ResourceTable,
|
||||
entry: AttributeResource,
|
||||
pck: String,
|
||||
prefix: String,
|
||||
list: MutableList<CompletionItem>
|
||||
) {
|
||||
if (entry.typeMask == FormatFlags.REFERENCE_VALUE) {
|
||||
for (value in AaptResourceType.values()) {
|
||||
if (value == UNKNOWN) {
|
||||
continue
|
||||
}
|
||||
|
||||
addValues("android", value, prefix, list)
|
||||
addValues(table, pck, value, prefix, list)
|
||||
}
|
||||
} else {
|
||||
// Check for specific attribute formats
|
||||
if (entry.hasType(STRING)) {
|
||||
addValues("android", type = AaptResourceType.STRING, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = AaptResourceType.STRING, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(INTEGER)) {
|
||||
addValues("android", type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(COLOR)) {
|
||||
addValues("android", type = AaptResourceType.COLOR, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = AaptResourceType.COLOR, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(BOOLEAN)) {
|
||||
addValues("android", type = AaptResourceType.BOOL, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = BOOL, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(DIMENSION)) {
|
||||
addValues("android", type = AaptResourceType.DIMEN, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = DIMEN, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(INTEGER)) {
|
||||
addValues("android", type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
addValues(table, pck, type = AaptResourceType.INTEGER, prefix = prefix, result = list)
|
||||
}
|
||||
|
||||
if (entry.hasType(ENUM) || entry.hasType(FLAGS)) {
|
||||
@@ -139,32 +155,63 @@ class AttrValueCompletionProvider : IXmlCompletionProvider() {
|
||||
}
|
||||
|
||||
list.add(
|
||||
createEnumOrFlagCompletionItem(
|
||||
pck = "android",
|
||||
name = symbol.symbol.name.entry!!,
|
||||
matchLevel
|
||||
)
|
||||
createEnumOrFlagCompletionItem(pck = pck, name = symbol.symbol.name.entry!!, matchLevel)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CompletionResult(list)
|
||||
private fun findResourceTables(nsUri: String): Set<ResourceTable> {
|
||||
if (nsUri == NAMESPACE_AUTO) {
|
||||
return findAllModuleResourceTables()
|
||||
}
|
||||
|
||||
val pck = nsUri.substringAfter(NAMESPACE_PREFIX)
|
||||
if (pck.isBlank()) {
|
||||
log.warn("Invalid namespace: $nsUri")
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
if (pck == ResourceTableRegistry.PCK_ANDROID) {
|
||||
val platformResTable =
|
||||
Lookup.DEFAULT.lookup(COMPLETION_FRAMEWORK_RES_LOOKUP_KEY)
|
||||
?: run {
|
||||
log.debug("No platform resource table is set")
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
return setOf(platformResTable)
|
||||
}
|
||||
|
||||
val table =
|
||||
ResourceTableRegistry.getInstance().forPackage(pck)
|
||||
?: run {
|
||||
log.error("Cannot find resource table for package: $pck")
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
return setOf(table)
|
||||
}
|
||||
|
||||
private fun findAllModuleResourceTables(): Set<ResourceTable> {
|
||||
// TODO find all resource tables from completing file's module
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
private fun addValues(
|
||||
resources: ResourceTable,
|
||||
pck: String,
|
||||
type: AaptResourceType,
|
||||
prefix: String,
|
||||
result: MutableList<CompletionItem>
|
||||
) {
|
||||
val resources = Lookup.DEFAULT.lookup(COMPLETION_FRAMEWORK_RES_LOOKUP_KEY) ?: return
|
||||
val colors =
|
||||
val entries =
|
||||
resources.findPackage(pck)?.findGroup(type)?.findEntries {
|
||||
matchLevel(it, prefix) != NO_MATCH
|
||||
}
|
||||
?: return
|
||||
colors.forEach {
|
||||
entries.forEach {
|
||||
result.add(
|
||||
createAttrValueCompletionItem(pck, type.tagName, it.name, matchLevel(it.name, prefix))
|
||||
)
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user