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..7a075941496 --- /dev/null +++ b/debug/org.eclipse.debug.terminal/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.debug.terminal;singleton:=true +Bundle-Vendor: %providerName +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/about.html b/debug/org.eclipse.debug.terminal/about.html new file mode 100644 index 00000000000..164f781a8fd --- /dev/null +++ b/debug/org.eclipse.debug.terminal/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ 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..f8d41a3695e --- /dev/null +++ b/debug/org.eclipse.debug.terminal/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + OSGI-INF/,\ + about.html +src.includes = about.html diff --git a/debug/org.eclipse.debug.terminal/plugin.properties b/debug/org.eclipse.debug.terminal/plugin.properties new file mode 100644 index 00000000000..3c26a4a458a --- /dev/null +++ b/debug/org.eclipse.debug.terminal/plugin.properties @@ -0,0 +1,16 @@ +############################################################################### +# 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 +############################################################################### + +pluginName=Terminal Session Support for Eclipse +providerName=Eclipse.org \ No newline at end of file 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..4fb07e25ba1 --- /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 { + + 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..8241eab3baf --- /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; + +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"; //$NON-NLS-1$ + } + + @Override + public String getName() { + return "Eclipse Terminal Console"; //$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 ""; //$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..0c84f890bd0 --- /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; + +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..935b5bfe6cf --- /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; + +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/pom.xml b/debug/pom.xml index 79ba2ac2fed..40886b15ea2 100644 --- a/debug/pom.xml +++ b/debug/pom.xml @@ -18,7 +18,6 @@ 4.37.0-SNAPSHOT - org.eclipse.platform eclipse.platform.debug pom @@ -37,6 +36,7 @@ org.eclipse.ui.console org.eclipse.ui.externaltools org.eclipse.unittest.ui + org.eclipse.debug.terminal