diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt index 0b7d93cd910..6499aadcc96 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtScratchExecutionSession.kt @@ -7,13 +7,16 @@ package org.jetbrains.kotlin.idea.scratch.compile import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.process.CapturingProcessHandler +import com.intellij.openapi.application.ReadAction import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.Task import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.Project import com.intellij.openapi.util.Computable import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.concurrency.NonUrgentExecutor import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.filterClassFiles @@ -39,6 +42,7 @@ class KtScratchExecutionSession( private const val TIMEOUT_MS = 30000 } + @Volatile private var backgroundProcessIndicator: ProgressIndicator? = null fun execute(callback: () -> Unit) { @@ -47,57 +51,74 @@ class KtScratchExecutionSession( val expressions = file.getExpressions() if (!executor.checkForErrors(psiFile, expressions)) return - when (val result = runReadAction { KtScratchSourceFileProcessor().process(expressions) }) { - is KtScratchSourceFileProcessor.Result.Error -> return executor.errorOccurs(result.message, isFatal = true) - is KtScratchSourceFileProcessor.Result.OK -> { - LOG.printDebugMessage("After processing by KtScratchSourceFileProcessor:\n ${result.code}") + val project = file.project + ReadAction.nonBlocking { + when (val result = KtScratchSourceFileProcessor().process(expressions)) { + is KtScratchSourceFileProcessor.Result.Error -> return@nonBlocking executor.errorOccurs(result.message, isFatal = true) + is KtScratchSourceFileProcessor.Result.OK -> { + LOG.printDebugMessage("After processing by KtScratchSourceFileProcessor:\n ${result.code}") - object : Task.Backgroundable(psiFile.project, "Running Kotlin Scratch...", true) { - override fun run(indicator: ProgressIndicator) { - backgroundProcessIndicator = indicator + object : Task.Backgroundable(psiFile.project, "Running Kotlin Scratch...", true) { + override fun run(indicator: ProgressIndicator) { + backgroundProcessIndicator = indicator - val modifiedScratchSourceFile = runReadAction { - KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile) - } - - try { - val tempDir = DumbService.getInstance(project).runReadActionInSmartMode( - Computable { - compileFileToTempDir(modifiedScratchSourceFile, expressions) + val modifiedScratchSourceFile = runReadAction { + KtPsiFactory(psiFile.project).createFileWithLightClassSupport("tmp.kt", result.code, psiFile) } - ) ?: return - try { - val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path) + try { + runCommandLine(project, modifiedScratchSourceFile, expressions, psiFile, result, indicator, callback) + } catch (e: Throwable) { + if (e is ControlFlowException) throw e - LOG.printDebugMessage(commandLine.commandLineString) - - val processHandler = CapturingProcessHandler(commandLine) - val executionResult = processHandler.runProcessWithProgressIndicator(indicator, TIMEOUT_MS) - when { - executionResult.isTimeout -> { - executor.errorOccurs("Couldn't get scratch execution result - stopped by timeout ($TIMEOUT_MS ms)") - } - executionResult.isCancelled -> { - // ignore - } - else -> { - executor.parseOutput(executionResult, expressions) - } + LOG.printDebugMessage(result.code) + executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true) } - } finally { - tempDir.delete() - callback() } - } catch (e: Throwable) { - if (e is ControlFlowException) throw e - - LOG.printDebugMessage(result.code) - executor.errorOccurs(e.message ?: "Couldn't compile ${psiFile.name}", e, isFatal = true) - } + }.queue() } - }.queue() + } } + .inSmartMode(project) + .expireWith(project) + .withDocumentsCommitted(project) + .submit(NonUrgentExecutor.getInstance()) + } + + private fun runCommandLine( + project: Project, + modifiedScratchSourceFile: KtFile, + expressions: List, + psiFile: KtFile, + result: KtScratchSourceFileProcessor.Result.OK, + indicator: ProgressIndicator, + callback: () -> Unit + ) { + val tempDir = DumbService.getInstance(project).runReadActionInSmartMode(Computable { + compileFileToTempDir(modifiedScratchSourceFile, expressions) + }) ?: return + + try { + val commandLine = createCommandLine(psiFile, file.module, result.mainClassName, tempDir.path) + + LOG.printDebugMessage(commandLine.commandLineString) + + val processHandler = CapturingProcessHandler(commandLine) + val executionResult = processHandler.runProcessWithProgressIndicator(indicator, TIMEOUT_MS) + when { + executionResult.isTimeout -> { + executor.errorOccurs("Couldn't get scratch execution result - stopped by timeout ($TIMEOUT_MS ms)") + } + executionResult.isCancelled -> { + // ignore + } + else -> { + executor.parseOutput(executionResult, expressions) + } + } + } finally { + tempDir.delete() + callback() } }