// Copyright © 2010, Esko Luontola <www.orfjackal.net> // This software is released under the Apache License 2.0. // The license text is at http://www.apache.org/licenses/LICENSE-2.0 package net.orfjackal.sbt.plugin; import com.intellij.execution.BeforeRunTaskProvider; import com.intellij.execution.configurations.ModuleBasedConfiguration; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.layout.ViewContext; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.compiler.CompilationStatusListener; import com.intellij.openapi.compiler.CompilerTopics; import com.intellij.openapi.compiler.DummyCompileContext; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.Topic; public class SbtBeforeRunTaskProvider extends BeforeRunTaskProvider<SbtBeforeRunTask> { private static final Logger logger = Logger.getInstance(SbtBeforeRunTaskProvider.class.getName()); private static final Key<SbtBeforeRunTask> TASK_ID = Key.create("SBT.BeforeRunTask"); private final Project project; public SbtBeforeRunTaskProvider(Project project) { this.project = project; } public Key<SbtBeforeRunTask> getId() { return TASK_ID; } // Leda public String getName() { return "SBT"; } public String getDescription(SbtBeforeRunTask task) { String desc = task.getAction(); return desc == null ? MessageBundle.message("sbt.tasks.before.run.empty") : MessageBundle.message("sbt.tasks.before.run", desc); } // Leda public boolean isConfigurable() { return true; } // Leda public boolean canExecuteTask(RunConfiguration runConfiguration, SbtBeforeRunTask sbtBeforeRunTask) { return true; } public SbtBeforeRunTask createTask(RunConfiguration runConfiguration) { return new SbtBeforeRunTask(TASK_ID); } public boolean configureTask(RunConfiguration runConfiguration, SbtBeforeRunTask task) { SelectSbtActionDialog dialog = new SelectSbtActionDialog(project, task.getAction(), task.isRunInCurrentModule()); dialog.show(); if (!dialog.isOK()) { return false; } task.setRunInCurrentModule(dialog.isRunInCurrentModule()); task.setAction(dialog.getSelectedAction()); return true; } // Nika public boolean executeTask(DataContext dataContext, RunConfiguration runConfiguration, final SbtBeforeRunTask task) { final String action = task.getAction(); if (action == null) { return false; } boolean runResult = run(runConfiguration, task, action); if (!runResult) { final Project project = PlatformDataKeys.PROJECT.getData(dataContext); if (project != null) { notifyFailureAndActivateToolWindow(action, project); } } return runResult; } // Leda public boolean executeTask(DataContext dataContext, RunConfiguration runConfiguration, ExecutionEnvironment executionEnvironment, SbtBeforeRunTask sbtBeforeRunTask) { return executeTask(dataContext, runConfiguration, sbtBeforeRunTask); } private boolean run(RunConfiguration runConfiguration, SbtBeforeRunTask task, String action) { if (task.isRunInCurrentModule() && runConfiguration instanceof ModuleBasedConfiguration<?>) { final ModuleBasedConfiguration<?> moduleBasedConfiguration = (ModuleBasedConfiguration<?>) runConfiguration; Module[] modules = safeGetModules(moduleBasedConfiguration); if (modules.length == 1) { Module module = modules[0]; return runInModule(action, module.getName()); } } return runDirectly(action); } private Module[] safeGetModules(final ModuleBasedConfiguration<?> moduleBasedConfiguration) { // Read action is a workaround for http://youtrack.jetbrains.com/issue/SCL-4716 return ApplicationManager.getApplication().runReadAction(new Computable<Module[]>() { public Module[] compute() { return moduleBasedConfiguration.getModules(); } }); } private boolean runInModule(String action, String moduleName) { runAndWait("project " + moduleName); try { return runAndWait(action); } catch (Exception e) { logger.error(e); return false; } finally { try { runAndWait("project /"); } catch (Exception e1) { // ignore } } } private boolean runDirectly(String action) { try { return runAndWait(action); } catch (Exception e) { logger.error(e); return false; } } private boolean runAndWait(String action) { return SbtRunnerComponent.getInstance(project) .executeInBackground(action) .waitForResult(); } private void notifyFailureAndActivateToolWindow(final String action, final Project project) { ApplicationManager.getApplication().invokeAndWait(new Runnable() { public void run() { String toolWindowId = MessageBundle.message("sbt.console.id"); String message = "SBT action \"" + action + "\" failed."; ToolWindowManager.getInstance(project).notifyByBalloon(toolWindowId, MessageType.ERROR, message); final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(toolWindowId); if (window != null && !window.isVisible()) { window.activate(null, false); } SbtRunnerComponent.getInstance(project).getConsole().scrollToEnd(); } }, ModalityState.NON_MODAL); } }