idea: implement function call completion (limited)

This commit is contained in:
Alex Zenla 2023-09-21 21:33:34 -07:00
parent d12aadf18c
commit c92a111af7
Signed by: alex
GPG Key ID: C0780728420EBFE5
5 changed files with 76 additions and 12 deletions

View File

@ -0,0 +1,7 @@
package gay.pizza.pork.parser
fun CharSource.readToString(): String = buildString {
while (peek() != CharSource.NullChar) {
append(next())
}
}

View File

@ -8,15 +8,34 @@ import gay.pizza.pork.idea.psi.gen.PorkElement
class PorkFunctionReference(element: PorkElement, textRange: TextRange) : PorkReference(element, textRange) {
override fun resolve(): PorkElement? {
val functionName = canonicalText
for (file in getRelevantFiles()) {
val thisFileFunctionDefinitions = PsiTreeUtil.collectElementsOfType(file, FunctionDefinitionElement::class.java)
val thisFileFoundFunctionDefinition = thisFileFunctionDefinitions.firstOrNull {
it.name == functionName
}
if (thisFileFoundFunctionDefinition != null) {
return thisFileFoundFunctionDefinition
}
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
}
}

View File

@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiReferenceBase
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.ImportDeclarationElement
@ -13,9 +14,12 @@ import gay.pizza.pork.idea.psi.gen.SymbolElement
abstract class PorkReference(element: PorkElement, textRange: TextRange) : PsiReferenceBase<PsiElement>(element, textRange) {
fun getRelevantFiles(): List<PsiFile> {
val containingFile = element.containingFile
val containingFile = element.containingFile ?: return emptyList()
if (containingFile.virtualFile == null) {
return getAllProjectPorkFiles()
}
val importDeclarationElements = PsiTreeUtil.collectElementsOfType(containingFile, ImportDeclarationElement::class.java)
val files = mutableListOf<PsiFile>(containingFile)
val files = mutableListOf(containingFile)
for (importDeclaration in importDeclarationElements) {
val symbolElements = importDeclaration.childrenOfType<SymbolElement>()
val importType = importDeclaration.childrenOfType<SymbolElement>().first().text
@ -25,10 +29,17 @@ abstract class PorkReference(element: PorkElement, textRange: TextRange) : PsiRe
val basicImportPath = symbolElements.drop(1).joinToString("/") { it.text.trim() }
val actualImportPath = "../${basicImportPath}.pork"
val virtualFile = containingFile.virtualFile.findFileByRelativePath(actualImportPath) ?: continue
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)
}
}
}

View File

@ -0,0 +1,26 @@
package gay.pizza.pork.tool
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.default
import gay.pizza.dough.fs.PlatformFsProvider
import gay.pizza.dough.fs.createDirectories
import gay.pizza.dough.fs.exists
import gay.pizza.dough.fs.writeString
import gay.pizza.pork.parser.readToString
import gay.pizza.pork.stdlib.PorkStdlib
class CopyStdlibCommand : CliktCommand(help = "Copy Stdlib", name = "copy-stdlib") {
val output by argument("output").default("stdlib")
override fun run() {
val outputFsPath = PlatformFsProvider.resolve(output)
for (filePath in PorkStdlib.files) {
val outputFilePath = outputFsPath.resolve(filePath)
if (outputFilePath.parent?.exists() == false) {
outputFilePath.parent?.createDirectories()
}
outputFilePath.writeString(PorkStdlib.loadAsCharSource(filePath).readToString())
}
}
}

View File

@ -16,7 +16,8 @@ class RootCommand : CliktCommand(
ParseCommand(),
AstCommand(),
AttributeCommand(),
ScopeAnalysisCommand()
ScopeAnalysisCommand(),
CopyStdlibCommand()
)
}