@@ -3,28 +3,30 @@ package com.github.tempest.framework.views.references
33import com.github.tempest.framework.php.getPhpViewVariables
44import com.intellij.codeInsight.completion.InsertionContext
55import com.intellij.codeInsight.completion.XmlAttributeInsertHandler
6+ import com.intellij.openapi.util.text.StringUtil
7+ import com.intellij.psi.PsiElementResolveResult
68import com.intellij.psi.PsiPolyVariantReferenceBase
79import com.intellij.psi.ResolveResult
810import com.intellij.psi.html.HtmlTag
911import com.intellij.psi.xml.XmlAttribute
12+ import com.intellij.webSymbols.utils.NameCaseUtils
1013import com.jetbrains.php.completion.PhpLookupElement
1114import com.jetbrains.php.lang.psi.PhpFile
1215
1316class TempestAttributeReference (element : XmlAttribute , private val htmlTag : HtmlTag ) :
14- PsiPolyVariantReferenceBase <XmlAttribute >(element, element.nameElement.textRangeInParent ) {
17+ PsiPolyVariantReferenceBase <XmlAttribute >(element) {
1518 override fun getVariants (): Array <out Any > {
1619 val fileReferences = htmlTag.references.filter { it is Immediate <* > }
1720
18- val lookupPrefix = element.text.commonPrefixWith(" ::" )
19-
2021 return fileReferences
2122 .mapNotNull { it.resolve() as ? PhpFile }
2223 .flatMap { it.getPhpViewVariables() }
2324 .flatMap {
25+ val attributeName = it.name.toKebabCase()
2426 listOf (
2527 object : PhpLookupElement (it) {
26- override fun getLookupString () = lookupPrefix + lookupString
27- override fun getAllLookupStrings () = setOf (lookupPrefix + lookupString )
28+ override fun getLookupString () = attributeName
29+ override fun getAllLookupStrings () = setOf (attributeName )
2830 override fun handleInsert (context : InsertionContext ) {
2931 XmlAttributeInsertHandler .INSTANCE .handleInsert(context, this )
3032 }
@@ -34,12 +36,37 @@ class TempestAttributeReference(element: XmlAttribute, private val htmlTag: Html
3436 .toTypedArray()
3537 }
3638
37- override fun multiResolve (incompleteCode : Boolean ): Array <out ResolveResult ?> {
38- // println("resolve ${element.text} for ${htmlTag.name}")
39- // println("range ${element.textRangeInParent} ${element.textRange}")
39+ override fun multiResolve (incompleteCode : Boolean ): Array <out ResolveResult > {
40+ val originalName = rangeInElement.substring(element.name)
41+
42+ // handle camelCaseVariables, they're wrongly cased
43+ if (originalName.inCamelCase()) return ResolveResult .EMPTY_ARRAY
44+
45+ val fileReferences = htmlTag.references.filter { it is Immediate <* > }
46+
47+ val lookupVariable = originalName.toCamelCase()
48+
49+ // println("lookupVariable $lookupVariable fileReferences $fileReferences")
50+ // println("element: ${element} (${element.text}) rangeInParent: ${rangeInElement}")
4051
41- return emptyArray()
52+ // todo: there's a bug with attributes started with ":", VueJS webTypes filter references under such attributes
53+ return fileReferences
54+ .mapNotNull { it.resolve() as ? PhpFile }
55+ .flatMap { it.getPhpViewVariables() }
56+ .filter { it.name == lookupVariable }
57+ // .apply { println("variants $this") }
58+ .run { PsiElementResolveResult .createResults(this ) }
59+ // .apply { println("resolve $lookupVariable ${this.joinToString { it.element.toString() }}") }
4260 }
4361
4462 override fun isSoft () = ! element.name.startsWith(" :" )
45- }
63+
64+ override fun getRangeInElement () = when {
65+ element.name.startsWith(" :" ) -> element.nameElement.textRangeInParent.shiftRight(1 ).grown(- 1 )
66+ else -> element.nameElement.textRangeInParent
67+ }
68+ }
69+
70+ fun String.toCamelCase () = NameCaseUtils .toCamelCase(this )
71+ fun String.toKebabCase () = NameCaseUtils .toKebabCase(this )
72+ fun String.inCamelCase () = StringUtil .hasUpperCaseChar(this ) && this != NameCaseUtils .toKebabCase(this )
0 commit comments