sergey.vardanyan/RIDER-84956-CreateProcessW-based-process-for-IntelliJ

Fix RIDER-84956: Add raw commandline support based on CreateProcessW

Merge-request: IJ-MR-163129
Merged-by: Sergey Vardanyan <sergey.vardanyan@jetbrains.com>

(cherry picked from commit 0b1eae71a5efcaeb98f868f0a4bd7640211d0f29)

IJ-CR-166077

GitOrigin-RevId: bb4243ad03c946e39ae6f74e0ad1c23ff0a7135f
This commit is contained in:
Sergey Vardanyan
2025-06-17 15:17:15 +00:00
committed by intellij-monorepo-bot
parent a21852d412
commit 23483ce45d
4 changed files with 60 additions and 20 deletions

View File

@@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.registry.Registry
import com.intellij.util.SystemProperties
import com.pty4j.Command
import com.pty4j.PtyProcess
import com.pty4j.PtyProcessBuilder
import com.pty4j.windows.conpty.WinConPtyProcess
@@ -21,8 +22,24 @@ class LocalProcessServiceImpl : LocalProcessService {
env: Map<String, String>,
options: LocalPtyOptions,
redirectErrorStream: Boolean,
): PtyProcess = startPtyProcess(Command.CommandList(command), directory, env, options, redirectErrorStream)
override fun startPtyProcess(
command: RawCommandLineString,
directory: String?,
env: Map<String, String>,
options: LocalPtyOptions,
redirectErrorStream: Boolean,
): PtyProcess = startPtyProcess(Command.RawCommandString(command.commandLine), directory, env, options, redirectErrorStream)
private fun startPtyProcess(
command: Command,
directory: String?,
env: Map<String, String>,
options: LocalPtyOptions,
redirectErrorStream: Boolean,
): PtyProcess {
val builder = PtyProcessBuilder(command.toTypedArray())
val builder = PtyProcessBuilder(command)
.setEnvironment(env)
.setDirectory(directory)
.setInitialColumns(if (options.initialColumns > 0) options.initialColumns else null)
@@ -104,8 +121,8 @@ class LocalProcessServiceImpl : LocalProcessService {
override fun getCommand(process: Process): List<String> {
return when (process) {
is WinConPtyProcess -> process.command
is WinPtyProcess -> process.command
is WinConPtyProcess -> process.commandWrapper.toList()
is WinPtyProcess -> process.commandWrapper.toList()
else -> {
val processInfo: ProcessHandle.Info = try {
process.info()

View File

@@ -399,10 +399,7 @@ public class GeneralCommandLine implements UserDataHolder {
}
try {
var commands = myProcessCreator != null || tryGetEel() != null
? ContainerUtil.concat(List.of(myExePath), myProgramParams.getList())
: validateAndPrepareCommandLineForLocalRun();
var process = startProcess(commands);
var process = startProcess();
String pidString = null;
if (LOG.isDebugEnabled()) {
try {
@@ -426,6 +423,16 @@ public class GeneralCommandLine implements UserDataHolder {
}
}
@ApiStatus.Internal
@ApiStatus.OverrideOnly
protected @NotNull Process startProcess() throws ExecutionException, IOException {
var commands = myProcessCreator != null || tryGetEel() != null
? ContainerUtil.concat(List.of(myExePath), myProgramParams.getList())
: validateAndPrepareCommandLineForLocalRun();
var process = startProcess(commands);
return process;
}
/**
* Allows specifying a handler for creating processes different from {@link ProcessBuilder#start()}.
* <p>

View File

@@ -1,8 +1,8 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.configurations;
import com.intellij.execution.process.LocalPtyOptions;
import com.intellij.execution.process.LocalProcessService;
import com.intellij.execution.process.LocalPtyOptions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -145,18 +145,7 @@ public class PtyCommandLine extends GeneralCommandLine implements CommandLineWit
@ApiStatus.Internal
public @NotNull Process startProcessWithPty(@NotNull List<String> commands) throws IOException {
Map<String, String> env = new HashMap<>();
setupEnvironment(env);
if (!SystemInfo.isWindows) {
// Let programs know about the emulator's capabilities to allow them to produce appropriate escape sequences.
// https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html
// Moreover, some programs require `$TERM` to be set, e.g. `/usr/bin/clear` or Python code `os.system("clear")`.
// The following error will be reported if `$TERM` is missing: "TERM environment variable set not set."
if (!getEnvironment().containsKey("TERM")) {
env.put("TERM", "xterm-256color");
}
}
Map<String, String> env = getPreparedEnvironment();
Path workingDirectory = getWorkingDirectory();
LocalPtyOptions options = getPtyOptions();
return LocalProcessService.getInstance().startPtyProcess(
@@ -168,6 +157,22 @@ public class PtyCommandLine extends GeneralCommandLine implements CommandLineWit
);
}
@ApiStatus.Internal
protected @NotNull Map<String, String> getPreparedEnvironment() {
Map<String, String> env = new HashMap<>();
setupEnvironment(env);
if (!SystemInfo.isWindows) {
// Let programs know about the emulator's capabilities to allow them to produce appropriate escape sequences.
// https://www.gnu.org/software/gettext/manual/html_node/The-TERM-variable.html
// Moreover, some programs require `$TERM` to be set, e.g. `/usr/bin/clear` or Python code `os.system("clear")`.
// The following error will be reported if `$TERM` is missing: "TERM environment variable set not set."
if (!getEnvironment().containsKey("TERM")) {
env.put("TERM", "xterm-256color");
}
}
return env;
}
@ApiStatus.Internal
public static @NotNull LocalPtyOptions getDefaultPtyOptions() {
return LocalPtyOptions.defaults().builder().consoleMode(true).build();

View File

@@ -16,6 +16,14 @@ interface LocalProcessService {
redirectErrorStream: Boolean,
): Process
fun startPtyProcess(
command: RawCommandLineString,
directory: String?,
env: Map<String, String>,
options: LocalPtyOptions,
redirectErrorStream: Boolean,
): Process
@Deprecated("Use the other `startPtyProcess` instead")
fun startPtyProcess(
command: Array<String>,
@@ -62,3 +70,6 @@ interface LocalProcessService {
fun getInstance(): LocalProcessService = service<LocalProcessService>()
}
}
@ApiStatus.Internal
data class RawCommandLineString(val commandLine: String)