[terminal] use Path instead of String for type safety in LocalShellIntegrationInjector

(cherry picked from commit 5c40ebdf18341d00a3f85901098b4b1095d090cc)

IJ-CR-170679


(cherry picked from commit a9967525529c42738271af5f28cd6289d45428bc)

GitOrigin-RevId: 80d57f8df07738d7335cdc2ceb464dfb76db4d7e
This commit is contained in:
Sergey Simonchik
2025-07-27 22:13:35 +02:00
committed by intellij-monorepo-bot
parent 38b90f842c
commit 60884ab498
2 changed files with 23 additions and 21 deletions

View File

@@ -50,6 +50,7 @@ public final class LocalShellIntegrationInjector {
private static final String JEDITERM_USER_RCFILE = "JEDITERM_USER_RCFILE";
private static final String ZDOTDIR = "ZDOTDIR";
private static final String IJ_COMMAND_HISTORY_FILE_ENV = "__INTELLIJ_COMMAND_HISTFILE__";
private static final String BASH_RCFILE_OPTION = "--rcfile";
// todo: it would be great to extract block terminal configuration from here
public static @NotNull ShellStartupOptions injectShellIntegration(@NotNull ShellStartupOptions options,
@@ -67,8 +68,8 @@ public final class LocalShellIntegrationInjector {
resultCommand.add(shellExe);
String shellName = PathUtil.getFileName(shellExe);
String rcFilePath = findRCFile(shellName);
if (rcFilePath != null) {
Path rcFile = findRCFile(shellName);
if (rcFile != null) {
boolean isBlockTerminal = isBlockTerminalSupported(shellName);
if (ShellNameUtil.isBash(shellName) || (SystemInfo.isMac && shellName.equals(ShellNameUtil.SH_NAME))) {
final var useEel = TerminalStartupKt.shouldUseEelApi();
@@ -76,7 +77,7 @@ public final class LocalShellIntegrationInjector {
.map(e -> EelProviderUtil.getEelDescriptor(Path.of(e)))
.orElse(null) : null;
addRcFileArgument(envs, arguments, resultCommand, rcFilePath, "--rcfile", eelDescriptor);
addBashRcFileArgument(envs, arguments, resultCommand, rcFile.toString(), eelDescriptor);
// remove --login to enable --rcfile sourcing
boolean loginShell = arguments.removeAll(LOGIN_CLI_OPTIONS);
setLoginShellEnv(envs, loginShell);
@@ -88,7 +89,7 @@ public final class LocalShellIntegrationInjector {
if (StringUtil.isNotEmpty(originalZDotDir)) {
envs.put("JETBRAINS_INTELLIJ_ORIGINAL_ZDOTDIR", originalZDotDir);
}
String intellijZDotDir = PathUtil.getParentPath(rcFilePath);
String intellijZDotDir = rcFile.getParent().toString();
envs.put(ZDOTDIR, intellijZDotDir);
envs.put(IJ_ZSH_DIR, PathUtil.getParentPath(intellijZDotDir));
integration = new ShellIntegration(ShellType.ZSH, isBlockTerminal ? new CommandBlockIntegration() : null);
@@ -96,13 +97,13 @@ public final class LocalShellIntegrationInjector {
else if (shellName.equals(ShellNameUtil.FISH_NAME)) {
// `--init-command=COMMANDS` is available since Fish 2.7.0 (released November 23, 2017)
// Multiple `--init-command=COMMANDS` are supported.
resultCommand.add("--init-command=source " + CommandLineUtil.posixQuote(rcFilePath));
resultCommand.add("--init-command=source " + CommandLineUtil.posixQuote(rcFile.toString()));
integration = new ShellIntegration(ShellType.FISH, isBlockTerminal ? new CommandBlockIntegration() : null);
}
else if (ShellNameUtil.isPowerShell(shellName)) {
resultCommand.addAll(arguments);
arguments.clear();
resultCommand.addAll(List.of("-NoExit", "-ExecutionPolicy", "Bypass", "-File", rcFilePath));
resultCommand.addAll(List.of("-NoExit", "-ExecutionPolicy", "Bypass", "-File", rcFile.toString()));
integration = new ShellIntegration(ShellType.POWERSHELL, isBlockTerminal ? new CommandBlockIntegration(true) : null);
}
}
@@ -140,7 +141,7 @@ public final class LocalShellIntegrationInjector {
.build();
}
private static @Nullable String findRCFile(@NotNull String shellName) {
private static @Nullable Path findRCFile(@NotNull String shellName) {
String rcfile = switch (shellName) {
case ShellNameUtil.BASH_NAME, ShellNameUtil.SH_NAME -> "shell-integrations/bash/bash-integration.bash";
case ShellNameUtil.ZSH_NAME -> "shell-integrations/zsh/zdotdir/.zshenv";
@@ -162,7 +163,7 @@ public final class LocalShellIntegrationInjector {
}
@VisibleForTesting
public static @NotNull String findAbsolutePath(@NotNull String relativePath) throws IOException {
public static @NotNull Path findAbsolutePath(@NotNull String relativePath) throws IOException {
String jarPath = PathUtil.getJarPathForClass(LocalTerminalDirectRunner.class);
final Path result;
if (PluginManagerCore.isRunningFromSources()) {
@@ -191,7 +192,7 @@ public final class LocalShellIntegrationInjector {
if (!Files.isRegularFile(result)) {
throw new IOException("Cannot find " + relativePath + ": " + result + " is not a file");
}
return result.toString();
return result;
}
private static void setLoginShellEnv(@NotNull Map<String, String> envs, boolean loginShell) {
@@ -200,11 +201,13 @@ public final class LocalShellIntegrationInjector {
}
}
private static void addRcFileArgument(Map<String, String> envs,
List<String> arguments,
List<String> result,
String rcFilePath, String rcfileOption, @Nullable EelDescriptor eelDescriptor) {
result.add(rcfileOption);
private static void addBashRcFileArgument(@NotNull Map<String, String> envs,
@NotNull List<String> arguments,
@NotNull List<String> result,
@NotNull String rcFilePath,
@Nullable EelDescriptor eelDescriptor) {
result.add(BASH_RCFILE_OPTION);
if (eelDescriptor != null) {
final var rcFile = Path.of(rcFilePath);
final var bashSupportDir = transferLocalContentToRemote(rcFile.getParent(), new EelPathUtils.TransferTarget.Temporary(eelDescriptor));
@@ -213,14 +216,14 @@ public final class LocalShellIntegrationInjector {
else {
result.add(rcFilePath);
}
int idx = arguments.indexOf(rcfileOption);
int idx = arguments.indexOf(BASH_RCFILE_OPTION);
if (idx >= 0) {
arguments.remove(idx);
if (idx < arguments.size()) {
String userRcFile = FileUtil.expandUserHome(arguments.get(idx));
// do not set the same RC file path to avoid sourcing recursion
if (!userRcFile.equals(rcFilePath)) {
envs.put(JEDITERM_USER_RCFILE, FileUtil.expandUserHome(arguments.get(idx)));
envs.put(JEDITERM_USER_RCFILE, userRcFile);
}
arguments.remove(idx);
}

View File

@@ -2,7 +2,6 @@
package org.jetbrains.plugins.terminal.runner
import com.intellij.idea.TestFor
import com.intellij.util.PathUtil
import org.jetbrains.plugins.terminal.ShellStartupOptions
import org.jetbrains.plugins.terminal.runner.LocalShellIntegrationInjector.findAbsolutePath
import org.jetbrains.plugins.terminal.shell_integration.CommandBlockIntegration
@@ -17,7 +16,7 @@ internal class LocalShellIntegrationInjectorTest {
fun testZsh() {
val actual = LocalShellIntegrationInjector.injectShellIntegration(
ShellStartupOptions.Builder()
.shellCommand(mutableListOf<String>("/bin/zsh"))
.shellCommand(mutableListOf("/bin/zsh"))
.envVariables(buildMap {
put("MY_CUSTOM_ENV1", "MY_CUSTOM_ENV_VALUE1")
})
@@ -28,12 +27,12 @@ internal class LocalShellIntegrationInjectorTest {
assertEquals(listOf("/bin/zsh"), actual.shellCommand)
assertEquals(ShellIntegration(ShellType.ZSH, CommandBlockIntegration(false)), actual.shellIntegration)
assertEquals(PathUtil.getParentPath(findAbsolutePath("shell-integrations/zsh/zsh-integration.zsh")), actual.envVariables[LocalShellIntegrationInjector.IJ_ZSH_DIR])
assertEquals(findAbsolutePath("shell-integrations/zsh/zsh-integration.zsh").parent.toString(), actual.envVariables[LocalShellIntegrationInjector.IJ_ZSH_DIR])
assertEquals("1", actual.envVariables["PROCESS_LAUNCHED_BY_CW"])
assertEquals("1", actual.envVariables["FIG_TERM"])
assertEquals("1", actual.envVariables["PROCESS_LAUNCHED_BY_Q"])
assertEquals("1", actual.envVariables["INTELLIJ_TERMINAL_COMMAND_BLOCKS"])
assertEquals(PathUtil.getParentPath(findAbsolutePath("shell-integrations/zsh/zdotdir/.zshenv")), actual.envVariables["ZDOTDIR"])
assertEquals(findAbsolutePath("shell-integrations/zsh/zdotdir/.zshenv").parent.toString(), actual.envVariables["ZDOTDIR"])
assertEquals("MY_CUSTOM_ENV_VALUE1", actual.envVariables["MY_CUSTOM_ENV1"])
}
@@ -50,7 +49,7 @@ internal class LocalShellIntegrationInjectorTest {
false
)
assertEquals(listOf("/bin/bash", "--rcfile", findAbsolutePath("shell-integrations/bash/bash-integration.bash")), actual.shellCommand)
assertEquals(listOf("/bin/bash", "--rcfile", findAbsolutePath("shell-integrations/bash/bash-integration.bash").toString()), actual.shellCommand)
assertEquals(ShellIntegration(ShellType.BASH, CommandBlockIntegration(false)), actual.shellIntegration)
assertEquals("1", actual.envVariables["PROCESS_LAUNCHED_BY_CW"])
assertEquals("1", actual.envVariables["FIG_TERM"])