diff --git a/src/main/scala/intellij/haskell/external/component/StackProjectManager.scala b/src/main/scala/intellij/haskell/external/component/StackProjectManager.scala index 62fdeb94..875b1601 100644 --- a/src/main/scala/intellij/haskell/external/component/StackProjectManager.scala +++ b/src/main/scala/intellij/haskell/external/component/StackProjectManager.scala @@ -107,13 +107,13 @@ object StackProjectManager { val title = (if (update) "Updating" else "Installing") + " Haskell tools" - ProgressManager.getInstance().run(new Task.Backgroundable(project, title, false, PerformInBackgroundOption.ALWAYS_BACKGROUND) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, title, true, PerformInBackgroundOption.ALWAYS_BACKGROUND) { private def isToolAvailable(progressIndicator: ProgressIndicator, tool: HTool) = { HaskellSettingsState.useCustomTools || { if (!GlobalInfo.toolPath(tool).exists() || update) { progressIndicator.setText(s"Busy with installing ${tool.name} in ${GlobalInfo.toolsBinPath}") - StackCommandLine.installTool(project, tool.name) + StackCommandLine.installTool(project, progressIndicator, tool.name) } else { true } diff --git a/src/main/scala/intellij/haskell/external/execution/CommandLine.scala b/src/main/scala/intellij/haskell/external/execution/CommandLine.scala index 63b08106..f99544c5 100644 --- a/src/main/scala/intellij/haskell/external/execution/CommandLine.scala +++ b/src/main/scala/intellij/haskell/external/execution/CommandLine.scala @@ -19,9 +19,11 @@ package intellij.haskell.external.execution import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.configurations.GeneralCommandLine.ParentEnvironmentType import com.intellij.execution.process._ +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.vfs.VfsUtil +import com.intellij.util.io.BaseOutputReader import intellij.haskell.HaskellNotificationGroup import org.jetbrains.jps.incremental.messages.BuildMessage import org.jetbrains.jps.incremental.messages.BuildMessage.Kind @@ -50,6 +52,23 @@ object CommandLine { run3(None, VfsUtil.getUserHomeDir.getPath, commandPath, arguments, timeoutInMillis, notifyBalloonError, ignoreExitCode, logOutput) } + def runWithProgressIndicator(project: Project, workDir: Option[String], commandPath: String, arguments: Seq[String], progressIndicator: Option[ProgressIndicator]): CapturingProcessHandler = { + val commandLine = createCommandLine(workDir.getOrElse(project.getBasePath), commandPath, arguments) + + new CapturingProcessHandler(commandLine) { + override protected def createProcessAdapter(processOutput: ProcessOutput): CapturingProcessAdapter = { + progressIndicator match { + case Some(pi) => new CapturingProcessToProgressIndicator(project, pi) + case None => super.createProcessAdapter(processOutput) + } + } + + override def readerOptions(): BaseOutputReader.Options = { + BaseOutputReader.Options.NON_BLOCKING + } + } + } + private def run3(project: Option[Project], workDir: String, commandPath: String, arguments: Seq[String], timeoutInMillis: Long = DefaultTimeout.toMillis, notifyBalloonError: Boolean = DefaultNotifyBalloonError, ignoreExitCode: Boolean = DefaultIgnoreExitCode, logOutput: Boolean = DefaultLogOutput): ProcessOutput = { @@ -121,6 +140,13 @@ private class CapturingProcessToLog(val project: Option[Project], val cmd: Gener } } +private class CapturingProcessToProgressIndicator(project: Project, progressIndicator: ProgressIndicator) extends CapturingProcessAdapter() { + + override def onTextAvailable(event: ProcessEvent, outputType: Key[_]): Unit = { + progressIndicator.setText2(event.getText) + } +} + sealed trait CaptureOutput diff --git a/src/main/scala/intellij/haskell/external/execution/StackCommandLine.scala b/src/main/scala/intellij/haskell/external/execution/StackCommandLine.scala index e267c8c5..fa7cc273 100644 --- a/src/main/scala/intellij/haskell/external/execution/StackCommandLine.scala +++ b/src/main/scala/intellij/haskell/external/execution/StackCommandLine.scala @@ -59,7 +59,19 @@ object StackCommandLine { }) } - def installTool(project: Project, toolName: String): Boolean = { + def runWithProgressIndicator(project: Project, workDir: Option[String], arguments: Seq[String], progressIndicator: Option[ProgressIndicator]): Option[CapturingProcessHandler] = { + HaskellSdkType.getStackBinaryPath(project).map(stackPath => { + CommandLine.runWithProgressIndicator( + project, + workDir, + stackPath, + arguments, + progressIndicator + ) + }) + } + + def installTool(project: Project, progressIndicator: ProgressIndicator, toolName: String): Boolean = { import intellij.haskell.GlobalInfo._ val systemGhcOption = if (StackYamlComponent.isNixEnabled(project) || !HaskellSettingsState.useSystemGhc) { Seq() @@ -67,8 +79,21 @@ object StackCommandLine { Seq("--system-ghc") } val arguments = systemGhcOption ++ Seq("-j1", "--stack-root", toolsStackRootPath.getPath, "--resolver", StackageLtsVersion, "--local-bin-path", toolsBinPath.getPath, "install", toolName) - val processOutput = run(project, arguments, -1, logOutput = true, notifyBalloonError = true, workDir = Some(VfsUtil.getUserHomeDir.getPath), enableExtraArguments = false) - processOutput.exists(o => o.getExitCode == 0 && !o.isTimeout) + + val result = runWithProgressIndicator(project, workDir = Some(VfsUtil.getUserHomeDir.getPath), arguments, Some(progressIndicator)).exists(handler => { + val output = handler.runProcessWithProgressIndicator(progressIndicator) + + if (output.isCancelled) { + handler.destroyProcess() + } + + if (output.getExitCode != 0) { + HaskellNotificationGroup.logErrorBalloonEvent(project, output.getStderr) + } + output.getExitCode == 0 && !output.isCancelled && !output.isTimeout + }) + + result } def updateStackIndex(project: Project): Option[ProcessOutput] = { diff --git a/src/main/scala/intellij/haskell/inspection/HLintQuickfix.scala b/src/main/scala/intellij/haskell/inspection/HLintQuickfix.scala index aa8b39ec..27f4b785 100644 --- a/src/main/scala/intellij/haskell/inspection/HLintQuickfix.scala +++ b/src/main/scala/intellij/haskell/inspection/HLintQuickfix.scala @@ -23,6 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.{PsiDocumentManager, PsiElement, PsiFile} import intellij.haskell.action.{HindentReformatAction, SelectionContext} import intellij.haskell.annotator.HaskellAnnotator +import intellij.haskell.external.component.StackProjectManager import intellij.haskell.psi.{HaskellElementFactory, HaskellPsiUtil, HaskellTypes} import intellij.haskell.util.HaskellFileUtil @@ -71,7 +72,9 @@ class HLintQuickfix(startElement: PsiElement, endElement: PsiElement, startLineN e.getTextRange.getEndOffset, e.getText ) - HindentReformatAction.format(psiFile, Some(context)) + if (StackProjectManager.isHindentAvailable(project)) { + HindentReformatAction.format(psiFile, Some(context)) + } }) HaskellFileUtil.saveFile(psiFile)