diff options
author | Paul Pazderski | 2019-04-05 17:19:52 +0000 |
---|---|---|
committer | Paul Pazderski | 2019-07-03 08:09:41 +0000 |
commit | 7907da8e73316345d971683cc5671026c313da1e (patch) | |
tree | 74f2688810cdfda89b535978d3e431b0cd2b943d | |
parent | 4b951888593050d8530d446ce36cf084fa200458 (diff) | |
download | eclipse.platform.debug-7907da8e73316345d971683cc5671026c313da1e.tar.gz eclipse.platform.debug-7907da8e73316345d971683cc5671026c313da1e.tar.xz eclipse.platform.debug-7907da8e73316345d971683cc5671026c313da1e.zip |
Bug 32205 - [console] Add launch option to merge process outputI20190703-0640
Also make use of output merge option in external tool launch.
Change-Id: Ibc3cec8df076a4cea3f83e37fa2640115dd3f49b
Signed-off-by: Paul Pazderski <paul-eclipse@ppazderski.de>
16 files changed, 437 insertions, 286 deletions
diff --git a/org.eclipse.core.externaltools/plugin.xml b/org.eclipse.core.externaltools/plugin.xml index 29142abdc..b60e930e3 100644 --- a/org.eclipse.core.externaltools/plugin.xml +++ b/org.eclipse.core.externaltools/plugin.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.4"?> <!-- - Copyright (c) 2005, 2010 IBM Corporation and others. + Copyright (c) 2005, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 @@ -22,14 +22,16 @@ delegate="org.eclipse.core.externaltools.internal.launchConfigurations.ProgramLaunchDelegate" category="org.eclipse.ui.externaltools" modes="run" - id="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType"> + id="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType" + allowOutputMerging="true"> </launchConfigurationType> <launchConfigurationType name="%Program.externalTools" delegate="org.eclipse.core.externaltools.internal.launchConfigurations.ProgramLaunchDelegate" category="org.eclipse.ui.externaltools.builder" modes="run" - id="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType"> + id="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType" + allowOutputMerging="true"> </launchConfigurationType> </extension> <extension diff --git a/org.eclipse.core.externaltools/src/org/eclipse/core/externaltools/internal/launchConfigurations/ProgramLaunchDelegate.java b/org.eclipse.core.externaltools/src/org/eclipse/core/externaltools/internal/launchConfigurations/ProgramLaunchDelegate.java index 1abe8c1a9..b7a0e2968 100644 --- a/org.eclipse.core.externaltools/src/org/eclipse/core/externaltools/internal/launchConfigurations/ProgramLaunchDelegate.java +++ b/org.eclipse.core.externaltools/src/org/eclipse/core/externaltools/internal/launchConfigurations/ProgramLaunchDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -50,6 +50,17 @@ public class ProgramLaunchDelegate extends LaunchConfigurationDelegate { private static final String ATTR_LAUNCH_IN_BACKGROUND = "org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND"; //$NON-NLS-1$ /** + * Launch configuration attribute - a boolean value indicating whether a + * configuration should be launched with merged error and standard output. + * Default value is <code>false</code>. + * <p> + * This constant is defined in org.eclipse.debug.ui, but has to be copied + * here to support headless launching. + * </p> + */ + private static final String ATTR_MERGE_OUTPUT = "org.eclipse.debug.ui.ATTR_MERGE_OUTPUT"; //$NON-NLS-1$ + + /** * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, * java.lang.String, org.eclipse.debug.core.ILaunch, * org.eclipse.core.runtime.IProgressMonitor) @@ -110,7 +121,8 @@ public class ProgramLaunchDelegate extends LaunchConfigurationDelegate { return; } - Process p = DebugPlugin.exec(cmdLine, workingDir, envp); + boolean mergeOutput = configuration.getAttribute(ATTR_MERGE_OUTPUT, false); + Process p = DebugPlugin.exec(cmdLine, workingDir, envp, mergeOutput); IProcess process = null; // add process type to process attributes diff --git a/org.eclipse.debug.core/META-INF/MANIFEST.MF b/org.eclipse.debug.core/META-INF/MANIFEST.MF index 0efbd67be..820ddc853 100644 --- a/org.eclipse.debug.core/META-INF/MANIFEST.MF +++ b/org.eclipse.debug.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.debug.core; singleton:=true -Bundle-Version: 3.13.400.qualifier +Bundle-Version: 3.14.0.qualifier Bundle-ClassPath: . Bundle-Activator: org.eclipse.debug.core.DebugPlugin Bundle-Vendor: %providerName diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java index b1d681ee0..c11335107 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -868,12 +868,60 @@ public class DebugPlugin extends Plugin { * @since 3.0 */ public static Process exec(String[] cmdLine, File workingDirectory, String[] envp) throws CoreException { - Process p= null; + return exec(cmdLine, workingDirectory, envp, false); + } + + /** + * Convenience method that performs a runtime exec on the given command line + * in the context of the specified working directory, and returns the + * resulting process. If the current runtime does not support the + * specification of a working directory, the status handler for error code + * <code>ERR_WORKING_DIRECTORY_NOT_SUPPORTED</code> is queried to see if the + * exec should be re-executed without specifying a working directory. + * + * @param cmdLine the command line + * @param workingDirectory the working directory, or <code>null</code> + * @param envp the environment variables set in the process, or + * <code>null</code> + * @param mergeOutput if <code>true</code> the error stream will be merged + * with standard output stream and both can be read through the + * same output stream + * @return the resulting process or <code>null</code> if the exec is + * canceled + * @exception CoreException if the exec fails + * @see Runtime + * + * @since 3.14 + */ + public static Process exec(String[] cmdLine, File workingDirectory, String[] envp, boolean mergeOutput) throws CoreException { + Process p = null; try { - if (workingDirectory == null) { - p= Runtime.getRuntime().exec(cmdLine, envp); + // starting with and without merged output could be done with the + // same process builder approach but since the handling of + // environment variables is slightly different between + // ProcessBuilder and Runtime.exec only the new option uses process + // builder to not break existing caller of this method + if (mergeOutput) { + ProcessBuilder pb = new ProcessBuilder(cmdLine); + pb.directory(workingDirectory); + pb.redirectErrorStream(mergeOutput); + if (envp != null) { + Map<String, String> env = pb.environment(); + env.clear(); + for (String e : envp) { + int index = e.indexOf('='); + if (index != -1) { + env.put(e.substring(0, index), e.substring(index + 1)); + } + } + } + p = pb.start(); } else { - p= Runtime.getRuntime().exec(cmdLine, envp, workingDirectory); + if (workingDirectory == null) { + p = Runtime.getRuntime().exec(cmdLine, envp); + } else { + p = Runtime.getRuntime().exec(cmdLine, envp, workingDirectory); + } } } catch (IOException e) { Status status = new Status(IStatus.ERROR, getUniqueIdentifier(), ERROR, DebugCoreMessages.DebugPlugin_0, e); @@ -885,8 +933,8 @@ public class DebugPlugin extends Plugin { if (handler != null) { Object result = handler.handleStatus(status, null); - if (result instanceof Boolean && ((Boolean)result).booleanValue()) { - p= exec(cmdLine, null); + if (result instanceof Boolean && ((Boolean) result).booleanValue()) { + p = exec(cmdLine, null); } } } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java index f28c69f25..094f7f2ca 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -374,4 +374,14 @@ public interface ILaunchConfigurationType extends IAdaptable { * @since 3.13 */ boolean supportsCommandLine(); + + /** + * Returns whether this type of launch configuration supports launching + * processes with error stream redirected and merged with standard output + * stream. + * + * @return whether this kind of launch configuration supports output merging + * @since 3.14 + */ + boolean supportsOutputMerging(); } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java index b77c5c957..ad8c42b5e 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2018 IBM Corporation and others. + * Copyright (c) 2006, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -365,4 +365,14 @@ public interface IConfigurationElementConstants { * @since 3.13 */ String ALLOW_COMMANDLINE = "allowCommandLine"; //$NON-NLS-1$ + + /** + * The allowOutputMerging node name for a configuration element + * <p> + * Equal to the word: <code>allowOutputMerging</code> + * </p> + * + * @since 3.14 + */ + String ALLOW_OUTPUT_MERGING = "allowOutputMerging"; //$NON-NLS-1$ } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java index ee5cfb8a0..5ced04ca5 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -494,5 +494,16 @@ public class LaunchConfigurationType extends PlatformObject implements ILaunchCo } return false; } + + @Override + public boolean supportsOutputMerging() { + String allowOutputMergingString = fElement.getAttribute(IConfigurationElementConstants.ALLOW_OUTPUT_MERGING); + if (allowOutputMergingString != null) { + if (allowOutputMergingString.equalsIgnoreCase("true")) { //$NON-NLS-1$ + return true; + } + } + return false; + } } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchDelegate.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchDelegate.java index c63e0aaae..303d37875 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchDelegate.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchDelegate.java @@ -30,23 +30,28 @@ import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; import com.ibm.icu.text.MessageFormat; /** - * Proxy to a launch delegate extension - * Clients can contribute launch delegates through the <code>launchDelegates</code> extension point - * + * Proxy to a launch delegate extension. + * <p> + * Clients can contribute launch delegates through the + * <code>launchDelegates</code> extension point + * </p> + * <p> * Example contribution of the local java launch delegate + * </p> + * * <pre> - * <extension point="org.eclipse.debug.core.launchDelegates"> - <launchDelegate - delegate="org.eclipse.jdt.launching.JavaLaunchDelegate" - id="org.eclipse.jdt.launching.localJavaApplicationDelegate" - modes="run, debug" - name="%localJavaApplication" - type="org.eclipse.jdt.launching.localJavaApplication"> - <modeCombination - modes="run, profile"> - perspective="com.example.Perspective"> - </modeCombination> - </launchDelegate> + * <extension point="org.eclipse.debug.core.launchDelegates"> + * <launchDelegate + * delegate="org.eclipse.jdt.launching.JavaLaunchDelegate" + * id="org.eclipse.jdt.launching.localJavaApplicationDelegate" + * modes="run, debug" + * name="%localJavaApplication" + * type="org.eclipse.jdt.launching.localJavaApplication"> + * <modeCombination + * modes="run, profile"> + * perspective="com.example.Perspective"> + * </modeCombination> + * </launchDelegate> * </pre> * * Clients are NOT intended to subclass this class diff --git a/org.eclipse.debug.core/pom.xml b/org.eclipse.debug.core/pom.xml index 7784584c6..bc7fdee0e 100644 --- a/org.eclipse.debug.core/pom.xml +++ b/org.eclipse.debug.core/pom.xml @@ -18,6 +18,6 @@ </parent> <groupId>org.eclipse.debug</groupId> <artifactId>org.eclipse.debug.core</artifactId> - <version>3.13.400-SNAPSHOT</version> + <version>3.14.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/org.eclipse.debug.core/schema/launchConfigurationTypes.exsd b/org.eclipse.debug.core/schema/launchConfigurationTypes.exsd index 94d883ba8..b16af6f70 100644 --- a/org.eclipse.debug.core/schema/launchConfigurationTypes.exsd +++ b/org.eclipse.debug.core/schema/launchConfigurationTypes.exsd @@ -170,6 +170,14 @@ Since 3.3, the <code>sourceLocatorId</code> can also be specified vi </documentation> </annotation> </attribute> + <attribute name="allowOutputMerging" type="boolean"> + <annotation> + <documentation> + specifies whether this launch configuration type supports output merging. A launch configuration which singals support must check the launch configuration attribute "org.eclipse.debug.ui.ATTR_MERGE_OUTPUT" and if its value is true perform the launch in a way that stderr and stdout are merged and both can be read through stdout. + Defaults to <code>false</code> if not specified. This attribute was added in 4.13 release. + </documentation> + </annotation> + </attribute> </complexType> </element> @@ -255,7 +263,7 @@ The value of the attribute <b>migrationDelegate</b> must be a fully <meta.section type="copyright"/> </appinfo> <documentation> - Copyright (c) 2000, 2018 IBM Corporation and others.<br> + Copyright (c) 2000, 2019 IBM Corporation and others.<br> This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which diff --git a/org.eclipse.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.debug.ui/META-INF/MANIFEST.MF index 17c582b9e..539cd0a87 100644 --- a/org.eclipse.debug.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.debug.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.debug.ui; singleton:=true -Bundle-Version: 3.14.200.qualifier +Bundle-Version: 3.15.0.qualifier Bundle-Activator: org.eclipse.debug.internal.ui.DebugUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/org.eclipse.debug.ui/pom.xml b/org.eclipse.debug.ui/pom.xml index fb42dfb7b..ff0d26020 100644 --- a/org.eclipse.debug.ui/pom.xml +++ b/org.eclipse.debug.ui/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.debug</groupId> <artifactId>org.eclipse.debug.ui</artifactId> - <version>3.14.200-SNAPSHOT</version> + <version>3.15.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> <properties> <code.ignoredWarnings>-warn:+resource,-deprecation,unavoidableGenericProblems</code.ignoredWarnings> diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java index 3588aa74a..d2ed415e3 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java @@ -46,6 +46,7 @@ public class LaunchConfigurationsMessages extends NLS { public static String CommonTab_19; public static String CommonTab_2; public static String CommonTab_20; + public static String CommonTab_21; public static String CommonTab_3; public static String CommonTab_4; public static String CommonTab_5; diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties index 7a3a36dfb..f042a9e5c 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties @@ -39,6 +39,7 @@ CommonTab_18=Select a resource to redirect input from: CommonTab_19=File System... CommonTab_2=Defa&ult - inherited ({0}) CommonTab_20=Variables... +CommonTab_21=&Merge standard and error output (disables coloring of error output) CommonTab_3=Oth&er CommonTab_4=Standard Input and Output CommonTab_5=&Allocate console (necessary for input) diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java index 9ac350da1..8f1191af3 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -123,21 +123,23 @@ public class CommonTab extends AbstractLaunchConfigurationTab { private static final String BAD_CONTAINER = "bad_container_name"; //$NON-NLS-1$ // Local/shared UI widgets + private Composite fIoComposit; private Button fLocalRadioButton; private Button fSharedRadioButton; private Text fSharedLocationText; private Button fSharedLocationButton; private Button fLaunchInBackgroundButton; - private Button fDefaultEncodingButton; - private Button fAltEncodingButton; - private Combo fEncodingCombo; + private Button fDefaultEncodingButton; + private Button fAltEncodingButton; + private Combo fEncodingCombo; private Button fConsoleOutput; - private Button fFileOutput; - private Button fFileBrowse; - private Text fFileText; - private Button fVariables; - private Button fAppend; - private Button fWorkspaceBrowse; + private Button fFileOutput; + private Button fFileBrowse; + private Text fFileText; + private Button fVariables; + private Button fAppend; + private Button fMergeOutput; + private Button fWorkspaceBrowse; private Button fInputFileCheckButton; private Text fInputFileLocationText; @@ -160,7 +162,7 @@ public class CommonTab extends AbstractLaunchConfigurationTab { } }; - /** + /** * Constructs a new tab with default context help. */ public CommonTab() { @@ -260,96 +262,97 @@ public class CommonTab extends AbstractLaunchConfigurationTab { setSharedEnabled(false); } - /** - * Creates the component set for the capture output composite - * @param parent the parent to add this component to - */ + /** + * Creates the component set for the capture output composite + * @param parent the parent to add this component to + */ private void createOutputCaptureComponent(Composite parent) { - Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_4, 5, 2, GridData.FILL_HORIZONTAL); + Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_4, 5, 2, GridData.FILL_HORIZONTAL); createInputCaptureComponent(group); Composite comp = SWTFactory.createComposite(group, group.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0); + fIoComposit = comp; fFileOutput = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_6); - fFileOutput.setLayoutData(new GridData(SWT.BEGINNING, SWT.NORMAL, false, false)); - fFileOutput.addSelectionListener(new SelectionAdapter() { - @Override + fFileOutput.setLayoutData(new GridData(SWT.BEGINNING, SWT.NORMAL, false, false)); + fFileOutput.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { - enableOuputCaptureWidgets(fFileOutput.getSelection()); - updateLaunchConfigurationDialog(); - } - }); - fFileText = SWTFactory.createSingleText(comp, 4); - fFileText.getAccessible().addAccessibleListener(new AccessibleAdapter() { - @Override + enableOuputCaptureWidgets(fFileOutput.getSelection()); + updateLaunchConfigurationDialog(); + } + }); + fFileText = SWTFactory.createSingleText(comp, 4); + fFileText.getAccessible().addAccessibleListener(new AccessibleAdapter() { + @Override public void getName(AccessibleEvent e) { - e.result = LaunchConfigurationsMessages.CommonTab_6; - } - }); - fFileText.addModifyListener(fBasicModifyListener); + e.result = LaunchConfigurationsMessages.CommonTab_6; + } + }); + fFileText.addModifyListener(fBasicModifyListener); - Composite bcomp = SWTFactory.createComposite(comp, 3, 5, GridData.HORIZONTAL_ALIGN_END); + Composite bcomp = SWTFactory.createComposite(comp, 3, 5, GridData.HORIZONTAL_ALIGN_END); GridLayout ld = (GridLayout)bcomp.getLayout(); - ld.marginHeight = 1; - ld.marginWidth = 0; - fWorkspaceBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_12, null); - fWorkspaceBrowse.addSelectionListener(new SelectionAdapter() { - @Override + ld.marginHeight = 1; + ld.marginWidth = 0; + fWorkspaceBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_12, null); + fWorkspaceBrowse.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { - ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider()); - dialog.setTitle(LaunchConfigurationsMessages.CommonTab_13); - dialog.setMessage(LaunchConfigurationsMessages.CommonTab_14); - dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); - dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); - dialog.setDialogBoundsSettings(getDialogBoundsSettings(WORKSPACE_SELECTION_DIALOG), Dialog.DIALOG_PERSISTSIZE); - if (dialog.open() == IDialogConstants.OK_ID) { - IResource resource = (IResource) dialog.getFirstResult(); - if(resource != null) { - String arg = resource.getFullPath().toString(); - String fileLoc = VariablesPlugin.getDefault().getStringVariableManager().generateVariableExpression("workspace_loc", arg); //$NON-NLS-1$ - fFileText.setText(fileLoc); - } - } - } - }); - fFileBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_7, null); - fFileBrowse.addSelectionListener(new SelectionAdapter() { - @Override + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider()); + dialog.setTitle(LaunchConfigurationsMessages.CommonTab_13); + dialog.setMessage(LaunchConfigurationsMessages.CommonTab_14); + dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); + dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); + dialog.setDialogBoundsSettings(getDialogBoundsSettings(WORKSPACE_SELECTION_DIALOG), Dialog.DIALOG_PERSISTSIZE); + if (dialog.open() == IDialogConstants.OK_ID) { + IResource resource = (IResource) dialog.getFirstResult(); + if(resource != null) { + String arg = resource.getFullPath().toString(); + String fileLoc = VariablesPlugin.getDefault().getStringVariableManager().generateVariableExpression("workspace_loc", arg); //$NON-NLS-1$ + fFileText.setText(fileLoc); + } + } + } + }); + fFileBrowse = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_7, null); + fFileBrowse.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { - String filePath = fFileText.getText(); + String filePath = fFileText.getText(); FileDialog dialog = new FileDialog(getShell(), SWT.SAVE | SWT.SHEET); - filePath = dialog.open(); - if (filePath != null) { - fFileText.setText(filePath); - } - } - }); - fVariables = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_9, null); - fVariables.addSelectionListener(new SelectionListener() { - @Override + filePath = dialog.open(); + if (filePath != null) { + fFileText.setText(filePath); + } + } + }); + fVariables = createPushButton(bcomp, LaunchConfigurationsMessages.CommonTab_9, null); + fVariables.addSelectionListener(new SelectionListener() { + @Override public void widgetSelected(SelectionEvent e) { - StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell()); + StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell()); dialog.open(); String variable = dialog.getVariableExpression(); if (variable != null) { fFileText.insert(variable); } - } - @Override + } + @Override public void widgetDefaultSelected(SelectionEvent e) {} - }); - fAppend = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_11); + }); + fAppend = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_11); GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, false); - gd.horizontalSpan = 4; - fAppend.setLayoutData(gd); + gd.horizontalSpan = 5; + fAppend.setLayoutData(gd); fAppend.addSelectionListener(new SelectionAdapter() { - @Override + @Override public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } + updateLaunchConfigurationDialog(); + } }); - } + } - private void createInputCaptureComponent(Composite parent){ + private void createInputCaptureComponent(Composite parent){ Composite comp1 = SWTFactory.createComposite(parent, parent.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0); fConsoleOutput = createCheckButton(comp1, LaunchConfigurationsMessages.CommonTab_5); fConsoleOutput.addSelectionListener(new SelectionAdapter() { @@ -450,30 +453,30 @@ public class CommonTab extends AbstractLaunchConfigurationTab { }); setInputFileEnabled(false); - } - /** - * Enables or disables the output capture widgets based on the the specified enablement - * @param enable if the output capture widgets should be enabled or not - * @since 3.2 - */ - private void enableOuputCaptureWidgets(boolean enable) { - fFileText.setEnabled(enable); - fFileBrowse.setEnabled(enable); - fWorkspaceBrowse.setEnabled(enable); - fVariables.setEnabled(enable); - fAppend.setEnabled(enable); - } - - /** - * Returns the default encoding for the specified config - * @param config the configuration to get the encoding for - * @return the default encoding - * - * @since 3.4 - */ - private String getDefaultEncoding(ILaunchConfiguration config) { - try { - IResource[] resources = config.getMappedResources(); + } + /** + * Enables or disables the output capture widgets based on the the specified enablement + * @param enable if the output capture widgets should be enabled or not + * @since 3.2 + */ + private void enableOuputCaptureWidgets(boolean enable) { + fFileText.setEnabled(enable); + fFileBrowse.setEnabled(enable); + fWorkspaceBrowse.setEnabled(enable); + fVariables.setEnabled(enable); + fAppend.setEnabled(enable); + } + + /** + * Returns the default encoding for the specified config + * @param config the configuration to get the encoding for + * @return the default encoding + * + * @since 3.4 + */ + private String getDefaultEncoding(ILaunchConfiguration config) { + try { + IResource[] resources = config.getMappedResources(); if(resources != null && resources.length > 0) { IResource res = resources[0]; if(res instanceof IFile) { @@ -483,62 +486,62 @@ public class CommonTab extends AbstractLaunchConfigurationTab { return ((IContainer)res).getDefaultCharset(); } } - } - catch(CoreException ce) { - DebugUIPlugin.log(ce); - } - return ResourcesPlugin.getEncoding(); - } - - /** - * Creates the encoding component - * @param parent the parent to add this composite to - */ - private void createEncodingComponent(Composite parent) { - Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_1, 2, 1, GridData.FILL_BOTH); - - fDefaultEncodingButton = createRadioButton(group, IInternalDebugCoreConstants.EMPTY_STRING); - GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, true, false); - gd.horizontalSpan = 2; - fDefaultEncodingButton.setLayoutData(gd); - - fAltEncodingButton = createRadioButton(group, LaunchConfigurationsMessages.CommonTab_3); - fAltEncodingButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); - - fEncodingCombo = new Combo(group, SWT.NONE); - fEncodingCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - fEncodingCombo.setFont(parent.getFont()); - List<String> allEncodings = IDEEncoding.getIDEEncodings(); - String[] encodingArray = allEncodings.toArray(new String[0]); - fEncodingCombo.setItems(encodingArray); - if (encodingArray.length > 0) { - fEncodingCombo.select(0); - } - fEncodingCombo.getAccessible().addAccessibleListener(new AccessibleAdapter() { - @Override + } + catch(CoreException ce) { + DebugUIPlugin.log(ce); + } + return ResourcesPlugin.getEncoding(); + } + + /** + * Creates the encoding component + * @param parent the parent to add this composite to + */ + private void createEncodingComponent(Composite parent) { + Group group = SWTFactory.createGroup(parent, LaunchConfigurationsMessages.CommonTab_1, 2, 1, GridData.FILL_BOTH); + + fDefaultEncodingButton = createRadioButton(group, IInternalDebugCoreConstants.EMPTY_STRING); + GridData gd = new GridData(SWT.BEGINNING, SWT.NORMAL, true, false); + gd.horizontalSpan = 2; + fDefaultEncodingButton.setLayoutData(gd); + + fAltEncodingButton = createRadioButton(group, LaunchConfigurationsMessages.CommonTab_3); + fAltEncodingButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + + fEncodingCombo = new Combo(group, SWT.NONE); + fEncodingCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + fEncodingCombo.setFont(parent.getFont()); + List<String> allEncodings = IDEEncoding.getIDEEncodings(); + String[] encodingArray = allEncodings.toArray(new String[0]); + fEncodingCombo.setItems(encodingArray); + if (encodingArray.length > 0) { + fEncodingCombo.select(0); + } + fEncodingCombo.getAccessible().addAccessibleListener(new AccessibleAdapter() { + @Override public void getName(AccessibleEvent e) { - e.result = LaunchConfigurationsMessages.CommonTab_3; - } - }); - SelectionListener listener = new SelectionAdapter() { - @Override + e.result = LaunchConfigurationsMessages.CommonTab_3; + } + }); + SelectionListener listener = new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { - if(e.getSource() instanceof Button) { - Button button = (Button)e.getSource(); - if(button.getSelection()) { - updateLaunchConfigurationDialog(); - fEncodingCombo.setEnabled(fAltEncodingButton.getSelection() == true); - } - } - else { - updateLaunchConfigurationDialog(); - } - } - }; - fAltEncodingButton.addSelectionListener(listener); - fDefaultEncodingButton.addSelectionListener(listener); - fEncodingCombo.addSelectionListener(listener); - fEncodingCombo.addKeyListener(new KeyAdapter() { + if(e.getSource() instanceof Button) { + Button button = (Button)e.getSource(); + if(button.getSelection()) { + updateLaunchConfigurationDialog(); + fEncodingCombo.setEnabled(fAltEncodingButton.getSelection() == true); + } + } + else { + updateLaunchConfigurationDialog(); + } + } + }; + fAltEncodingButton.addSelectionListener(listener); + fDefaultEncodingButton.addSelectionListener(listener); + fEncodingCombo.addSelectionListener(listener); + fEncodingCombo.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { scheduleUpdateJob(); @@ -658,9 +661,9 @@ public class CommonTab extends AbstractLaunchConfigurationTab { String currentContainerString = fSharedLocationText.getText(); IContainer currentContainer = getContainer(currentContainerString); ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(), - currentContainer, - false, - LaunchConfigurationsMessages.CommonTab_Select_a_location_for_the_launch_configuration_13); + currentContainer, + false, + LaunchConfigurationsMessages.CommonTab_Select_a_location_for_the_launch_configuration_13); dialog.showClosedProjects(false); dialog.setDialogBoundsSettings(getDialogBoundsSettings(SHARED_LAUNCH_CONFIGURATON_DIALOG), Dialog.DIALOG_PERSISTSIZE); dialog.open(); @@ -706,33 +709,54 @@ public class CommonTab extends AbstractLaunchConfigurationTab { updateConsoleOutput(configuration); } - /** - * Updates the console output form the local configuration - * @param configuration the local configuration - */ - private void updateConsoleOutput(ILaunchConfiguration configuration) { - boolean outputToConsole = true; + /** + * Updates the console output form the local configuration + * @param configuration the local configuration + */ + private void updateConsoleOutput(ILaunchConfiguration configuration) { + boolean outputToConsole = true; String stdinFromFile = null; - String outputFile = null; - boolean append = false; + String outputFile = null; + boolean append = false; + boolean mergeOutput = false; + boolean supportsMergeOutput = false; - try { - outputToConsole = configuration.getAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true); + try { + outputToConsole = configuration.getAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true); stdinFromFile = configuration.getAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, (String) null); - outputFile = configuration.getAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String)null); - append = configuration.getAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, false); - } catch (CoreException e) { - } + outputFile = configuration.getAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String)null); + append = configuration.getAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, false); + mergeOutput = configuration.getAttribute(IDebugUIConstants.ATTR_MERGE_OUTPUT, false); + supportsMergeOutput = configuration.getType().supportsOutputMerging(); + } catch (CoreException e) { + } fConsoleOutput.setSelection(outputToConsole); - fAppend.setSelection(append); - boolean haveOutputFile= outputFile != null; - if (haveOutputFile) { - fFileText.setText(outputFile); + fAppend.setSelection(append); + if (supportsMergeOutput) { + fMergeOutput = createCheckButton(fIoComposit, LaunchConfigurationsMessages.CommonTab_21); + GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, false); + gd.horizontalSpan = 5; + fMergeOutput.setLayoutData(gd); + fMergeOutput.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateLaunchConfigurationDialog(); + } + }); + fMergeOutput.setSelection(mergeOutput); } - fFileOutput.setSelection(haveOutputFile); - enableOuputCaptureWidgets(haveOutputFile); + else if (fMergeOutput != null) { + fMergeOutput.dispose(); + fMergeOutput = null; + } + boolean haveOutputFile= outputFile != null; + if (haveOutputFile) { + fFileText.setText(outputFile); + } + fFileOutput.setSelection(haveOutputFile); + enableOuputCaptureWidgets(haveOutputFile); boolean haveInputFile = stdinFromFile != null; if (haveInputFile) { @@ -740,13 +764,13 @@ public class CommonTab extends AbstractLaunchConfigurationTab { } fInputFileCheckButton.setSelection(haveInputFile); setInputFileEnabled(haveInputFile); - } + } - /** - * Updates the launch on background check button - * @param configuration the local launch configuration - */ - protected void updateLaunchInBackground(ILaunchConfiguration configuration) { + /** + * Updates the launch on background check button + * @param configuration the local launch configuration + */ + protected void updateLaunchInBackground(ILaunchConfiguration configuration) { fLaunchInBackgroundButton.setSelection(isLaunchInBackground(configuration)); } @@ -755,24 +779,24 @@ public class CommonTab extends AbstractLaunchConfigurationTab { * @param configuration the local configuration */ private void updateEncoding(ILaunchConfiguration configuration) { - String encoding = null; - try { - encoding = configuration.getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, (String)null); - } catch (CoreException e) { - } - String defaultEncoding = getDefaultEncoding(configuration); + String encoding = null; + try { + encoding = configuration.getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, (String)null); + } catch (CoreException e) { + } + String defaultEncoding = getDefaultEncoding(configuration); fDefaultEncodingButton.setText(MessageFormat.format(LaunchConfigurationsMessages.CommonTab_2, new Object[] { defaultEncoding })); - fDefaultEncodingButton.pack(); - if (encoding != null) { - fAltEncodingButton.setSelection(true); - fDefaultEncodingButton.setSelection(false); - fEncodingCombo.setText(encoding); - fEncodingCombo.setEnabled(true); - } else { - fDefaultEncodingButton.setSelection(true); - fAltEncodingButton.setSelection(false); - fEncodingCombo.setEnabled(false); - } + fDefaultEncodingButton.pack(); + if (encoding != null) { + fAltEncodingButton.setSelection(true); + fDefaultEncodingButton.setSelection(false); + fEncodingCombo.setText(encoding); + fEncodingCombo.setEnabled(true); + } else { + fDefaultEncodingButton.setSelection(true); + fAltEncodingButton.setSelection(false); + fEncodingCombo.setEnabled(false); + } } /** @@ -925,42 +949,42 @@ public class CommonTab extends AbstractLaunchConfigurationTab { return validateLocalShared() && validateRedirectFile() && validateEncoding() && validateStdinFile(); } - /** - * validates the encoding selection - * @return true if the validate encoding is allowable, false otherwise - */ - private boolean validateEncoding() { - if (fAltEncodingButton.getSelection()) { - if (fEncodingCombo.getSelectionIndex() == -1) { - if (!isValidEncoding(fEncodingCombo.getText().trim())) { - setErrorMessage(LaunchConfigurationsMessages.CommonTab_15); - return false; - } - } - } - return true; - } - - /** - * Validates if the redirect file is valid - * @return true if the filename is not zero, false otherwise - */ - private boolean validateRedirectFile() { - if(fFileOutput.getSelection()) { - int len = fFileText.getText().trim().length(); - if (len == 0) { - setErrorMessage(LaunchConfigurationsMessages.CommonTab_8); - return false; - } - } - return true; - } - - /** - * validates the local shared config file location - * @return true if the local shared file exists, false otherwise - */ - private boolean validateLocalShared() { + /** + * validates the encoding selection + * @return true if the validate encoding is allowable, false otherwise + */ + private boolean validateEncoding() { + if (fAltEncodingButton.getSelection()) { + if (fEncodingCombo.getSelectionIndex() == -1) { + if (!isValidEncoding(fEncodingCombo.getText().trim())) { + setErrorMessage(LaunchConfigurationsMessages.CommonTab_15); + return false; + } + } + } + return true; + } + + /** + * Validates if the redirect file is valid + * @return true if the filename is not zero, false otherwise + */ + private boolean validateRedirectFile() { + if(fFileOutput.getSelection()) { + int len = fFileText.getText().trim().length(); + if (len == 0) { + setErrorMessage(LaunchConfigurationsMessages.CommonTab_8); + return false; + } + } + return true; + } + + /** + * validates the local shared config file location + * @return true if the local shared file exists, false otherwise + */ + private boolean validateLocalShared() { if (isShared()) { String path = fSharedLocationText.getText().trim(); IContainer container = getContainer(path); @@ -1004,15 +1028,15 @@ public class CommonTab extends AbstractLaunchConfigurationTab { setAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, configuration, fLaunchInBackgroundButton.getSelection(), true); String encoding = null; if(fAltEncodingButton.getSelection()) { - encoding = fEncodingCombo.getText().trim(); + encoding = fEncodingCombo.getText().trim(); } configuration.setAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, encoding); boolean captureOutput = false; if (fConsoleOutput.getSelection()) { - captureOutput = true; + captureOutput = true; configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, (String) null); } else { - configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false); + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false); } if (fInputFileCheckButton.getSelection()) { configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, fInputFileLocationText.getText()); @@ -1020,22 +1044,29 @@ public class CommonTab extends AbstractLaunchConfigurationTab { configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, (String) null); } if (fFileOutput.getSelection()) { - captureOutput = true; - String file = fFileText.getText(); - configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, file); - if(fAppend.getSelection()) { - configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, true); + captureOutput = true; + String file = fFileText.getText(); + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, file); + if(fAppend.getSelection()) { + configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, true); + } else { + configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, (String)null); + } + } else { + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String)null); + } + if (fMergeOutput != null) { + if (fMergeOutput.getSelection()) { + configuration.setAttribute(IDebugUIConstants.ATTR_MERGE_OUTPUT, true); } else { - configuration.setAttribute(IDebugUIConstants.ATTR_APPEND_TO_FILE, (String)null); + configuration.setAttribute(IDebugUIConstants.ATTR_MERGE_OUTPUT, (String) null); } - } else { - configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_FILE, (String)null); } if (!captureOutput) { - configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, false); + configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, false); } else { - configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, (String)null); + configuration.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, (String)null); } } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java index 58be140f4..672ba0ece 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -995,6 +995,18 @@ public interface IDebugUIConstants { */ String ATTR_APPEND_TO_FILE = PLUGIN_ID + ".ATTR_APPEND_TO_FILE"; //$NON-NLS-1$ + /** + * Launch configuration attribute - a boolean value indicating whether a + * configuration should be launched with merged error and standard output. + * Merging output can ensure the process output appears in console in same order + * as the process produce it. On the other hand the error output can not be + * colored different from standard output anymore. Default value is + * <code>false</code>. + * + * @since 3.15 + */ + String ATTR_MERGE_OUTPUT = PLUGIN_ID + ".ATTR_MERGE_OUTPUT"; //$NON-NLS-1$ + // Extension points /** |