mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10:55 +00:00
idea: proper scoping support, completion now works
This commit is contained in:
@ -0,0 +1,11 @@
|
||||
package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.lang.refactoring.RefactoringSupportProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import gay.pizza.pork.idea.psi.gen.PorkNamedElement
|
||||
|
||||
class PorkRefactoringSupportProvider : RefactoringSupportProvider() {
|
||||
override fun isMemberInplaceRenameAvailable(element: PsiElement, context: PsiElement?): Boolean {
|
||||
return element is PorkNamedElement
|
||||
}
|
||||
}
|
@ -26,9 +26,6 @@ object PorkElementHelpers {
|
||||
|
||||
fun referenceOfElement(element: PorkElement, type: NodeType): PsiReference? {
|
||||
val textRangeOfSymbolInElement = element.childrenOfType<SymbolElement>().firstOrNull()?.textRangeInParent ?: return null
|
||||
if (type == NodeType.FunctionDefinition) {
|
||||
return PorkFunctionReference(element, textRangeOfSymbolInElement)
|
||||
}
|
||||
return null
|
||||
return PorkIdentifierReference(element, textRangeOfSymbolInElement)
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
package gay.pizza.pork.idea.psi
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import gay.pizza.pork.idea.psi.gen.FunctionDefinitionElement
|
||||
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||
|
||||
class PorkFunctionReference(element: PorkElement, textRange: TextRange) : PorkReference(element, textRange) {
|
||||
override fun resolve(): PorkElement? {
|
||||
val functionName = canonicalText
|
||||
val functionDefinitions = findFunctionDefinitions(functionName)
|
||||
if (functionDefinitions.isNotEmpty()) {
|
||||
return functionDefinitions.first()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> {
|
||||
return findFunctionDefinitions().toTypedArray()
|
||||
}
|
||||
|
||||
fun findFunctionDefinitions(name: String? = null): List<FunctionDefinitionElement> {
|
||||
val foundFunctionDefinitions = mutableListOf<FunctionDefinitionElement>()
|
||||
for (file in getRelevantFiles()) {
|
||||
val fileFunctionDefinitions = PsiTreeUtil.collectElementsOfType(file, FunctionDefinitionElement::class.java)
|
||||
if (name != null) {
|
||||
val fileFoundDefinition = fileFunctionDefinitions.firstOrNull {
|
||||
it.name == name
|
||||
}
|
||||
|
||||
if (fileFoundDefinition != null) {
|
||||
foundFunctionDefinitions.add(fileFoundDefinition)
|
||||
return foundFunctionDefinitions
|
||||
}
|
||||
} else {
|
||||
foundFunctionDefinitions.addAll(fileFunctionDefinitions)
|
||||
}
|
||||
}
|
||||
return foundFunctionDefinitions
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package gay.pizza.pork.idea.psi
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
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) {
|
||||
override fun resolve(): PorkElement? {
|
||||
val identifierName = canonicalText
|
||||
val items = findAllCandidates(identifierName)
|
||||
if (items.isNotEmpty()) {
|
||||
return items.first()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> {
|
||||
return findAllCandidates().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)
|
||||
if (functionDefinitionElement == null) {
|
||||
return emptyList()
|
||||
}
|
||||
val locals = mutableListOf<PorkElement>()
|
||||
|
||||
fun check(localCandidate: PsiElement, upward: Boolean) {
|
||||
if (localCandidate is BlockElement && !upward) {
|
||||
return
|
||||
}
|
||||
|
||||
if (localCandidate == element) {
|
||||
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>().first()
|
||||
locals.add(forInItem)
|
||||
}
|
||||
|
||||
localCandidate.children.forEach { check(it, false) }
|
||||
}
|
||||
|
||||
PsiTreeUtil.treeWalkUp(element, functionDefinitionElement) { _, localCandidate ->
|
||||
if (localCandidate != null) {
|
||||
check(localCandidate, true)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
val argumentSpecElements = functionDefinitionElement.childrenOfType<ArgumentSpecElement>()
|
||||
locals.addAll(argumentSpecElements)
|
||||
return locals.filter { it.name == name }
|
||||
}
|
||||
|
||||
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,17 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class ArgumentSpecElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class ForInItemElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
@ -19,6 +19,7 @@ object PorkElementFactory {
|
||||
NodeType.InfixOperation -> InfixOperationElement(node)
|
||||
NodeType.BooleanLiteral -> BooleanLiteralElement(node)
|
||||
NodeType.FunctionCall -> FunctionCallElement(node)
|
||||
NodeType.ArgumentSpec -> ArgumentSpecElement(node)
|
||||
NodeType.FunctionDefinition -> FunctionDefinitionElement(node)
|
||||
NodeType.LetDefinition -> LetDefinitionElement(node)
|
||||
NodeType.If -> IfElement(node)
|
||||
@ -33,6 +34,7 @@ object PorkElementFactory {
|
||||
NodeType.StringLiteral -> StringLiteralElement(node)
|
||||
NodeType.SymbolReference -> SymbolReferenceElement(node)
|
||||
NodeType.While -> WhileElement(node)
|
||||
NodeType.ForInItem -> ForInItemElement(node)
|
||||
NodeType.ForIn -> ForInElement(node)
|
||||
NodeType.Break -> BreakElement(node)
|
||||
NodeType.Continue -> ContinueElement(node)
|
||||
|
@ -1,17 +1,6 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class SetAssignmentElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
class SetAssignmentElement(node: ASTNode) : PorkElement(node)
|
||||
|
@ -20,6 +20,9 @@
|
||||
<lang.braceMatcher
|
||||
language="Pork"
|
||||
implementationClass="gay.pizza.pork.idea.PorkBraceMatcher"/>
|
||||
<lang.refactoringSupport
|
||||
language="Pork"
|
||||
implementationClass="gay.pizza.pork.idea.PorkRefactoringSupportProvider"/>
|
||||
<psi.declarationProvider implementation="gay.pizza.pork.idea.PorkSymbolDeclarationProvider"/>
|
||||
</extensions>
|
||||
|
||||
|
Reference in New Issue
Block a user