diff --git a/plugins/sh/resources/META-INF/plugin.xml b/plugins/sh/resources/META-INF/plugin.xml index 7cfd92e05b12..a1d9ec14b4e0 100644 --- a/plugins/sh/resources/META-INF/plugin.xml +++ b/plugins/sh/resources/META-INF/plugin.xml @@ -37,7 +37,9 @@ Adds support for working with shell script files + + diff --git a/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java new file mode 100644 index 000000000000..ac8ad2cb0246 --- /dev/null +++ b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java @@ -0,0 +1,167 @@ +// Copyright 2000-2019 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.intellij.sh.run; + +import com.intellij.execution.BeforeRunTask; +import com.intellij.execution.BeforeRunTaskProvider; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.compound.ConfigurationSelectionUtil; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.impl.RunConfigurationBeforeRunProvider; +import com.intellij.execution.impl.RunManagerImpl; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; +import com.intellij.sh.ShLanguage; +import com.intellij.util.containers.ContainerUtil; +import icons.SHIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.AsyncPromise; +import org.jetbrains.concurrency.Promise; + +import javax.swing.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ShBeforeRunTaskProvider extends BeforeRunTaskProvider { + private static final String SH_BEFORE_KEY_PREFIX = "Sh.BeforeRunTask"; + private static final Key ID = Key.create(SH_BEFORE_KEY_PREFIX); + private static final Map> KEY_MAP = new HashMap<>(); + + @Override + public Key getId() { + return ID; + } + + @Override + public String getName() { + return "Run " + ShLanguage.INSTANCE.getID(); + } + + @Override + public String getDescription(ShBeforeRunTask task) { + RunnerAndConfigurationSettings configurationSettings = task.getSettings(); + return configurationSettings != null ? "Run " + ShLanguage.INSTANCE.getID() + " '" + configurationSettings.getName() + "'" + : "Run " + ShLanguage.INSTANCE.getID(); + } + + @Nullable + @Override + public Icon getIcon() { + return SHIcons.ShFile; + } + + @Nullable + @Override + public Icon getTaskIcon(ShBeforeRunTask task) { + return SHIcons.ShFile; + } + + @Nullable + @Override + public ShBeforeRunTask createTask(@NotNull RunConfiguration runConfiguration) { + return new ShBeforeRunTask(runConfiguration.getProject()); + } + + @Override + public boolean isConfigurable() { + return true; + } + + @Override + public Promise configureTask(@NotNull DataContext context, + @NotNull RunConfiguration currentConfig, + @NotNull ShBeforeRunTask task) { + AsyncPromise result = new AsyncPromise<>(); + Project project = currentConfig.getProject(); + if (project == null || !project.isInitialized()) { + result.setResult(false); + return result; + } + + RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project); + List configurations = RunManagerImpl.getInstanceImpl(project).getAllSettings().stream() + .map(RunnerAndConfigurationSettings::getConfiguration) + .filter(config -> config instanceof ShRunConfiguration && config != currentConfig) + .collect(Collectors.toList()); + + ConfigurationSelectionUtil.createPopup(project, runManager, configurations, (selectedConfigs, selectedTarget) -> { + RunConfiguration selectedConfig = ContainerUtil.getFirstItem(selectedConfigs); + RunnerAndConfigurationSettings selectedSettings = selectedConfig == null ? null : runManager.getSettings(selectedConfig); + + if (selectedSettings != null) { + task.setSettings(selectedSettings); + result.setResult(true); + } + else { + result.setResult(false); + } + }).showInBestPositionFor(context); + return result; + } + + @Override + public boolean executeTask(@NotNull DataContext context, + @NotNull RunConfiguration configuration, + @NotNull ExecutionEnvironment env, + @NotNull ShBeforeRunTask task) { + RunnerAndConfigurationSettings configurationSettings = task.getSettings(); + if (configurationSettings == null) return false; + + Key userDataKey = getRunBeforeUserDataKey(configurationSettings.getConfiguration()); + configuration.getProject().putUserData(userDataKey, true); + boolean result = RunConfigurationBeforeRunProvider.doExecuteTask(env, configurationSettings, null); + configuration.getProject().putUserData(userDataKey, false); + return result; + } + + static Key getRunBeforeUserDataKey(@NotNull RunConfiguration runConfiguration) { + return KEY_MAP.computeIfAbsent(runConfiguration.getName(), key -> Key.create(SH_BEFORE_KEY_PREFIX + "_" + key)); + } + + static class ShBeforeRunTask extends BeforeRunTask implements PersistentStateComponent { + private ShBeforeRunTaskState myState = new ShBeforeRunTaskState(); + private RunnerAndConfigurationSettings mySettings; + private final Project myProject; + + protected ShBeforeRunTask(@NotNull Project project) { + super(ID); + myProject = project; + } + + @Nullable + @Override + public ShBeforeRunTaskState getState() { + return myState; + } + + @Override + public void loadState(@NotNull ShBeforeRunTaskState state) { + state.resetModificationCount(); + myState = state; + } + + public void setSettings(@Nullable RunnerAndConfigurationSettings settings) { + mySettings = settings; + if (settings == null) { + myState.setRunConfigType(""); + myState.setRunConfigName(""); + return; + } + myState.setRunConfigType(settings.getType().getId()); + myState.setRunConfigName(settings.getName()); + } + + @Nullable + public RunnerAndConfigurationSettings getSettings() { + if (mySettings != null) return mySettings; + return myState != null && myState.getRunConfigType() != null && myState.getRunConfigName() != null + ? mySettings = RunManagerImpl.getInstanceImpl(myProject).findConfigurationByTypeAndName(myState.getRunConfigType(), myState.getRunConfigName()) + : null; + } + } +} diff --git a/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt new file mode 100644 index 000000000000..94fef1b2f35a --- /dev/null +++ b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2019 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.intellij.sh.run + +import com.intellij.openapi.components.BaseState +import com.intellij.util.xmlb.annotations.Attribute + +class ShBeforeRunTaskState : BaseState() { + @get:Attribute("RUN_CONFIG_TYPE") + var runConfigType by string() + @get:Attribute("RUN_CONFIG_NAME") + var runConfigName by string() +} \ No newline at end of file diff --git a/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java b/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java index e77a6c566466..59cbb6b70e86 100644 --- a/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java +++ b/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java @@ -1,11 +1,7 @@ // Copyright 2000-2019 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.intellij.sh.run; -import com.intellij.execution.DefaultExecutionResult; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionResult; -import com.intellij.execution.Executor; -import com.intellij.execution.Platform; +import com.intellij.execution.*; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.PtyCommandLine; import com.intellij.execution.configurations.RunProfileState; @@ -16,6 +12,7 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.ui.ConsoleView; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -32,7 +29,6 @@ import java.util.Arrays; import static com.intellij.sh.ShStringUtil.quote; public class ShRunConfigurationProfileState implements RunProfileState { - private static final String WHITESPACE = " "; private final Project myProject; private final ShRunConfiguration myRunConfiguration; @@ -44,8 +40,11 @@ public class ShRunConfigurationProfileState implements RunProfileState { @Nullable @Override public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + Key userDataKey = ShBeforeRunTaskProvider.getRunBeforeUserDataKey(myRunConfiguration); + Boolean userDataValue = myProject.getUserData(userDataKey); + boolean isRunBeforeConfig = userDataValue != null && userDataValue.booleanValue(); ShRunner shRunner = ServiceManager.getService(myProject, ShRunner.class); - if (shRunner == null || !shRunner.isAvailable(myProject)) { + if (shRunner == null || !shRunner.isAvailable(myProject) || isRunBeforeConfig) { return buildExecutionResult(); } shRunner.run(buildCommand(), myRunConfiguration.getScriptWorkingDirectory());