WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<HtmlRawTextImpl>()
.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 "<?php $variableDeclarations ?>"
}
}
Loading