diff --git a/src/main/kotlin/com/github/tempest/framework/views/injection/PHPLanguageInjector.kt b/src/main/kotlin/com/github/tempest/framework/views/injection/PHPLanguageInjector.kt index 422aee9..2db9dbf 100644 --- a/src/main/kotlin/com/github/tempest/framework/views/injection/PHPLanguageInjector.kt +++ b/src/main/kotlin/com/github/tempest/framework/views/injection/PHPLanguageInjector.kt @@ -1,5 +1,6 @@ package com.github.tempest.framework.views.injection +import com.github.tempest.framework.TempestFrameworkUtil import com.intellij.lang.injection.MultiHostInjector import com.intellij.lang.injection.MultiHostRegistrar import com.intellij.lang.tree.util.children @@ -8,75 +9,83 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiLanguageInjectionHost import com.intellij.psi.html.HtmlTag import com.intellij.psi.impl.source.html.HtmlRawTextImpl +import com.intellij.psi.impl.source.xml.XmlAttributeValueImpl +import com.intellij.psi.impl.source.xml.XmlTextImpl +import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.xml.XmlAttribute -import com.intellij.psi.xml.XmlAttributeValue -import com.intellij.psi.xml.XmlText import com.intellij.psi.xml.XmlToken import com.jetbrains.php.lang.PhpLanguage +import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment class PHPLanguageInjector : MultiHostInjector { - val tagsMap = mapOf( - "{!!" to "!!}", - "{{" to "}}", - ) + companion object { + private val templateTags = mapOf( + "{!!" to "!!}", + "{{" to "}}", + ) + } - override fun getLanguagesToInject( - registrar: MultiHostRegistrar, - element: PsiElement - ) { - when (element) { - is XmlAttributeValue -> { - val attribute = element.parent as? XmlAttribute ?: return + override fun elementsToInjectIn() = listOf( + XmlAttributeValueImpl::class.java, + XmlTextImpl::class.java, + HtmlTag::class.java, + ) - if (!attribute.name.startsWith(':')) return + override fun getLanguagesToInject(registrar: MultiHostRegistrar, element: PsiElement) { + val file = element.containingFile ?: return + if (!file.name.endsWith(TempestFrameworkUtil.TEMPLATE_SUFFIX)) return - val injectableHost = element as? PsiLanguageInjectionHost ?: return + when (element) { + is XmlAttributeValueImpl -> injectIntoAttribute(element, registrar) + is XmlTextImpl -> injectIntoText(element, registrar) + is HtmlTag -> injectIntoHtmlTag(element, registrar) + } + } - registrar - .startInjecting(PhpLanguage.INSTANCE ?: return) - .addPlace("", injectableHost, TextRange(0, injectableHost.textLength)) - .doneInjecting() - } + private fun injectIntoAttribute(element: XmlAttributeValueImpl, registrar: MultiHostRegistrar) { + val attribute = element.parent as? XmlAttribute ?: return + if (!attribute.name.startsWith(':')) return - is HtmlTag -> { - element.children - .mapNotNull { it as? HtmlRawTextImpl } - .forEach { child -> - injectIntoText(HtmlTextInjectionHostWrapper(child), registrar) - } - } + val variableDeclarations = collectVariableDeclarations(element) + registrar + .startInjecting(PhpLanguage.INSTANCE) + .addPlace("$variableDeclarations", element, element.textRange.shiftLeft(element.startOffset)) + .doneInjecting() + } - is XmlText -> { -// println("element: ${element.text}, ${element.javaClass.name} ${element is PsiLanguageInjectionHost}") - val injectableHost = element as? PsiLanguageInjectionHost ?: return - injectIntoText(injectableHost, registrar) - } - } + private fun injectIntoHtmlTag(element: HtmlTag, registrar: MultiHostRegistrar) { + element.children + .filterIsInstance() + .forEach { injectIntoText(HtmlTextInjectionHostWrapper(it), registrar) } } - private fun injectIntoText( - element: PsiLanguageInjectionHost, - registrar: MultiHostRegistrar - ) { - val children = element.node.children().toList() + private fun injectIntoText(element: PsiLanguageInjectionHost, registrar: MultiHostRegistrar) { + val tokens = element.node.children() .filter { it is XmlToken } - .apply { if (size < 2) return } + .toList() + .takeIf { it.size >= 2 } ?: return + + val openTag = tokens.find { it.text in templateTags }?.psi ?: return + val closeTag = tokens.find { it.text == templateTags[openTag.text] }?.psi ?: return + val range = TextRange(openTag.textRangeInParent.endOffset, closeTag.startOffsetInParent) -// println("children: $children") - val openTag = children.find { tagsMap.containsKey(it.text) }?.psi ?: return - val closeTag = children.find { it.text == tagsMap[openTag.text] }?.psi ?: return + val variableDeclarations = collectVariableDeclarations(element) -// println("openTag: ${openTag.text}, closeTag: ${closeTag?.text}") - val textRange = TextRange(openTag.textRangeInParent.endOffset, closeTag.startOffsetInParent) -// println("injecting ${language} into $element, $textRange") - registrar.startInjecting(PhpLanguage.INSTANCE) - .addPlace("", element, textRange) + registrar + .startInjecting(PhpLanguage.INSTANCE) + .addPlace("$variableDeclarations", element, range) .doneInjecting() } - override fun elementsToInjectIn() = listOf( - XmlAttributeValue::class.java, - XmlText::class.java, - HtmlTag::class.java, - ) + private fun collectVariableDeclarations(element: PsiElement): String? { + val file = element.containingFile ?: return null + + val searchFile = file.viewProvider.getPsi(PhpLanguage.INSTANCE) ?: file + val variableDeclarations = PsiTreeUtil.findChildrenOfType(searchFile, PhpDocComment::class.java) + .filter { "@var" in it.text } + .joinToString("\n") { it.text } + .ifEmpty { return null } + + return "" + } } \ No newline at end of file