generated from JetBrains/intellij-platform-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(provider): add RunService interface and implementation
Add RunService interface and implementation to handle running files within a project.
- Loading branch information
Showing
13 changed files
with
613 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
core/src/main/kotlin/com/phodal/shirelang/ShireCoreBundle.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.phodal.shirelang | ||
|
||
import com.intellij.DynamicBundle | ||
import org.jetbrains.annotations.NonNls | ||
import org.jetbrains.annotations.PropertyKey | ||
|
||
@NonNls | ||
private const val BUNDLE = "messages.ShireCoreBundle" | ||
|
||
object ShireCoreBundle : DynamicBundle(BUNDLE) { | ||
@Suppress("SpreadOperator") | ||
@JvmStatic | ||
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = getMessage(key, *params) | ||
|
||
@Suppress("SpreadOperator", "unused") | ||
@JvmStatic | ||
fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = | ||
getLazyMessage(key, *params) | ||
} |
24 changes: 24 additions & 0 deletions
24
core/src/main/kotlin/com/phodal/shirelang/ShirelangNotifications.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.phodal.shirelang | ||
|
||
import com.intellij.notification.NotificationGroup | ||
import com.intellij.notification.NotificationGroupManager | ||
import com.intellij.notification.NotificationType | ||
import com.intellij.openapi.project.Project | ||
|
||
object ShirelangNotifications { | ||
private fun group(): NotificationGroup? { | ||
return NotificationGroupManager.getInstance().getNotificationGroup("Shirelang.notification.group") | ||
} | ||
|
||
fun notify(project: Project, msg: String) { | ||
group()?.createNotification(msg, NotificationType.INFORMATION)?.notify(project) | ||
} | ||
|
||
fun error(project: Project, msg: String) { | ||
group()?.createNotification(msg, NotificationType.ERROR)?.notify(project) | ||
} | ||
|
||
fun warn(project: Project, msg: String) { | ||
group()?.createNotification(msg, NotificationType.WARNING)?.notify(project) | ||
} | ||
} |
140 changes: 140 additions & 0 deletions
140
core/src/main/kotlin/com/phodal/shirelang/provider/RunService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package com.phodal.shirelang.provider | ||
|
||
import com.intellij.execution.RunManager | ||
import com.intellij.execution.RunnerAndConfigurationSettings | ||
import com.intellij.execution.actions.ConfigurationContext | ||
import com.intellij.execution.configurations.RunConfiguration | ||
import com.intellij.execution.configurations.RunProfile | ||
import com.intellij.openapi.application.runReadAction | ||
import com.intellij.openapi.diagnostic.Logger | ||
import com.intellij.openapi.diagnostic.logger | ||
import com.intellij.openapi.progress.ProgressManager | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.openapi.vfs.VirtualFile | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiErrorElement | ||
import com.intellij.psi.PsiFile | ||
import com.phodal.shirelang.runner.RunServiceTask | ||
|
||
interface RunService { | ||
private val logger: Logger get() = logger<RunService>() | ||
|
||
/** | ||
* Retrieves the run configuration class for the given project. | ||
* | ||
* @param project The project for which to retrieve the run configuration class. | ||
* @return The run configuration class for the project. | ||
*/ | ||
fun runConfigurationClass(project: Project): Class<out RunProfile>? | ||
|
||
/** | ||
* Creates a new run configuration for the given project and virtual file. | ||
* | ||
* 1. Looks up the PSI file from the virtual file using `PsiManager.getInstance(project).findFile(virtualFile)`. | ||
* 2. Creates a RunConfigurationSettings instance with the name "name" and the specified RunConfigurationType using `RunManager.getInstance(project).createConfiguration("name", RunConfigurationType)`. | ||
* | ||
* @param project The project for which to create the run configuration. | ||
* @param virtualFile The virtual file to associate with the run configuration. | ||
* @return The newly created RunConfiguration, or `null` if creation failed. | ||
*/ | ||
fun createConfiguration(project: Project, virtualFile: VirtualFile): RunConfiguration? = null | ||
|
||
/** | ||
* Creates a new run configuration settings for the given project and virtual file. | ||
* | ||
* If a configuration with the same name already exists, it will be returned. | ||
* Otherwise, a new configuration is created and added to the run manager. | ||
* | ||
* @param project The project for which the configuration should be created. | ||
* @param virtualFile The virtual file for which the configuration should be created. | ||
* @return The created or found run configuration settings, or `null` if no suitable configuration could be | ||
*/ | ||
fun createRunSettings(project: Project, virtualFile: VirtualFile, testElement: PsiElement?): RunnerAndConfigurationSettings? { | ||
if (testElement != null) { | ||
val settings = createDefaultTestConfigurations(project, testElement) | ||
if (settings != null) { | ||
return settings | ||
} | ||
} | ||
|
||
val runManager = RunManager.getInstance(project) | ||
var testConfig = runManager.allConfigurationsList.firstOrNull { | ||
val runConfigureClass = runConfigurationClass(project) | ||
it.name == virtualFile.nameWithoutExtension && (it.javaClass == runConfigureClass) | ||
} | ||
|
||
var isTemporary = false | ||
|
||
// try to create config if not founds | ||
if (testConfig == null) { | ||
isTemporary = true | ||
testConfig = createConfiguration(project, virtualFile) | ||
} | ||
|
||
if (testConfig == null) { | ||
logger.warn("Failed to find test configuration for: ${virtualFile.nameWithoutExtension}") | ||
return null | ||
} | ||
|
||
val settings = runManager.findConfigurationByTypeAndName(testConfig.type, testConfig.name) | ||
if (settings == null) { | ||
logger.warn("Failed to find test configuration for: ${virtualFile.nameWithoutExtension}") | ||
return null | ||
} | ||
|
||
if (isTemporary) { | ||
settings.isTemporary = true | ||
} | ||
|
||
runManager.selectedConfiguration = settings | ||
|
||
return settings | ||
} | ||
|
||
fun PsiFile.collectPsiError(): MutableList<String> { | ||
val errors = mutableListOf<String>() | ||
val visitor = object : PsiSyntaxCheckingVisitor() { | ||
override fun visitElement(element: PsiElement) { | ||
if (element is PsiErrorElement) { | ||
errors.add("Syntax error at position ${element.textRange.startOffset}: ${element.errorDescription}") | ||
} | ||
super.visitElement(element) | ||
} | ||
} | ||
|
||
this.accept(visitor) | ||
return errors | ||
} | ||
|
||
abstract class PsiSyntaxCheckingVisitor : com.intellij.psi.PsiElementVisitor() { | ||
override fun visitElement(element: PsiElement) { | ||
runReadAction { | ||
element.children.forEach { it.accept(this) } | ||
} | ||
} | ||
} | ||
|
||
private fun createDefaultTestConfigurations(project: Project, element: PsiElement): RunnerAndConfigurationSettings? { | ||
return ConfigurationContext(element).configurationsFromContext?.firstOrNull()?.configurationSettings | ||
} | ||
|
||
/** | ||
* This function is responsible for running a file within a specified project and virtual file. | ||
* It creates a run configuration using the provided parameters and then attempts to execute it using the `ExecutionManager`. The function returns `null` if an error occurs during the configuration creation or execution process. | ||
* | ||
* @param project The project within which the file is to be run. | ||
* @param virtualFile The virtual file that represents the file to be run. | ||
* @return The result of the run operation, or `null` if an error occurred. | ||
*/ | ||
fun runFile(project: Project, virtualFile: VirtualFile, psiElement: PsiElement?): String? { | ||
try { | ||
val runTask = RunServiceTask(project, virtualFile, psiElement, this) | ||
ProgressManager.getInstance().run(runTask) | ||
} catch (e: Exception) { | ||
logger.error("Failed to run file: ${virtualFile.name}", e) | ||
return e.message | ||
} | ||
|
||
return null | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
core/src/main/kotlin/com/phodal/shirelang/runner/RunContext.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.phodal.shirelang.runner | ||
|
||
import com.intellij.execution.ExecutionListener | ||
import com.intellij.execution.Executor | ||
import com.intellij.execution.process.ProcessListener | ||
import com.intellij.execution.runners.ExecutionEnvironment | ||
import com.intellij.execution.runners.ProgramRunner | ||
import com.intellij.openapi.Disposable | ||
import java.util.concurrent.CountDownLatch | ||
|
||
class RunContext( | ||
val processListener: ProcessListener?, | ||
val executionListener: ExecutionListener?, | ||
val latch: CountDownLatch, | ||
val executor: Executor? = null, | ||
val runner: ProgramRunner<*>? = null, | ||
) : Disposable { | ||
val environments: MutableList<ExecutionEnvironment> = mutableListOf() | ||
override fun dispose() {} | ||
} |
59 changes: 59 additions & 0 deletions
59
core/src/main/kotlin/com/phodal/shirelang/runner/RunServiceExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. | ||
package com.phodal.shirelang.runner | ||
|
||
import com.intellij.execution.ExecutionListener | ||
import com.intellij.execution.process.ProcessHandler | ||
import com.intellij.execution.runners.ExecutionEnvironment | ||
|
||
class CheckExecutionListener( | ||
private val executorId: String, | ||
private val runContext: RunContext, | ||
) : ExecutionListener { | ||
override fun processStartScheduled(executorId: String, env: ExecutionEnvironment) { | ||
checkAndExecute(executorId, env) { | ||
runContext.executionListener?.processStartScheduled(executorId, env) | ||
} | ||
} | ||
|
||
override fun processNotStarted(executorId: String, env: ExecutionEnvironment) { | ||
checkAndExecute(executorId, env) { | ||
runContext.latch.countDown() | ||
runContext.executionListener?.processNotStarted(executorId, env) | ||
} | ||
} | ||
|
||
override fun processStarting(executorId: String, env: ExecutionEnvironment) { | ||
checkAndExecute(executorId, env) { | ||
runContext.executionListener?.processStarting(executorId, env) | ||
} | ||
} | ||
|
||
override fun processStarted(executorId: String, env: ExecutionEnvironment, handler: ProcessHandler) { | ||
checkAndExecute(executorId, env) { | ||
runContext.executionListener?.processStarted(executorId, env, handler) | ||
} | ||
} | ||
|
||
override fun processTerminating(executorId: String, env: ExecutionEnvironment, handler: ProcessHandler) { | ||
checkAndExecute(executorId, env) { | ||
runContext.executionListener?.processTerminating(executorId, env, handler) | ||
} | ||
} | ||
|
||
override fun processTerminated( | ||
executorId: String, | ||
env: ExecutionEnvironment, | ||
handler: ProcessHandler, | ||
exitCode: Int | ||
) { | ||
checkAndExecute(executorId, env) { | ||
runContext.executionListener?.processTerminated(executorId, env, handler, exitCode) | ||
} | ||
} | ||
|
||
private fun checkAndExecute(executorId: String, env: ExecutionEnvironment, action: () -> Unit) { | ||
if (this.executorId == executorId && env in runContext.environments) { | ||
action() | ||
} | ||
} | ||
} |
Oops, something went wrong.