mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 21:00:56 +00:00
idea: enhance symbol support
This commit is contained in:
parent
87623505c0
commit
97283636bc
@ -0,0 +1,39 @@
|
|||||||
|
package gay.pizza.pork.idea
|
||||||
|
|
||||||
|
import com.intellij.model.Pointer
|
||||||
|
import com.intellij.model.Symbol
|
||||||
|
import com.intellij.navigation.ItemPresentation
|
||||||
|
import com.intellij.navigation.NavigatableSymbol
|
||||||
|
import com.intellij.navigation.PsiElementNavigationItem
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.platform.backend.navigation.NavigationRequest
|
||||||
|
import com.intellij.platform.backend.navigation.NavigationRequests
|
||||||
|
import com.intellij.platform.backend.navigation.NavigationTarget
|
||||||
|
import com.intellij.platform.backend.presentation.TargetPresentation
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||||
|
import gay.pizza.pork.idea.psi.PorkReferencable
|
||||||
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
data class PorkDeclarationSymbol(val module: String, val name: String) : Symbol, NavigatableSymbol {
|
||||||
|
override fun createPointer(): Pointer<out Symbol> = Pointer { this }
|
||||||
|
override fun getNavigationTargets(project: Project): MutableCollection<out NavigationTarget> {
|
||||||
|
return PorkReferenceResolution.getAllProjectPorkFiles(project)
|
||||||
|
.flatMap { PorkReferenceResolution.findAnyDefinitions(it) }
|
||||||
|
.map { PorkNavigationTarget(it) }
|
||||||
|
.toMutableList()
|
||||||
|
}
|
||||||
|
|
||||||
|
class PorkNavigationTarget(val internalPorkElement: PorkElement) : NavigationTarget {
|
||||||
|
override fun createPointer(): Pointer<out NavigationTarget> = Pointer { this }
|
||||||
|
|
||||||
|
override fun computePresentation(): TargetPresentation = TargetPresentation
|
||||||
|
.builder(internalPorkElement.name!!)
|
||||||
|
.presentation()
|
||||||
|
|
||||||
|
override fun navigationRequest(): NavigationRequest? {
|
||||||
|
return NavigationRequest.sourceNavigationRequest(internalPorkElement.containingFile, internalPorkElement.textRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package gay.pizza.pork.idea
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.search.FilenameIndex
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import com.intellij.psi.util.childrenOfType
|
||||||
|
import gay.pizza.pork.idea.psi.gen.*
|
||||||
|
|
||||||
|
object PorkReferenceResolution {
|
||||||
|
fun getRelevantFiles(containingFile: PsiFile): List<PsiFile> {
|
||||||
|
if (containingFile.virtualFile == null) {
|
||||||
|
return getAllProjectPorkFiles(containingFile.project)
|
||||||
|
}
|
||||||
|
val importDeclarationElements = PsiTreeUtil.collectElementsOfType(containingFile, ImportDeclarationElement::class.java)
|
||||||
|
val files = mutableListOf(containingFile)
|
||||||
|
for (importDeclaration in importDeclarationElements) {
|
||||||
|
val symbolElements = importDeclaration.childrenOfType<SymbolElement>()
|
||||||
|
val importType = importDeclaration.childrenOfType<SymbolElement>().first().text
|
||||||
|
if (importType != "local") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val basicImportPath = symbolElements.drop(1).joinToString("/") { it.text.trim() }
|
||||||
|
val actualImportPath = "../${basicImportPath}.pork"
|
||||||
|
val virtualFile = containingFile.virtualFile?.findFileByRelativePath(actualImportPath) ?: continue
|
||||||
|
val psiFile = PsiManager.getInstance(containingFile.project).findFile(virtualFile) ?: continue
|
||||||
|
files.add(psiFile)
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAllProjectPorkFiles(project: Project): List<PsiFile> {
|
||||||
|
val porkVirtualFiles = FilenameIndex.getAllFilesByExt(project, "pork")
|
||||||
|
return porkVirtualFiles.mapNotNull { virtualFile ->
|
||||||
|
PsiManager.getInstance(project).findFile(virtualFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findAllCandidates(internalPorkElement: PorkElement, name: String? = null): List<PorkElement> =
|
||||||
|
listOf(findAnyLocals(internalPorkElement, name), findAnyDefinitions(internalPorkElement.containingFile, name)).flatten()
|
||||||
|
|
||||||
|
fun findAnyLocals(internalPorkElement: PorkElement, name: String? = null): List<PorkElement> {
|
||||||
|
val functionDefinitionElement = PsiTreeUtil.getParentOfType(internalPorkElement, FunctionDefinitionElement::class.java)
|
||||||
|
?: return emptyList()
|
||||||
|
val locals = mutableListOf<PorkElement>()
|
||||||
|
|
||||||
|
fun check(localCandidate: PsiElement, upward: Boolean) {
|
||||||
|
if (localCandidate is BlockElement && !upward) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localCandidate is ArgumentSpecElement ||
|
||||||
|
localCandidate is LetAssignmentElement ||
|
||||||
|
localCandidate is VarAssignmentElement) {
|
||||||
|
locals.add(localCandidate as PorkElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localCandidate is ForInElement) {
|
||||||
|
val forInItem = localCandidate.childrenOfType<ForInItemElement>().firstOrNull()
|
||||||
|
if (forInItem != null) {
|
||||||
|
locals.add(forInItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localCandidate.children.forEach { check(it, false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiTreeUtil.treeWalkUp(internalPorkElement, functionDefinitionElement) { _, localCandidate ->
|
||||||
|
if (localCandidate != null) {
|
||||||
|
if (internalPorkElement == functionDefinitionElement) {
|
||||||
|
return@treeWalkUp true
|
||||||
|
}
|
||||||
|
check(localCandidate, true)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val argumentSpecElements = functionDefinitionElement.childrenOfType<ArgumentSpecElement>()
|
||||||
|
locals.addAll(argumentSpecElements)
|
||||||
|
val finalLocals = locals.distinctBy { it.textRange }
|
||||||
|
return finalLocals.filter { if (name != null) it.name == name else true }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findAnyDefinitions(containingFile: PsiFile, name: String? = null): List<PorkElement> {
|
||||||
|
val foundDefinitions = mutableListOf<PorkNamedElement>()
|
||||||
|
for (file in getRelevantFiles(containingFile)) {
|
||||||
|
val definitions = PsiTreeUtil.collectElements(file) { element ->
|
||||||
|
element is FunctionDefinitionElement ||
|
||||||
|
element is LetDefinitionElement
|
||||||
|
}.filterIsInstance<PorkNamedElement>()
|
||||||
|
if (name != null) {
|
||||||
|
val fileFoundDefinition = definitions.firstOrNull {
|
||||||
|
it.name == name
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileFoundDefinition != null) {
|
||||||
|
foundDefinitions.add(fileFoundDefinition)
|
||||||
|
return foundDefinitions
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foundDefinitions.addAll(definitions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundDefinitions
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package gay.pizza.pork.idea
|
||||||
|
|
||||||
|
import com.intellij.model.Symbol
|
||||||
|
import com.intellij.model.psi.PsiSymbolDeclaration
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||||
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
class PorkSymbolDeclaration(val element: PorkElement) : PsiSymbolDeclaration {
|
||||||
|
override fun getDeclaringElement(): PsiElement = element
|
||||||
|
override fun getRangeInDeclaringElement(): TextRange {
|
||||||
|
val textRangeOfSymbol = PorkElementHelpers.symbolElementOf(element)?.psi?.textRangeInParent
|
||||||
|
?: throw RuntimeException("Unable to get symbol of element: $element")
|
||||||
|
return textRangeOfSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSymbol(): Symbol = PorkElementHelpers.psiSymbolFor(element) ?:
|
||||||
|
throw RuntimeException("Unable to get symbol of element: $element")
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package gay.pizza.pork.idea
|
||||||
|
|
||||||
|
import com.intellij.model.psi.PsiSymbolDeclaration
|
||||||
|
import com.intellij.model.psi.PsiSymbolDeclarationProvider
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import gay.pizza.pork.idea.psi.gen.FunctionDefinitionElement
|
||||||
|
import gay.pizza.pork.idea.psi.gen.LetDefinitionElement
|
||||||
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
class PorkSymbolDeclarationProvider : PsiSymbolDeclarationProvider {
|
||||||
|
override fun getDeclarations(element: PsiElement, offsetInElement: Int): MutableCollection<out PsiSymbolDeclaration> {
|
||||||
|
if (element !is PorkElement) return mutableListOf()
|
||||||
|
if (element is FunctionDefinitionElement || element is LetDefinitionElement) {
|
||||||
|
return mutableListOf(PorkSymbolDeclaration(element))
|
||||||
|
}
|
||||||
|
return mutableListOf()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package gay.pizza.pork.idea
|
||||||
|
|
||||||
|
import com.intellij.model.Symbol
|
||||||
|
import com.intellij.model.psi.PsiSymbolReference
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||||
|
import gay.pizza.pork.idea.psi.PorkReferencable
|
||||||
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
class PorkSymbolReference(override val internalPorkElement: PorkElement, val range: TextRange) : PsiSymbolReference, PorkReferencable {
|
||||||
|
override fun getElement(): PsiElement = internalPorkElement
|
||||||
|
override fun getRangeInElement(): TextRange = range
|
||||||
|
override fun resolveReference(): MutableCollection<out Symbol> {
|
||||||
|
return findAllCandidates().mapNotNull { PorkElementHelpers.psiSymbolFor(it) }.toMutableList()
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package gay.pizza.pork.idea.psi
|
package gay.pizza.pork.idea.psi
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode
|
import com.intellij.lang.ASTNode
|
||||||
|
import com.intellij.model.Symbol
|
||||||
import com.intellij.navigation.ItemPresentation
|
import com.intellij.navigation.ItemPresentation
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFileFactory
|
import com.intellij.psi.PsiFileFactory
|
||||||
@ -11,28 +12,30 @@ import com.intellij.psi.util.childrenOfType
|
|||||||
import com.intellij.util.PlatformIcons
|
import com.intellij.util.PlatformIcons
|
||||||
import gay.pizza.pork.ast.NodeType
|
import gay.pizza.pork.ast.NodeType
|
||||||
import gay.pizza.pork.common.unused
|
import gay.pizza.pork.common.unused
|
||||||
|
import gay.pizza.pork.idea.PorkDeclarationSymbol
|
||||||
import gay.pizza.pork.idea.PorkElementTypes
|
import gay.pizza.pork.idea.PorkElementTypes
|
||||||
import gay.pizza.pork.idea.PorkLanguage
|
import gay.pizza.pork.idea.PorkLanguage
|
||||||
import gay.pizza.pork.idea.psi.gen.*
|
import gay.pizza.pork.idea.psi.gen.*
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
object PorkElementHelpers {
|
object PorkElementHelpers {
|
||||||
private val symbolElementType = PorkElementTypes.elementTypeFor(NodeType.Symbol)
|
private val symbolElementType = PorkElementTypes.elementTypeFor(NodeType.Symbol)
|
||||||
|
|
||||||
fun nameOfNamedElement(element: PorkNamedElement): String? {
|
fun nameOfNamedElement(element: PorkNamedElement): String? {
|
||||||
val child = symbolOf(element) ?: return null
|
val child = symbolElementOf(element) ?: return null
|
||||||
return child.text
|
return child.text
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setNameOfNamedElement(element: PorkNamedElement, name: String): PsiElement {
|
fun setNameOfNamedElement(element: PorkNamedElement, name: String): PsiElement {
|
||||||
val child = symbolOf(element) ?: return element
|
val child = symbolElementOf(element) ?: return element
|
||||||
val factory = PsiFileFactory.getInstance(element.project) as PsiFileFactoryImpl
|
val factory = PsiFileFactory.getInstance(element.project) as PsiFileFactoryImpl
|
||||||
val created = factory.createElementFromText(name, PorkLanguage, child.elementType, element.context) as PorkElement
|
val created = factory.createElementFromText(name, PorkLanguage, child.elementType, element.context) as PorkElement
|
||||||
element.node.replaceChild(child, created.node)
|
element.node.replaceChild(child, created.node)
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
fun symbolOf(element: PorkElement): ASTNode? {
|
fun symbolElementOf(element: PorkElement): ASTNode? {
|
||||||
var child = element.node.findChildByType(symbolElementType)
|
var child = element.node.findChildByType(symbolElementType)
|
||||||
if (child == null) {
|
if (child == null) {
|
||||||
child = PsiTreeUtil.collectElementsOfType(element, SymbolElement::class.java).firstOrNull()?.node
|
child = PsiTreeUtil.collectElementsOfType(element, SymbolElement::class.java).firstOrNull()?.node
|
||||||
@ -41,7 +44,7 @@ object PorkElementHelpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun nameIdentifierOfNamedElement(element: PorkNamedElement): PsiElement? {
|
fun nameIdentifierOfNamedElement(element: PorkNamedElement): PsiElement? {
|
||||||
return symbolOf(element)?.psi
|
return symbolElementOf(element)?.psi
|
||||||
}
|
}
|
||||||
|
|
||||||
fun referenceOfElement(element: PorkElement, type: NodeType): PsiReference? {
|
fun referenceOfElement(element: PorkElement, type: NodeType): PsiReference? {
|
||||||
@ -73,4 +76,13 @@ object PorkElementHelpers {
|
|||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun psiSymbolFor(element: PorkElement): Symbol? {
|
||||||
|
val symbolElement = symbolElementOf(element) ?: return null
|
||||||
|
val module = element.containingFile?.virtualFile?.path ?: element.containingFile?.name ?: return null
|
||||||
|
if (element is FunctionDefinitionElement || element is LetDefinitionElement) {
|
||||||
|
return PorkDeclarationSymbol(module, symbolElement.text)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package gay.pizza.pork.idea.psi
|
package gay.pizza.pork.idea.psi
|
||||||
|
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
|
||||||
import com.intellij.psi.util.childrenOfType
|
|
||||||
import gay.pizza.pork.idea.psi.gen.*
|
|
||||||
|
|
||||||
class PorkIdentifierReference(element: PorkElement, textRange: TextRange) : PorkReference(element, textRange) {
|
class PorkIdentifierReference(element: PorkElement, textRange: TextRange) : PorkReference(element, textRange) {
|
||||||
override fun resolve(): PorkElement? {
|
override fun resolve(): PorkElement? {
|
||||||
@ -20,72 +17,4 @@ class PorkIdentifierReference(element: PorkElement, textRange: TextRange) : Pork
|
|||||||
val candidates = findAllCandidates()
|
val candidates = findAllCandidates()
|
||||||
return candidates.toTypedArray()
|
return candidates.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findAllCandidates(name: String? = null): List<PorkElement> =
|
|
||||||
listOf(findAnyLocals(name), findAnyDefinitions(name)).flatten()
|
|
||||||
|
|
||||||
fun findAnyLocals(name: String? = null): List<PorkElement> {
|
|
||||||
val functionDefinitionElement = PsiTreeUtil.getParentOfType(element, FunctionDefinitionElement::class.java)
|
|
||||||
?: return emptyList()
|
|
||||||
val locals = mutableListOf<PorkElement>()
|
|
||||||
|
|
||||||
fun check(localCandidate: PsiElement, upward: Boolean) {
|
|
||||||
if (localCandidate is BlockElement && !upward) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localCandidate is ArgumentSpecElement ||
|
|
||||||
localCandidate is LetAssignmentElement ||
|
|
||||||
localCandidate is VarAssignmentElement) {
|
|
||||||
locals.add(localCandidate as PorkElement)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localCandidate is ForInElement) {
|
|
||||||
val forInItem = localCandidate.childrenOfType<ForInItemElement>().firstOrNull()
|
|
||||||
if (forInItem != null) {
|
|
||||||
locals.add(forInItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
localCandidate.children.forEach { check(it, false) }
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiTreeUtil.treeWalkUp(element, functionDefinitionElement) { _, localCandidate ->
|
|
||||||
if (localCandidate != null) {
|
|
||||||
if (element == functionDefinitionElement) {
|
|
||||||
return@treeWalkUp true
|
|
||||||
}
|
|
||||||
check(localCandidate, true)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
val argumentSpecElements = functionDefinitionElement.childrenOfType<ArgumentSpecElement>()
|
|
||||||
locals.addAll(argumentSpecElements)
|
|
||||||
val finalLocals = locals.distinctBy { it.textRange }
|
|
||||||
return finalLocals.filter { if (name != null) it.name == name else true }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findAnyDefinitions(name: String? = null): List<PorkElement> {
|
|
||||||
val foundDefinitions = mutableListOf<PorkNamedElement>()
|
|
||||||
for (file in getRelevantFiles()) {
|
|
||||||
val definitions = PsiTreeUtil.collectElements(file) { element ->
|
|
||||||
element is FunctionDefinitionElement ||
|
|
||||||
element is LetDefinitionElement
|
|
||||||
}.filterIsInstance<PorkNamedElement>()
|
|
||||||
if (name != null) {
|
|
||||||
val fileFoundDefinition = definitions.firstOrNull {
|
|
||||||
it.name == name
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileFoundDefinition != null) {
|
|
||||||
foundDefinitions.add(fileFoundDefinition)
|
|
||||||
return foundDefinitions
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundDefinitions.addAll(definitions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return foundDefinitions
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package gay.pizza.pork.idea.psi
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import gay.pizza.pork.idea.PorkReferenceResolution
|
||||||
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
|
|
||||||
|
interface PorkReferencable {
|
||||||
|
val internalPorkElement: PorkElement
|
||||||
|
|
||||||
|
fun getRelevantFiles(): List<PsiFile> = PorkReferenceResolution.getRelevantFiles(internalPorkElement.containingFile)
|
||||||
|
fun findAllCandidates(name: String? = null): List<PorkElement> =
|
||||||
|
listOf(findAnyLocals(name), findAnyDefinitions(name)).flatten()
|
||||||
|
|
||||||
|
fun findAnyLocals(name: String? = null): List<PorkElement> =
|
||||||
|
PorkReferenceResolution.findAnyLocals(internalPorkElement, name)
|
||||||
|
|
||||||
|
fun findAnyDefinitions(name: String? = null): List<PorkElement> =
|
||||||
|
PorkReferenceResolution.findAnyDefinitions(internalPorkElement.containingFile, name)
|
||||||
|
}
|
@ -12,34 +12,6 @@ import gay.pizza.pork.idea.psi.gen.ImportDeclarationElement
|
|||||||
import gay.pizza.pork.idea.psi.gen.PorkElement
|
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||||
import gay.pizza.pork.idea.psi.gen.SymbolElement
|
import gay.pizza.pork.idea.psi.gen.SymbolElement
|
||||||
|
|
||||||
abstract class PorkReference(element: PorkElement, textRange: TextRange) : PsiReferenceBase<PsiElement>(element, textRange) {
|
abstract class PorkReference(element: PorkElement, textRange: TextRange) : PsiReferenceBase<PsiElement>(element, textRange), PorkReferencable {
|
||||||
fun getRelevantFiles(): List<PsiFile> {
|
override val internalPorkElement: PorkElement = element
|
||||||
val containingFile = element.containingFile ?: return emptyList()
|
|
||||||
if (containingFile.virtualFile == null) {
|
|
||||||
return getAllProjectPorkFiles()
|
|
||||||
}
|
|
||||||
val importDeclarationElements = PsiTreeUtil.collectElementsOfType(containingFile, ImportDeclarationElement::class.java)
|
|
||||||
val files = mutableListOf(containingFile)
|
|
||||||
for (importDeclaration in importDeclarationElements) {
|
|
||||||
val symbolElements = importDeclaration.childrenOfType<SymbolElement>()
|
|
||||||
val importType = importDeclaration.childrenOfType<SymbolElement>().first().text
|
|
||||||
if (importType != "local") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val basicImportPath = symbolElements.drop(1).joinToString("/") { it.text.trim() }
|
|
||||||
val actualImportPath = "../${basicImportPath}.pork"
|
|
||||||
val virtualFile = containingFile.virtualFile?.findFileByRelativePath(actualImportPath) ?: continue
|
|
||||||
val psiFile = PsiManager.getInstance(element.project).findFile(virtualFile) ?: continue
|
|
||||||
files.add(psiFile)
|
|
||||||
}
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAllProjectPorkFiles(): List<PsiFile> {
|
|
||||||
val porkVirtualFiles = FilenameIndex.getAllFilesByExt(element.project, "pork")
|
|
||||||
return porkVirtualFiles.mapNotNull { virtualFile ->
|
|
||||||
PsiManager.getInstance(element.project).findFile(virtualFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<lang.elementManipulator
|
<lang.elementManipulator
|
||||||
implementationClass="gay.pizza.pork.idea.PorkElementManipulator"
|
implementationClass="gay.pizza.pork.idea.PorkElementManipulator"
|
||||||
forClass="gay.pizza.pork.idea.psi.gen.PorkElement"/>
|
forClass="gay.pizza.pork.idea.psi.gen.PorkElement"/>
|
||||||
|
<psi.declarationProvider implementation="gay.pizza.pork.idea.PorkSymbolDeclarationProvider"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<applicationListeners>
|
<applicationListeners>
|
||||||
|
Loading…
Reference in New Issue
Block a user