Skip to content

Commit c7110e2

Browse files
committed
refactor: make php language injector play nice with phpdocs
1 parent ab02b52 commit c7110e2

File tree

1 file changed

+49
-42
lines changed

1 file changed

+49
-42
lines changed
Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.tempest.framework.views.injection
22

3+
import com.github.tempest.framework.TempestFrameworkUtil
34
import com.intellij.lang.injection.MultiHostInjector
45
import com.intellij.lang.injection.MultiHostRegistrar
56
import com.intellij.lang.tree.util.children
@@ -8,69 +9,59 @@ import com.intellij.psi.PsiElement
89
import com.intellij.psi.PsiLanguageInjectionHost
910
import com.intellij.psi.html.HtmlTag
1011
import com.intellij.psi.impl.source.html.HtmlRawTextImpl
12+
import com.intellij.psi.util.PsiTreeUtil
1113
import com.intellij.psi.xml.XmlAttribute
1214
import com.intellij.psi.xml.XmlAttributeValue
1315
import com.intellij.psi.xml.XmlText
1416
import com.intellij.psi.xml.XmlToken
1517
import com.jetbrains.php.lang.PhpLanguage
18+
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment
1619

1720
class PHPLanguageInjector : MultiHostInjector {
18-
val tagsMap = mapOf(
21+
private val templateTags = mapOf(
1922
"{!!" to "!!}",
2023
"{{" to "}}",
2124
)
2225

23-
override fun getLanguagesToInject(
24-
registrar: MultiHostRegistrar,
25-
element: PsiElement
26-
) {
26+
override fun getLanguagesToInject(registrar: MultiHostRegistrar, element: PsiElement) {
2727
when (element) {
28-
is XmlAttributeValue -> {
29-
val attribute = element.parent as? XmlAttribute ?: return
30-
31-
if (!attribute.name.startsWith(':')) return
28+
is XmlAttributeValue -> injectIntoAttribute(element, registrar)
29+
is HtmlTag -> injectIntoHtmlTag(element, registrar)
30+
is XmlText -> (element as? PsiLanguageInjectionHost)?.let { injectIntoText(it, registrar) }
31+
}
32+
}
3233

33-
val injectableHost = element as? PsiLanguageInjectionHost ?: return
34+
private fun injectIntoAttribute(element: XmlAttributeValue, registrar: MultiHostRegistrar) {
35+
val attribute = element.parent as? XmlAttribute ?: return
36+
if (!attribute.name.startsWith(':')) return
3437

35-
registrar
36-
.startInjecting(PhpLanguage.INSTANCE ?: return)
37-
.addPlace("<?=", "?>", injectableHost, TextRange(0, injectableHost.textLength))
38-
.doneInjecting()
39-
}
38+
val host = element as? PsiLanguageInjectionHost ?: return
4039

41-
is HtmlTag -> {
42-
element.children
43-
.mapNotNull { it as? HtmlRawTextImpl }
44-
.forEach { child ->
45-
injectIntoText(HtmlTextInjectionHostWrapper(child), registrar)
46-
}
47-
}
40+
registrar
41+
.startInjecting(PhpLanguage.INSTANCE)
42+
.addPlace(getVarDeclarationsPrefix(element), "?>", host, TextRange(0, host.textLength))
43+
.doneInjecting()
44+
}
4845

49-
is XmlText -> {
50-
// println("element: ${element.text}, ${element.javaClass.name} ${element is PsiLanguageInjectionHost}")
51-
val injectableHost = element as? PsiLanguageInjectionHost ?: return
52-
injectIntoText(injectableHost, registrar)
53-
}
54-
}
46+
private fun injectIntoHtmlTag(element: HtmlTag, registrar: MultiHostRegistrar) {
47+
element.children
48+
.filterIsInstance<HtmlRawTextImpl>()
49+
.forEach { injectIntoText(HtmlTextInjectionHostWrapper(it), registrar) }
5550
}
5651

57-
private fun injectIntoText(
58-
element: PsiLanguageInjectionHost,
59-
registrar: MultiHostRegistrar
60-
) {
61-
val children = element.node.children().toList()
52+
private fun injectIntoText(element: PsiLanguageInjectionHost, registrar: MultiHostRegistrar) {
53+
val tokens = element.node.children()
6254
.filter { it is XmlToken }
63-
.apply { if (size < 2) return }
55+
.toList()
56+
.takeIf { it.size >= 2 } ?: return
6457

65-
// println("children: $children")
66-
val openTag = children.find { tagsMap.containsKey(it.text) }?.psi ?: return
67-
val closeTag = children.find { it.text == tagsMap[openTag.text] }?.psi ?: return
58+
val openTag = tokens.find { it.text in templateTags }?.psi ?: return
59+
val closeTag = tokens.find { it.text == templateTags[openTag.text] }?.psi ?: return
60+
val range = TextRange(openTag.textRangeInParent.endOffset, closeTag.startOffsetInParent)
6861

69-
// println("openTag: ${openTag.text}, closeTag: ${closeTag?.text}")
70-
val textRange = TextRange(openTag.textRangeInParent.endOffset, closeTag.startOffsetInParent)
71-
// println("injecting ${language} into $element, $textRange")
72-
registrar.startInjecting(PhpLanguage.INSTANCE)
73-
.addPlace("<?=", "?>", element, textRange)
62+
registrar
63+
.startInjecting(PhpLanguage.INSTANCE)
64+
.addPlace(getVarDeclarationsPrefix(element), "?>", element, range)
7465
.doneInjecting()
7566
}
7667

@@ -79,4 +70,20 @@ class PHPLanguageInjector : MultiHostInjector {
7970
XmlText::class.java,
8071
HtmlTag::class.java,
8172
)
73+
74+
private fun getVarDeclarationsPrefix(element: PsiElement): String {
75+
val file = element.containingFile ?: return DEFAULT_PREFIX
76+
if (!file.name.endsWith(TempestFrameworkUtil.TEMPLATE_SUFFIX)) return DEFAULT_PREFIX
77+
78+
val searchFile = file.viewProvider.getPsi(PhpLanguage.INSTANCE) ?: file
79+
val varDeclarations = PsiTreeUtil.findChildrenOfType(searchFile, PhpDocComment::class.java)
80+
.filter { "@var" in it.text }
81+
.joinToString(" ") { it.text }
82+
83+
return if (varDeclarations.isEmpty()) DEFAULT_PREFIX else "<?php $varDeclarations ?>$DEFAULT_PREFIX"
84+
}
85+
86+
companion object {
87+
private const val DEFAULT_PREFIX = "<?="
88+
}
8289
}

0 commit comments

Comments
 (0)