Skip to content

Add support for launching Eclipse Process in a system terminal session #1762

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> 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) {
}
}
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions debug/org.eclipse.debug.terminal/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
33 changes: 33 additions & 0 deletions debug/org.eclipse.debug.terminal/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.debug.terminal</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ds.core.builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dsVersion=V1_4
eclipse.preferences.version=1
enabled=true
generateBundleActivationPolicyLazy=true
path=OSGI-INF
validationErrorLevel=error
validationErrorLevel.missingImplicitUnbindMethod=error
16 changes: 16 additions & 0 deletions debug/org.eclipse.debug.terminal/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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
Import-Package: com.pty4j;version="0.13.2"
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.debug.core;bundle-version="3.23.0",
org.eclipse.tm.terminal.control;bundle-version="5.5.301",
org.eclipse.cdt.core.native;bundle-version="6.3.401",
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.4.0" name="org.eclipse.debug.terminal.ui.PageBookAdapter">
<property name="adaptableClass" type="String" value="org.eclipse.debug.terminal.PtyRuntimeProcess"/>
<property name="adapterNames" type="String" value="org.eclipse.ui.part.IPageBookViewPage"/>
<service>
<provide interface="org.eclipse.core.runtime.IAdapterFactory"/>
</service>
<implementation class="org.eclipse.debug.terminal.ui.PageBookAdapter"/>
</scr:component>
6 changes: 6 additions & 0 deletions debug/org.eclipse.debug.terminal/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
OSGI-INF/org.eclipse.debug.terminal.ui.PageBookAdapter.xml
25 changes: 25 additions & 0 deletions debug/org.eclipse.debug.terminal/plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.debug.core.execFactories">
<execFactory
class="org.eclipse.debug.terminal.PtyExecFactory"
id="org.eclipse.debug.terminal.execFactory1"
priority="100">
</execFactory>
<execFactory
class="org.eclipse.debug.terminal.Pty4jExecFactory"
id="org.eclipse.debug.terminal.execFactory2"
priority="0">
</execFactory>
</extension>
<extension
point="org.eclipse.debug.core.processFactories">
<processFactory
class="org.eclipse.debug.terminal.PtyProcessFactory"
id="org.eclipse.debug.terminal.processFactory.cdt">
</processFactory>
</extension>

</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* 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.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ExecFactory;

import com.pty4j.PtyProcessBuilder;

class Pty4jExecFactory implements ExecFactory {

@Override
public Optional<Process> exec(String[] cmdLine, Optional<File> workingDirectory,
Optional<Map<String, String>> environment, boolean mergeOutput) throws CoreException {
try {
PtyProcessBuilder builder = new PtyProcessBuilder().setRedirectErrorStream(true).setInitialRows(80)
.setInitialColumns(25).setCommand(cmdLine).setEnvironment(environment.orElse(System.getenv()));
workingDirectory.map(File::getAbsolutePath).ifPresent(builder::setDirectory);
return Optional.of(builder.start());
} catch (IOException e) {
throw new CoreException(Status.error("Can't start process", e));
} catch (RuntimeException e) {
return Optional.empty();
}
}

}
Original file line number Diff line number Diff line change
@@ -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<Process> exec(String[] cmdLine, Optional<File> workingDirectory,
Optional<Map<String, String>> 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));
}
}

}
Original file line number Diff line number Diff line change
@@ -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<String, String> attributes) {
return new PtyRuntimeProcess(launch, process, label, attributes);
}

}
Original file line number Diff line number Diff line change
@@ -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<String, String> attributes) {
super(launch, process, name, attributes);
}

public Spawner getSpawner() {
Process systemProcess = super.getSystemProcess();
if (systemProcess instanceof Spawner) {
return (Spawner) systemProcess;
}
return null;
}

}
Loading
Loading