diff --git a/platform/platform-util-io-impl/src/com/intellij/execution/process/LocalProcessServiceImpl.kt b/platform/platform-util-io-impl/src/com/intellij/execution/process/LocalProcessServiceImpl.kt index 9cbe2637fda1..01e04b25a052 100644 --- a/platform/platform-util-io-impl/src/com/intellij/execution/process/LocalProcessServiceImpl.kt +++ b/platform/platform-util-io-impl/src/com/intellij/execution/process/LocalProcessServiceImpl.kt @@ -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, options: LocalPtyOptions, redirectErrorStream: Boolean, + ): PtyProcess = startPtyProcess(Command.CommandList(command), directory, env, options, redirectErrorStream) + + override fun startPtyProcess( + command: RawCommandLineString, + directory: String?, + env: Map, + options: LocalPtyOptions, + redirectErrorStream: Boolean, + ): PtyProcess = startPtyProcess(Command.RawCommandString(command.commandLine), directory, env, options, redirectErrorStream) + + private fun startPtyProcess( + command: Command, + directory: String?, + env: Map, + 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 { 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() diff --git a/platform/platform-util-io/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-util-io/src/com/intellij/execution/configurations/GeneralCommandLine.java index df4ee6b59773..f1240d3c76b7 100644 --- a/platform/platform-util-io/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-util-io/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -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()}. *

diff --git a/platform/platform-util-io/src/com/intellij/execution/configurations/PtyCommandLine.java b/platform/platform-util-io/src/com/intellij/execution/configurations/PtyCommandLine.java index e5bc65fb24a0..ffac52fd97b0 100644 --- a/platform/platform-util-io/src/com/intellij/execution/configurations/PtyCommandLine.java +++ b/platform/platform-util-io/src/com/intellij/execution/configurations/PtyCommandLine.java @@ -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 commands) throws IOException { - Map 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 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 getPreparedEnvironment() { + Map 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(); diff --git a/platform/platform-util-io/src/com/intellij/execution/process/LocalProcessService.kt b/platform/platform-util-io/src/com/intellij/execution/process/LocalProcessService.kt index d2c4d34a6780..49d8b6481dff 100644 --- a/platform/platform-util-io/src/com/intellij/execution/process/LocalProcessService.kt +++ b/platform/platform-util-io/src/com/intellij/execution/process/LocalProcessService.kt @@ -16,6 +16,14 @@ interface LocalProcessService { redirectErrorStream: Boolean, ): Process + fun startPtyProcess( + command: RawCommandLineString, + directory: String?, + env: Map, + options: LocalPtyOptions, + redirectErrorStream: Boolean, + ): Process + @Deprecated("Use the other `startPtyProcess` instead") fun startPtyProcess( command: Array, @@ -62,3 +70,6 @@ interface LocalProcessService { fun getInstance(): LocalProcessService = service() } } + +@ApiStatus.Internal +data class RawCommandLineString(val commandLine: String)