Move PsiElement.getElementTextWithContext to psi module with small adjustments
* replace existing function (the new one makes it more clear which element was printed) * prints position for element * handles invalid psi element
This commit is contained in:
committed by
Space Team
parent
4b3bff3344
commit
c5014d4765
@@ -5,31 +5,51 @@
|
||||
|
||||
package org.jetbrains.kotlin.utils
|
||||
|
||||
import com.intellij.injected.editor.VirtualFileWindow
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
|
||||
fun getElementTextWithContext(psiElement: PsiElement): String {
|
||||
if (!psiElement.isValid) return "<invalid element $psiElement>"
|
||||
|
||||
if (psiElement is PsiFile) {
|
||||
return psiElement.containingFile.text
|
||||
}
|
||||
|
||||
// Find parent for element among file children
|
||||
val topLevelElement = PsiTreeUtil.findFirstParent(psiElement) { it.parent is PsiFile }
|
||||
?: throw AssertionError("For non-file element we should always be able to find parent in file children")
|
||||
|
||||
val startContextOffset = topLevelElement.textRange.startOffset
|
||||
val elementContextOffset = psiElement.textRange.startOffset
|
||||
|
||||
val inFileParentOffset = elementContextOffset - startContextOffset
|
||||
|
||||
|
||||
@Suppress("LocalVariableName") val ELEMENT_TAG = "ELEMENT"
|
||||
val containingFile = psiElement.containingFile
|
||||
val isInjected = containingFile is VirtualFileWindow
|
||||
return StringBuilder(topLevelElement.text)
|
||||
.insert(inFileParentOffset, "<caret>")
|
||||
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
||||
.toString()
|
||||
val context = psiElement.parentOfType("KtImportDirective")
|
||||
?: psiElement.parentOfType("KtPackageDirective")
|
||||
?: psiElement.parentOfType("KtDeclarationWithBody", "KtClassOrObject", "KtScript")
|
||||
?: psiElement.parentOfType("KtProperty")
|
||||
?: containingFile
|
||||
val elementTextInContext = buildString {
|
||||
context.accept(object : PsiElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (element === psiElement) append("<$ELEMENT_TAG>")
|
||||
if (element is LeafPsiElement) {
|
||||
append(element.text)
|
||||
} else {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
if (element === psiElement) append("</$ELEMENT_TAG>")
|
||||
}
|
||||
})
|
||||
}.trimIndent().trim()
|
||||
|
||||
return buildString {
|
||||
appendLine("<File name: ${containingFile.name}, Physical: ${containingFile.isPhysical}>")
|
||||
append(elementTextInContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.parentOfType(vararg psiClassNames: String): PsiElement? {
|
||||
fun acceptsClass(javaClass: Class<*>): Boolean {
|
||||
if (javaClass.simpleName in psiClassNames) return true
|
||||
javaClass.superclass?.let { if (acceptsClass(it)) return true }
|
||||
for (superInterface in javaClass.interfaces) {
|
||||
if (acceptsClass(superInterface)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return generateSequence(this) { it.parent }
|
||||
.filter { it !is PsiFile }
|
||||
.firstOrNull { acceptsClass(it::class.java) }
|
||||
}
|
||||
Reference in New Issue
Block a user