diff --git a/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java b/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java index 4fefb9ead7c..da70c8d75cd 100644 --- a/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java +++ b/debug/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java @@ -864,10 +864,13 @@ public static IProcess newProcess(ILaunch launch, Process process, String label) */ public static IProcess newProcess(ILaunch launch, Process process, String label, Map attributes) { ILaunchConfiguration config= launch.getLaunchConfiguration(); - String processFactoryID= null; + String processFactoryID = null; + // FIXME hack for demo purpose we need an UI for the user to decide if a + // terminal + // is wanted if (config != null) { try { - processFactoryID= config.getAttribute(ATTR_PROCESS_FACTORY_ID, (String)null); + processFactoryID = config.getAttribute(ATTR_PROCESS_FACTORY_ID, "org.eclipse.debug.terminal.processFactory.cdt"); //$NON-NLS-1$ } catch (CoreException e) { } } @@ -1028,6 +1031,7 @@ public static Process exec(String[] cmdLine, File workingDirectory, String[] env // 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); directory.ifPresent(pb::directory); diff --git a/debug/org.eclipse.debug.terminal/.classpath b/debug/org.eclipse.debug.terminal/.classpath new file mode 100644 index 00000000000..375961e4d61 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/debug/org.eclipse.debug.terminal/.project b/debug/org.eclipse.debug.terminal/.project new file mode 100644 index 00000000000..78eeecd4d55 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/.project @@ -0,0 +1,33 @@ + + + org.eclipse.debug.terminal + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/debug/org.eclipse.debug.terminal/.settings/org.eclipse.core.resources.prefs b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/debug/org.eclipse.debug.terminal/.settings/org.eclipse.jdt.core.prefs b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..23fa13b1705 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 diff --git a/debug/org.eclipse.debug.terminal/.settings/org.eclipse.pde.ds.annotations.prefs b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.pde.ds.annotations.prefs new file mode 100644 index 00000000000..5faf08b7d5c --- /dev/null +++ b/debug/org.eclipse.debug.terminal/.settings/org.eclipse.pde.ds.annotations.prefs @@ -0,0 +1,7 @@ +dsVersion=V1_4 +eclipse.preferences.version=1 +enabled=true +generateBundleActivationPolicyLazy=true +path=OSGI-INF +validationErrorLevel=error +validationErrorLevel.missingImplicitUnbindMethod=error diff --git a/debug/org.eclipse.debug.terminal/META-INF/MANIFEST.MF b/debug/org.eclipse.debug.terminal/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..b344726ef44 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Terminal Session Support for Eclipse +Bundle-SymbolicName: org.eclipse.debug.terminal;singleton:=true +Bundle-Version: 1.0.0.qualifier +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.debug.core;bundle-version="3.23.0", + org.eclipse.tm.terminal.control;bundle-version="5.6.0", + org.eclipse.cdt.core.native;bundle-version="6.4.0", + org.eclipse.swt;bundle-version="3.130.0", + org.eclipse.ui;bundle-version="3.207.100" +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Automatic-Module-Name: org.eclipse.debug.terminal +Bundle-ActivationPolicy: lazy +Service-Component: OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml diff --git a/debug/org.eclipse.debug.terminal/OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml b/debug/org.eclipse.debug.terminal/OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml new file mode 100644 index 00000000000..bf4d63e7ec7 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/debug/org.eclipse.debug.terminal/build.properties b/debug/org.eclipse.debug.terminal/build.properties new file mode 100644 index 00000000000..a633832ae47 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml diff --git a/debug/org.eclipse.debug.terminal/plugin.xml b/debug/org.eclipse.debug.terminal/plugin.xml new file mode 100644 index 00000000000..a71b5f94a2a --- /dev/null +++ b/debug/org.eclipse.debug.terminal/plugin.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyExecFactory.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyExecFactory.java new file mode 100644 index 00000000000..5bf138d5fe7 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyExecFactory.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.pty.PTY.Mode; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.ExecFactory; + +public class PtyExecFactory implements ExecFactory { + + @Override + public Optional exec(String[] cmdLine, Optional workingDirectory, + Optional> environment, boolean mergeOutput) throws CoreException { + if (mergeOutput || !PTY.isSupported(Mode.TERMINAL)) { + return Optional.empty(); + } + try { + PTY pty = new PTY(Mode.TERMINAL); + pty.setTerminalSize(80, 24); + String[] env; + if (environment.isEmpty()) { + env = null; + } else { + env = environment.stream().flatMap(m -> m.entrySet().stream()).map(e -> e.getKey() + "=" + e.getValue()) + .toArray(String[]::new); + } + File wd = workingDirectory.orElse(null); + return Optional.of(ProcessFactory.getFactory().exec(cmdLine, env, wd, pty)); + } catch (IOException e) { + throw new CoreException(Status.error("Execution failed", e)); + } + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyProcessFactory.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyProcessFactory.java new file mode 100644 index 00000000000..da93247a515 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyProcessFactory.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal; + +import java.util.Map; + +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.IProcessFactory; +import org.eclipse.debug.core.model.IProcess; + +public class PtyProcessFactory implements IProcessFactory { + + @Override + public IProcess newProcess(ILaunch launch, Process process, String label, Map attributes) { + return new PtyRuntimeProcess(launch, process, label, attributes); + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyRuntimeProcess.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyRuntimeProcess.java new file mode 100644 index 00000000000..a3d544ddb85 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/PtyRuntimeProcess.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal; + +import java.util.Map; + +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.RuntimeProcess; + +public class PtyRuntimeProcess extends RuntimeProcess { + + public PtyRuntimeProcess(ILaunch launch, Process process, String name, Map attributes) { + super(launch, process, name, attributes); + } + + public Spawner getSpawner() { + Process systemProcess = super.getSystemProcess(); + if (systemProcess instanceof Spawner) { + return (Spawner) systemProcess; + } + return null; + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleConnector.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleConnector.java new file mode 100644 index 00000000000..8cefb1f4e05 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleConnector.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal.ui; + +import java.io.OutputStream; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +public class ConsoleConnector implements ITerminalConnector { + + private Spawner process; + private ITerminalControl control; + + public ConsoleConnector(Spawner process) { + this.process = process; + } + + @Override + public T getAdapter(Class adapter) { + return null; + } + + @Override + public String getId() { + return "org.eclipse.debug.terminal.cdt"; //$NON-NLS-1$ + } + + @Override + public String getName() { + return "testme"; //$NON-NLS-1$ + } + + @Override + public boolean isHidden() { + return true; + } + + @Override + public boolean isInitialized() { + return true; + } + + @Override + public String getInitializationErrorMessage() { + return null; + } + + @Override + public void connect(ITerminalControl control) { + this.control = control; + control.setState(TerminalState.CONNECTED); + + } + + @Override + public void disconnect() { + control.setState(TerminalState.CLOSED); + } + + @Override + public boolean isLocalEcho() { + return false; + } + + @Override + public void setTerminalSize(int newWidth, int newHeight) { + PTY pty = process.pty(); + if (pty != null) { + pty.setTerminalSize(newWidth, newHeight); + } + } + + @Override + public OutputStream getTerminalToRemoteStream() { + return process.getOutputStream(); + } + + @Override + public void load(ISettingsStore store) { + + } + + @Override + public void save(ISettingsStore store) { + + } + + @Override + public void setDefaultSettings() { + + } + + @Override + public String getSettingsSummary() { + return "summary"; //$NON-NLS-1$ + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleTerminalListener.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleTerminalListener.java new file mode 100644 index 00000000000..5a2cfb7a139 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/ConsoleTerminalListener.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal.ui; + +import org.eclipse.tm.internal.terminal.control.ITerminalListener; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +public class ConsoleTerminalListener implements ITerminalListener { + + @Override + public void setState(TerminalState state) { + + } + + @Override + public void setTerminalTitle(String title) { + // TODO redirect to the console? + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/PageBookAdapter.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/PageBookAdapter.java new file mode 100644 index 00000000000..fafef42092b --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/PageBookAdapter.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal.ui; + +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.core.runtime.AdapterTypes; +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.debug.terminal.PtyRuntimeProcess; +import org.eclipse.ui.part.IPageBookViewPage; +import org.osgi.service.component.annotations.Component; + +@Component +@AdapterTypes(adaptableClass = PtyRuntimeProcess.class, adapterNames = { IPageBookViewPage.class }) +public class PageBookAdapter implements IAdapterFactory { + + @Override + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof PtyRuntimeProcess rt) { + Spawner spawner = rt.getSpawner(); + if (spawner != null) { + return adapterType.cast(new TerminalConsolePage(spawner, rt.getStreamsProxy())); + } + } + return null; + } + +} diff --git a/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/TerminalConsolePage.java b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/TerminalConsolePage.java new file mode 100644 index 00000000000..26f4c514aa0 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/src/org/eclipse/debug/terminal/ui/TerminalConsolePage.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.terminal.ui; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.Charset; + +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.debug.core.model.IBinaryStreamMonitor; +import org.eclipse.debug.core.model.IStreamMonitor; +import org.eclipse.debug.core.model.IStreamsProxy; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.TerminalViewControlFactory; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.IPageBookViewPage; +import org.eclipse.ui.part.IPageSite; + +public class TerminalConsolePage implements IPageBookViewPage, IAdaptable { + + private Spawner process; + private IPageSite site; + private ITerminalViewControl viewer; + private Composite composite; + private IStreamsProxy streamsProxy; + + public TerminalConsolePage(Spawner spawner, IStreamsProxy streamsProxy) { + this.process = spawner; + this.streamsProxy = streamsProxy; + } + + @Override + public void createControl(Composite parent) { + composite = new Composite(parent, SWT.NONE); + composite.setLayout(new FillLayout()); + viewer = TerminalViewControlFactory.makeControl(new ConsoleTerminalListener(), composite, + new ITerminalConnector[] {}, true); + viewer.setConnector(new ConsoleConnector(process)); + viewer.setCharset(Charset.defaultCharset()); + viewer.clearTerminal(); + viewer.connectTerminal(); + if (viewer instanceof ITerminalControl ctrl) { + ctrl.setConnectOnEnterIfClosed(false); + ctrl.setVT100LineWrapping(true); + IStreamMonitor streamMonitor = streamsProxy.getOutputStreamMonitor(); + if (streamMonitor instanceof IBinaryStreamMonitor bin) { + OutputStream outputStream = ctrl.getRemoteToTerminalOutputStream(); + bin.addBinaryListener((data, monitor) -> { + try { + outputStream.write(data); + } catch (IOException e1) { + e1.printStackTrace(); + } + }); + } + } + } + + @Override + public void dispose() { + viewer.disposeTerminal(); + } + + @Override + public Control getControl() { + return composite; + } + + @Override + public void setActionBars(IActionBars actionBars) { + } + + @Override + public void setFocus() { + if (viewer != null) { + viewer.setFocus(); + } + } + + @Override + public IPageSite getSite() { + return site; + } + + @Override + public void init(IPageSite site) throws PartInitException { + this.site = site; + } + + @Override + public T getAdapter(Class adapter) { + return null; + } + +} diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java index 7fb69c97680..2add2c37987 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.java @@ -48,6 +48,10 @@ public class LaunchConfigurationsMessages extends NLS { public static String CommonTab_20; public static String CommonTab_21; public static String CommonTab_22; + + public static String CommonTab_23; + + public static String CommonTab_24; public static String CommonTab_3; public static String CommonTab_4; public static String CommonTab_5; @@ -66,6 +70,8 @@ public class LaunchConfigurationsMessages extends NLS { public static String CommonTab_AttributeLabel_FavoriteGroups; public static String CommonTab_AttributeLabel_TerminateDescendants; + public static String CommonTab_disable_console_input; + public static String CompileErrorProjectPromptStatusHandler_0; public static String CompileErrorProjectPromptStatusHandler_1; public static String CompileErrorPromptStatusHandler_0; diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties index 2832aebd723..9333555f4a2 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationsMessages.properties @@ -41,6 +41,8 @@ CommonTab_2=Defa&ult - inherited from project and workspace ({0}) CommonTab_22=Use &system encoding ({0}) CommonTab_20=Variables... CommonTab_21=&Merge standard and error output (disables coloring of error output) +CommonTab_23=Allocate Terminal +CommonTab_24=&Allocate text console CommonTab_3=Oth&er CommonTab_4=Standard Input and Output CommonTab_5=&Allocate console (necessary for input) @@ -57,6 +59,7 @@ CommonTab_AttributeLabel_AppendToFile=Append to file CommonTab_AttributeLabel_LaunchInBackground=Launch in background CommonTab_AttributeLabel_FavoriteGroups=Favorite groups CommonTab_AttributeLabel_TerminateDescendants=&Terminate child-processes if terminating the launched process +CommonTab_disable_console_input=Disable Input/Output CompileErrorPromptStatusHandler_0=Errors in Workspace CompileErrorPromptStatusHandler_1=Errors exist in a required project. Continue launch? diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java index c11ac8d4c58..f2bf9b47c2b 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/CommonTab.java @@ -33,6 +33,8 @@ import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; @@ -98,6 +100,7 @@ */ public class CommonTab extends AbstractLaunchConfigurationTab { + private static final String TERMINAL_PROCESS_FACTORY_ID = "org.eclipse.debug.terminal.processFactory"; //$NON-NLS-1$ /** * Constant representing the id of the {@link IDialogSettings} location for the {@link ContainerSelectionDialog} used * on this tab @@ -130,6 +133,8 @@ public class CommonTab extends AbstractLaunchConfigurationTab { private Button forceSystemEncodingButton; private Combo fEncodingCombo; private Button fConsoleOutput; + private Button noConsoleOutput; + private Button terminalOutput; private Button fFileOutput; private Button fFileBrowse; private Text fFileText; @@ -153,6 +158,7 @@ public class CommonTab extends AbstractLaunchConfigurationTab { * Modify listener that simply updates the owning launch configuration dialog. */ private final ModifyListener fBasicModifyListener = evt -> scheduleUpdateJob(); + private boolean hasTerminalSupport; /** * Constructs a new tab with default context help. @@ -160,6 +166,7 @@ public class CommonTab extends AbstractLaunchConfigurationTab { public CommonTab() { super(); setHelpContextId(IDebugHelpContextIds.LAUNCH_CONFIGURATION_DIALOG_COMMON_TAB); + hasTerminalSupport = hasTerminalSupport(); } @Override @@ -311,8 +318,22 @@ private void createOutputCaptureComponent(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(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog())); + if (hasTerminalSupport) { + SelectionListener adapter = widgetSelectedAdapter(e -> updateLaunchConfigurationDialog()); + Composite buttonComposite = new Composite(comp1, SWT.NONE); + buttonComposite.setLayout(new GridLayout(3, false)); + fConsoleOutput = createRadioButton(buttonComposite, LaunchConfigurationsMessages.CommonTab_24); + fConsoleOutput.addSelectionListener(adapter); + terminalOutput = createRadioButton(buttonComposite, LaunchConfigurationsMessages.CommonTab_23); + terminalOutput.addSelectionListener(adapter); + noConsoleOutput = createRadioButton(buttonComposite, + LaunchConfigurationsMessages.CommonTab_disable_console_input); + noConsoleOutput.addSelectionListener(adapter); + + } else { + fConsoleOutput = createCheckButton(comp1, LaunchConfigurationsMessages.CommonTab_5); + fConsoleOutput.addSelectionListener(widgetSelectedAdapter(e -> updateLaunchConfigurationDialog())); + } Composite comp = SWTFactory.createComposite(comp1, comp1.getFont(), 5, 5, GridData.FILL_BOTH, 0, 0); fInputFileCheckButton = createCheckButton(comp, LaunchConfigurationsMessages.CommonTab_17); @@ -388,6 +409,20 @@ private void createInputCaptureComponent(Composite parent){ setInputFileEnabled(false); } + + private static boolean hasTerminalSupport() { + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_PROCESS_FACTORIES); + IConfigurationElement[] infos = extensionPoint.getConfigurationElements(); + for (IConfigurationElement configurationElement : infos) { + String id = configurationElement.getAttribute("id"); //$NON-NLS-1$ + if (TERMINAL_PROCESS_FACTORY_ID.equals(id)) { + return true; + } + } + return 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 @@ -666,8 +701,20 @@ private void updateConsoleOutput(ILaunchConfiguration configuration) { supportsMergeOutput = configuration.getType().supportsOutputMerging(); } catch (CoreException e) { } - - fConsoleOutput.setSelection(outputToConsole); + if (hasTerminalSupport) { + if (outputToConsole) { + if (TERMINAL_PROCESS_FACTORY_ID + .equals(getAttribute(configuration, DebugPlugin.ATTR_PROCESS_FACTORY_ID, ""))) { //$NON-NLS-1$ + terminalOutput.setSelection(true); + } else { + fConsoleOutput.setSelection(true); + } + } else { + noConsoleOutput.setSelection(true); + } + } else { + fConsoleOutput.setSelection(outputToConsole); + } fAppend.setSelection(append); if (supportsMergeOutput) { fMergeOutput = createCheckButton(fIoComposit, LaunchConfigurationsMessages.CommonTab_21); @@ -995,11 +1042,25 @@ public void performApply(ILaunchConfigurationWorkingCopy configuration) { } configuration.setAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, encoding); boolean captureOutput = false; - if (fConsoleOutput.getSelection()) { - captureOutput = true; - configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, (String) null); + if (hasTerminalSupport) { + if (noConsoleOutput.getSelection()) { + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false); + } else { + captureOutput = true; + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, (String) null); + if (terminalOutput.getSelection()) { + configuration.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, TERMINAL_PROCESS_FACTORY_ID); + } else { + configuration.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, (String) null); + } + } } else { - configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false); + if (fConsoleOutput.getSelection()) { + captureOutput = true; + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, (String) null); + } else { + configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, false); + } } if (fInputFileCheckButton.getSelection()) { configuration.setAttribute(IDebugUIConstants.ATTR_CAPTURE_STDIN_FILE, fInputFileLocationText.getText());