From c92a111af740deb29b0be050316acb1cab588b00 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Thu, 21 Sep 2023 21:33:34 -0700 Subject: [PATCH] idea: implement function call completion (limited) --- .../pizza/pork/parser/CharSourceExtensions.kt | 7 ++++ .../pork/idea/psi/PorkFunctionReference.kt | 35 ++++++++++++++----- .../gay/pizza/pork/idea/psi/PorkReference.kt | 17 +++++++-- .../gay/pizza/pork/tool/CopyStdlibCommand.kt | 26 ++++++++++++++ .../kotlin/gay/pizza/pork/tool/RootCommand.kt | 3 +- 5 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 parser/src/main/kotlin/gay/pizza/pork/parser/CharSourceExtensions.kt create mode 100644 tool/src/main/kotlin/gay/pizza/pork/tool/CopyStdlibCommand.kt diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/CharSourceExtensions.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/CharSourceExtensions.kt new file mode 100644 index 0000000..df7fbfa --- /dev/null +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/CharSourceExtensions.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.parser + +fun CharSource.readToString(): String = buildString { + while (peek() != CharSource.NullChar) { + append(next()) + } +} diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkFunctionReference.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkFunctionReference.kt index 4fb1f6e..e367b5e 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkFunctionReference.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkFunctionReference.kt @@ -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 { + return findFunctionDefinitions().toTypedArray() + } + + fun findFunctionDefinitions(name: String? = null): List { + val foundFunctionDefinitions = mutableListOf() + 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 + } } diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkReference.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkReference.kt index cc0bd89..5936122 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkReference.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/psi/PorkReference.kt @@ -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(element, textRange) { fun getRelevantFiles(): List { - 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(containingFile) + val files = mutableListOf(containingFile) for (importDeclaration in importDeclarationElements) { val symbolElements = importDeclaration.childrenOfType() val importType = importDeclaration.childrenOfType().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 { + val porkVirtualFiles = FilenameIndex.getAllFilesByExt(element.project, "pork") + return porkVirtualFiles.mapNotNull { virtualFile -> + PsiManager.getInstance(element.project).findFile(virtualFile) + } + } } diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CopyStdlibCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CopyStdlibCommand.kt new file mode 100644 index 0000000..3682cdc --- /dev/null +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CopyStdlibCommand.kt @@ -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()) + } + } +} diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/RootCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/RootCommand.kt index ad3a829..393e353 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/RootCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/RootCommand.kt @@ -16,7 +16,8 @@ class RootCommand : CliktCommand( ParseCommand(), AstCommand(), AttributeCommand(), - ScopeAnalysisCommand() + ScopeAnalysisCommand(), + CopyStdlibCommand() ) }