Skip to content

Commit

Permalink
feat(completion): add basic completion for project run tasks
Browse files Browse the repository at this point in the history
Extend completion for project run tasks with basic support.

- Added completion for project run tasks in ShireCompletionContributor.kt
- Implemented ProjectRunProvider.kt for providing completions
- Updated ProjectRunService.kt with lookupAvailableTask method
- Added GradleTasksUtil.kt with createGradleTestConfiguration and createConfigForGradle methods
- Updated JavaRunProjectService.kt with run and lookupAvailableTask methods
  • Loading branch information
phodal committed Jun 8, 2024
1 parent 80a3aed commit e8c6578
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
package com.phodal.shirecore.provider

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project

interface ProjectRunService {
fun isAvailable(project: Project): Boolean

fun run(project: Project, taskName: String?)
fun run(project: Project, taskName: String)

/**
* Return List of available tasks
*/
fun taskCompletion(project: Project) {
// do nothing
fun lookupAvailableTask(
project: Project,
parameters: CompletionParameters,
result: CompletionResultSet,
): List<LookupElement> {
return emptyList()
}

companion object {
val EP_NAME = ExtensionPointName<ProjectRunService>("com.phodal.shireRunProjectService")

fun all(): List<ProjectRunService> {
return ProjectRunService.EP_NAME.extensionList
}

fun provider(project: Project): ProjectRunService? {
val projectRunServices = EP_NAME.extensionList
return projectRunServices.firstOrNull { it.isAvailable(project) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
package com.phodal.shirelang.java.impl

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.util.SmartList
import com.phodal.shirecore.provider.ProjectRunService
import com.phodal.shirelang.java.toolchain.GradleTasksUtil
import icons.GradleIcons

class JavaRunProjectService : ProjectRunService {
override fun isAvailable(project: Project): Boolean {
TODO("Not yet implemented")
return ProjectRootManager.getInstance(project).projectSdk is JavaSdk
}

override fun run(project: Project, taskName: String?) {
TODO("Not yet implemented")
override fun run(project: Project, taskName: String) {
// val configureGradleTask = GradleTasksUtil.createConfigForGradle(project, taskName)
}

override fun lookupAvailableTask(
project: Project,
parameters: CompletionParameters,
result: CompletionResultSet,
): List<LookupElement> {
val lookupElements: MutableList<LookupElement> = SmartList()
GradleTasksUtil.collectGradleTasksWithCheck(project).forEach {
val element = LookupElementBuilder.create(it.text)
.withTypeText(it.description)
.withIcon(GradleIcons.Gradle)
result.addElement(element)
}

return lookupElements
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package com.phodal.shirelang.java.toolchain

import com.intellij.execution.RunManager
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager
import com.intellij.openapi.externalSystem.service.ui.completion.TextCompletionInfo
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.phodal.shirelang.java.impl.GRADLE_COMPLETION_COMPARATOR
import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType
import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration
import org.jetbrains.plugins.gradle.service.project.GradleTasksIndices
import org.jetbrains.plugins.gradle.util.GradleConstants

Expand Down Expand Up @@ -47,4 +55,69 @@ object GradleTasksUtil {
.sortedWith(Comparator.comparing({ it.text }, GRADLE_COMPLETION_COMPARATOR))
return tasks
}

fun createGradleTestConfiguration(virtualFile: VirtualFile, project: Project): GradleRunConfiguration? {
val name = virtualFile.name

val canonicalName = runReadAction {
val psiFile: PsiJavaFile =
PsiManager.getInstance(project).findFile(virtualFile) as? PsiJavaFile ?: return@runReadAction null
// skip for non-test files
(psiFile.packageName + "." + virtualFile.nameWithoutExtension).removePrefix(".")
} ?: return null

val runManager = RunManager.getInstance(project)

var moduleName = ""
val moduleForFile = runReadAction { ProjectFileIndex.getInstance(project).getModuleForFile(virtualFile) }
// a moduleForFile.name will be like <project>.<module>.<testModule>, so we need to remove the last part and first part
if (moduleForFile != null) {
val moduleNameSplit = moduleForFile.name.split(".").drop(1).dropLast(1).joinToString(":")
if (moduleNameSplit.isNotEmpty()) {
moduleName = "$moduleNameSplit:"
}
}

// todo: add maven ??
val configuration = runManager.createConfiguration(name, GradleExternalTaskConfigurationType::class.java)
val runConfiguration = configuration.configuration as GradleRunConfiguration

runConfiguration.isDebugServerProcess = false
runConfiguration.settings.externalProjectPath = project.guessProjectDir()?.path
// todo: add module for test
runConfiguration.rawCommandLine = moduleName + "test --tests \"${canonicalName}\""

runManager.addConfiguration(configuration)
runManager.selectedConfiguration = configuration

return runConfiguration
}

/**
* This function is used to create a Gradle run configuration for a specific virtual file in a project.
* It takes the virtual file, project, and task name as parameters and returns a GradleRunConfiguration object.
*
* @param virtualFile The virtual file for which the configuration is being created.
* @param project The project in which the configuration is being created.
* @param taskName The name of the task to be executed in the Gradle run configuration.
* @return A GradleRunConfiguration object representing the created configuration.
*/
fun createConfigForGradle(project: Project, taskName: String): GradleRunConfiguration {
val runManager = RunManager.getInstance(project)
val configuration = runManager.createConfiguration(
taskName,
GradleExternalTaskConfigurationType::class.java
)
val runConfiguration = configuration.configuration as GradleRunConfiguration

runConfiguration.isDebugServerProcess = false
runConfiguration.settings.externalProjectPath = project.guessProjectDir()?.path

runConfiguration.rawCommandLine = taskName

runManager.addConfiguration(configuration)
runManager.selectedConfiguration = configuration

return runConfiguration
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class ShireCompletionContributor : CompletionContributor() {
valuePattern(BuiltinCommand.Refactor.commandName),
RefactoringFuncProvider()
)
extend(
CompletionType.BASIC,
valuePattern(BuiltinCommand.RUN.commandName),
ProjectRunProvider()
)
}

private inline fun <reified I : PsiElement> psiElement() = PlatformPatterns.psiElement(I::class.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.phodal.shirelang.completion.provider

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.util.ProcessingContext
import com.phodal.shirecore.provider.ProjectRunService

class ProjectRunProvider : CompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
result: CompletionResultSet,
) {
ProjectRunService.all().forEach { completionProvider ->
val elements = completionProvider.lookupAvailableTask(parameters.editor.project!!, parameters, result)
elements.forEach {
result.addElement(it)
}
}
}
}

0 comments on commit e8c6578

Please sign in to comment.