IDEA-74031 Variables in command line parameters of run configuration

The first iteration:
1) New registry key allow.macros.for.run.configurations=true
2) EditorMacros are not allowed at all
3) Some of possible wanted macros like file arrays etc. are not implemented yet
This commit is contained in:
Vassiliy.Kudryashov
2018-06-15 03:44:32 +03:00
parent 537dd174d4
commit 0a286767fc
9 changed files with 114 additions and 60 deletions
@@ -14,6 +14,7 @@ import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.icons.AllIcons;
import com.intellij.ide.macro.MacroManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
@@ -322,7 +323,7 @@ public class ExecutorRegistryImpl extends ExecutorRegistry implements Disposable
if (project == null || project.isDisposed()) {
return;
}
MacroManager.getInstance().cacheMacrosPreview(e.getDataContext());
run(project, getSelectedConfiguration(project), e.getDataContext());
}
}
@@ -23,6 +23,7 @@ import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.configurations.LocatableConfiguration;
import com.intellij.execution.configurations.LocatableConfigurationBase;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.ide.macro.MacroManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -125,6 +126,7 @@ public abstract class BaseRunConfigurationAction extends ActionGroup {
@Override
public void actionPerformed(final AnActionEvent e) {
final DataContext dataContext = e.getDataContext();
MacroManager.getInstance().cacheMacrosPreview(e.getDataContext());
final ConfigurationContext context = ConfigurationContext.getFromContext(dataContext);
final RunnerAndConfigurationSettings existing = context.findExisting();
if (existing == null) {
@@ -25,6 +25,7 @@ import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.macro.MacroManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.CommonDataKeys;
@@ -328,6 +329,7 @@ public class ChooseRunConfigurationPopup implements ExecutorProvider {
public void perform(@NotNull Project project, @NotNull Executor executor, @NotNull DataContext context) {
RunnerAndConfigurationSettings config = getValue();
RunManager.getInstance(project).setSelectedConfiguration(config);
MacroManager.getInstance().cacheMacrosPreview(context);
ExecutionUtil.runConfiguration(config, executor);
}
@@ -24,6 +24,7 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.macro.MacroManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
@@ -56,6 +57,7 @@ public class FakeRerunAction extends AnAction {
public void actionPerformed(@NotNull AnActionEvent event) {
ExecutionEnvironment environment = getEnvironment(event);
if (environment != null) {
MacroManager.getInstance().cacheMacrosPreview(event.getDataContext());
ExecutionUtil.restart(environment);
}
}
@@ -19,6 +19,9 @@ import com.intellij.execution.CommonProgramRunConfigurationParameters;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.icons.AllIcons;
import com.intellij.ide.macro.EditorMacro;
import com.intellij.ide.macro.MacrosDialog;
import com.intellij.ide.macro.PromptingMacro;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
@@ -28,9 +31,12 @@ import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.PanelWithAnchor;
import com.intellij.ui.RawCommandLineEditor;
import com.intellij.ui.TextAccessor;
import com.intellij.ui.components.fields.ExpandableTextField;
import com.intellij.ui.components.fields.ExtendableTextComponent;
import com.intellij.util.PathUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -87,6 +93,26 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc
protected void initComponents() {
myProgramParametersComponent = LabeledComponent.create(new RawCommandLineEditor(),
ExecutionBundle.message("run.configuration.program.parameters"));
ExpandableTextField expandableTextField = (ExpandableTextField)myProgramParametersComponent.getComponent().getTextField();
if (Registry.is("allow.macros.for.run.configurations")) {
expandableTextField.addExtension(new ExtendableTextComponent.Extension() {
@Override
public Icon getIcon(boolean hovered) {
return AllIcons.General.Add;
}
@Override
public String getTooltip() {
return "Insert Macros";
}
@Override
public Runnable getActionOnClick() {
return () -> MacrosDialog.show(expandableTextField,
macro -> !(macro instanceof PromptingMacro) && !(macro instanceof EditorMacro));
}
});
}
FileChooserDescriptor fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
//noinspection DialogTitleCapitalization
@@ -5,6 +5,10 @@ import com.intellij.execution.CommonProgramRunConfigurationParameters;
import com.intellij.execution.configurations.ModuleBasedConfiguration;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.execution.configurations.SimpleProgramParameters;
import com.intellij.ide.macro.EditorMacro;
import com.intellij.ide.macro.Macro;
import com.intellij.ide.macro.MacroManager;
import com.intellij.ide.macro.PromptingMacro;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
@@ -13,6 +17,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ExternalProjectSystemRegistry;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.EnvironmentUtil;
@@ -23,6 +28,7 @@ import org.jetbrains.annotations.SystemIndependent;
import org.jetbrains.jps.model.serialization.PathMacroUtil;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -37,7 +43,7 @@ public class ProgramParametersConfigurator {
Project project = configuration.getProject();
Module module = getModule(configuration);
parameters.getProgramParametersList().addParametersString(expandPath(configuration.getProgramParameters(), module, project));
parameters.getProgramParametersList().addParametersString(expandMacros(expandPath(configuration.getProgramParameters(), module, project)));
parameters.setWorkingDirectory(getWorkingDir(configuration, project, module));
@@ -51,6 +57,23 @@ public class ProgramParametersConfigurator {
parameters.setPassParentEnvs(configuration.isPassParentEnvs());
}
private static String expandMacros(String path) {
if (Registry.is("allow.macros.for.run.configurations")) {
Collection<Macro> macros = MacroManager.getInstance().getMacros();
for (Macro macro: macros) {
String value = StringUtil.notNullize(
macro instanceof PromptingMacro || macro instanceof EditorMacro
? null :
macro.preview(), "");
if (StringUtil.containsWhitespaces(value)) {
value = "\"" + value + "\"";
}
path = path.replace("$" + macro.getName() + "$", value);
}
}
return path;
}
@Nullable
public String getWorkingDir(CommonProgramRunConfigurationParameters configuration, Project project, Module module) {
String workingDirectory = configuration.getWorkingDirectory();
@@ -22,59 +22,89 @@ import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.DoubleClickListener;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SeparatorFactory;
import com.intellij.ui.components.JBList;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public final class MacrosDialog extends DialogWrapper {
private final DefaultListModel myMacrosModel;
private final JList myMacrosList;
private final JTextArea myPreviewTextarea;
private final DefaultListModel<MacroWrapper> myMacrosModel = new DefaultListModel<>();
private final JBList<MacroWrapper> myMacrosList = new JBList<>(myMacrosModel);
private final JTextArea myPreviewTextarea = new JTextArea();
public MacrosDialog(Project project) {
super(project, true);
MacroManager.getInstance().cacheMacrosPreview(SimpleDataContext.getProjectContext(project));
setTitle(IdeBundle.message("title.macros"));
setOKButtonText(IdeBundle.message("button.insert"));
myMacrosModel = new DefaultListModel();
myMacrosList = new JBList(myMacrosModel);
myPreviewTextarea = new JTextArea();
init();
}
public MacrosDialog(Component parent) {
super(parent, true);
MacroManager.getInstance().cacheMacrosPreview(DataManager.getInstance().getDataContext(parent));
setTitle(IdeBundle.message("title.macros"));
setOKButtonText(IdeBundle.message("button.insert"));
myMacrosModel = new DefaultListModel();
myMacrosList = new JBList(myMacrosModel);
myPreviewTextarea = new JTextArea();
init();
}
public static void show(@NotNull JTextComponent textComponent, @Nullable Condition<? super Macro> filter) {
MacrosDialog dialog = new MacrosDialog(textComponent);
if (filter != null) {
for (int i = 0; i < dialog.myMacrosModel.size(); i++) {
if (!filter.value(dialog.myMacrosModel.get(i).myMacro)) {
dialog.myMacrosModel.remove(i);
i--;
}
}
if (dialog.myMacrosModel.size() > 0){
dialog.myMacrosList.setSelectedIndex(0);
}
else{
dialog.setOKActionEnabled(false);
}
}
if (dialog.showAndGet() && dialog.getSelectedMacro() != null) {
String macro = dialog.getSelectedMacro().getName();
int position = textComponent.getCaretPosition();
int selectionStart = textComponent.getSelectionStart();
int selectionEnd = textComponent.getSelectionEnd();
try {
if (selectionStart < selectionEnd) {
textComponent.getDocument().remove(selectionStart, selectionEnd - selectionStart);
position = selectionStart;
}
textComponent.getDocument().insertString(position, "$" + macro + "$", null);
textComponent.setCaretPosition(position + macro.length() + 2);
} catch (BadLocationException ignored) {
}
}
IdeFocusManager.findInstance().requestFocus(textComponent, true);
}
@Override
protected void init() {
super.init();
java.util.List<Macro> macros = new ArrayList<>(MacroManager.getInstance().getMacros());
setTitle(IdeBundle.message("title.macros"));
setOKButtonText(IdeBundle.message("button.insert"));
List<Macro> macros = new ArrayList<>(MacroManager.getInstance().getMacros());
Collections.sort(macros, new Comparator<Macro>() {
@Override
public int compare(Macro macro1, Macro macro2) {
@@ -15,13 +15,7 @@
*/
package com.intellij.ui;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.components.fields.ExpandableTextField;
import com.intellij.util.Function;
@@ -31,15 +25,10 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
public class RawCommandLineEditor extends JPanel implements TextAccessor {
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.RawCommandLineEditor");
private final JTextField myEditor;
private final TextFieldWithBrowseButton myTextField;
private final ExpandableTextField myEditor;
private String myDialogCaption = "";
public RawCommandLineEditor() {
@@ -48,30 +37,8 @@ public class RawCommandLineEditor extends JPanel implements TextAccessor {
public RawCommandLineEditor(final Function<String, List<String>> lineParser, final Function<List<String>, String> lineJoiner) {
super(new BorderLayout());
if (Registry.is("raw.command.line.editor.dialog")) {
myTextField = new TextFieldWithBrowseButton(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (myDialogCaption == null) {
Container parent = getParent();
if (parent instanceof LabeledComponent) {
parent = parent.getParent();
}
LOG.error("Did not call RawCommandLineEditor.setDialogCaption() in " + parent);
myDialogCaption = "Parameters";
}
Messages.showTextAreaDialog(myTextField.getTextField(), myDialogCaption, "EditParametersPopupWindow", lineParser, lineJoiner);
}
});
myEditor = myTextField.getTextField();
myTextField.setButtonIcon(AllIcons.Actions.ShowViewer);
add(myTextField, BorderLayout.CENTER);
}
else {
myTextField = null;
myEditor = new ExpandableTextField(lineParser, lineJoiner);
add(myEditor, BorderLayout.CENTER);
}
myEditor = new ExpandableTextField(lineParser, lineJoiner);
add(myEditor, BorderLayout.CENTER);
setDescriptor(null);
}
@@ -83,10 +50,12 @@ public class RawCommandLineEditor extends JPanel implements TextAccessor {
InsertPathAction.addTo(myEditor, descriptor, insertSystemDependentPaths);
}
@Deprecated
public String getDialogCaption() {
return myDialogCaption;
}
@Deprecated
public void setDialogCaption(String dialogCaption) {
myDialogCaption = dialogCaption != null ? dialogCaption : "";
}
@@ -116,6 +85,6 @@ public class RawCommandLineEditor extends JPanel implements TextAccessor {
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
(myTextField != null ? myTextField : myEditor).setEnabled(enabled);
myEditor.setEnabled(enabled);
}
}
@@ -913,9 +913,6 @@ emmet.segments.limit=50
emmet.template.length.limit.kilobytes=15
command.line.execution.timeout=30
raw.command.line.editor.dialog=false
raw.command.line.editor.dialog.description=Use dialog to edit command line
ide.settings.keymap.input.method.enabled=false
ide.settings.keymap.input.method.enabled.description=Use input method instead of simple key event to enter shortcuts.
@@ -1354,6 +1351,8 @@ run.configuration.max.name.length.description=When name of run configuration exc
suggest.all.run.configurations.from.context=false
suggest.all.run.configurations.from.context.description=With the option enabled, all run configuration from context will be suggested to\
run or create in spite of existing run configuration in the context
allow.macros.for.run.configurations=true
allow.macros.for.run.configurations.description=Enables context-dependent macros like $FileName$ or $SelectedText$ in Run Configurations
pause.indexing.in.power.save.mode=false