Phase 5a: add configurable Jai module roots

This commit is contained in:
hgranthorner
2026-08-05 10:24:32 -04:00
parent 9122b5a5c0
commit 2bc1b9f4be
13 changed files with 740 additions and 214 deletions

View File

@@ -7,7 +7,6 @@ import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.tree.IElementType
@@ -15,6 +14,8 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.ProcessingContext
import dev.hgh.jai.lexer.JaiLexer
import dev.hgh.jai.lexer.JaiTokenTypes
import dev.hgh.jai.module.JaiModuleResolver
import dev.hgh.jai.module.JaiPathMode
import dev.hgh.jai.psi.JaiDirectiveExpr
/** Directives and their adjacent comma flags before an import/load string. */
@@ -106,11 +107,12 @@ private class JaiCompletionProvider : CompletionProvider<CompletionParameters>()
resultSet: CompletionResultSet,
) {
val sourceFile = parameters.originalFile.virtualFile
val project = parameters.originalFile.project
val variants =
if (directive == "#import") {
JaiModuleCompletion.moduleNames(parameters.originalFile.project, sourceFile)
JaiModuleCompletion.moduleNames(project, sourceFile)
} else {
JaiModuleCompletion.loadPaths(sourceFile)
JaiModuleCompletion.loadPaths(project, sourceFile)
}
variants
.filter { it.startsWith(prefix) }
@@ -309,14 +311,12 @@ private object JaiCompletionCatalog {
private object JaiModuleCompletion {
private const val JAI_EXTENSION = "jai"
private val fileSystem: LocalFileSystem
get() = LocalFileSystem.getInstance()
fun moduleNames(
project: com.intellij.openapi.project.Project,
sourceFile: VirtualFile?,
): List<String> =
collectCandidates(candidateRoots(project, sourceFile, moduleMode = true)) { child ->
collectCandidates(JaiModuleResolver.candidateRoots(project, sourceFile, JaiPathMode.MODULE)) { child ->
when {
child.isDirectory && child.findChild("module.jai") != null -> child.name
!child.isDirectory && child.extension == JAI_EXTENSION -> child.nameWithoutExtension
@@ -324,10 +324,11 @@ private object JaiModuleCompletion {
}
}
fun loadPaths(sourceFile: VirtualFile?): List<String> =
collectCandidates(
listOfNotNull(sourceFile?.parent),
) { child ->
fun loadPaths(
project: com.intellij.openapi.project.Project,
sourceFile: VirtualFile?,
): List<String> =
collectCandidates(JaiModuleResolver.candidateRoots(project, sourceFile, JaiPathMode.FILE)) { child ->
if (!child.isDirectory && child.extension == JAI_EXTENSION) child.name else null
}
@@ -344,27 +345,4 @@ private object JaiModuleCompletion {
}
return names.sorted()
}
private fun candidateRoots(
project: com.intellij.openapi.project.Project,
sourceFile: VirtualFile?,
moduleMode: Boolean,
): List<VirtualFile> {
val roots = linkedMapOf<String, VirtualFile>()
fun add(root: VirtualFile?) {
if (root != null && root.isValid && root.isDirectory) roots.putIfAbsent(root.path, root)
}
if (moduleMode) {
add(sourceFile?.parent?.findChild("modules"))
val projectRoot = project.basePath?.let(fileSystem::findFileByPath)
add(projectRoot?.findChild("modules"))
add(projectRoot)
add(fileSystem.findFileByPath("${System.getProperty("user.home")}/.local/jai/modules"))
} else {
add(sourceFile?.parent)
}
return roots.values.toList()
}
}