in patched-vscode/src/vs/platform/terminal/node/terminalEnvironment.ts [108:273]
export function getShellIntegrationInjection(
shellLaunchConfig: IShellLaunchConfig,
options: ITerminalProcessOptions,
env: ITerminalEnvironment | undefined,
logService: ILogService,
productService: IProductService
): IShellIntegrationConfigInjection | undefined {
// Conditionally disable shell integration arg injection
// - The global setting is disabled
// - There is no executable (not sure what script to run)
// - The terminal is used by a feature like tasks or debugging
const useWinpty = isWindows && (!options.windowsEnableConpty || getWindowsBuildNumber() < 18309);
if (
// The global setting is disabled
!options.shellIntegration.enabled ||
// There is no executable (so there's no way to determine how to inject)
!shellLaunchConfig.executable ||
// It's a feature terminal (tasks, debug), unless it's explicitly being forced
(shellLaunchConfig.isFeatureTerminal && !shellLaunchConfig.forceShellIntegration) ||
// The ignoreShellIntegration flag is passed (eg. relaunching without shell integration)
shellLaunchConfig.ignoreShellIntegration ||
// Winpty is unsupported
useWinpty
) {
return undefined;
}
const originalArgs = shellLaunchConfig.args;
const shell = process.platform === 'win32' ? path.basename(shellLaunchConfig.executable).toLowerCase() : path.basename(shellLaunchConfig.executable);
const appRoot = path.dirname(FileAccess.asFileUri('').fsPath);
let newArgs: string[] | undefined;
const envMixin: IProcessEnvironment = {
'VSCODE_INJECTION': '1'
};
if (options.shellIntegration.nonce) {
envMixin['VSCODE_NONCE'] = options.shellIntegration.nonce;
}
// Windows
if (isWindows) {
if (shell === 'pwsh.exe' || shell === 'powershell.exe') {
if (!originalArgs || arePwshImpliedArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwsh);
} else if (arePwshLoginArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.WindowsPwshLogin);
}
if (!newArgs) {
return undefined;
}
newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array
newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot, '');
if (options.shellIntegration.suggestEnabled) {
envMixin['VSCODE_SUGGEST'] = '1';
}
return { newArgs, envMixin };
} else if (shell === 'bash.exe') {
if (!originalArgs || originalArgs.length === 0) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
} else if (areZshBashLoginArgs(originalArgs)) {
envMixin['VSCODE_SHELL_LOGIN'] = '1';
addEnvMixinPathPrefix(options, envMixin);
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
}
if (!newArgs) {
return undefined;
}
newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array
newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot);
return { newArgs, envMixin };
}
logService.warn(`Shell integration cannot be enabled for executable "${shellLaunchConfig.executable}" and args`, shellLaunchConfig.args);
return undefined;
}
// Linux & macOS
switch (shell) {
case 'bash': {
if (!originalArgs || originalArgs.length === 0) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
} else if (areZshBashLoginArgs(originalArgs)) {
envMixin['VSCODE_SHELL_LOGIN'] = '1';
addEnvMixinPathPrefix(options, envMixin);
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
}
if (!newArgs) {
return undefined;
}
newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array
newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot);
return { newArgs, envMixin };
}
case 'fish': {
// The injection mechanism used for fish is to add a custom dir to $XDG_DATA_DIRS which
// is similar to $ZDOTDIR in zsh but contains a list of directories to run from.
const oldDataDirs = env?.XDG_DATA_DIRS ?? '/usr/local/share:/usr/share';
const newDataDir = path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/fish_xdg_data');
envMixin['XDG_DATA_DIRS'] = `${oldDataDirs}:${newDataDir}`;
addEnvMixinPathPrefix(options, envMixin);
return { newArgs: undefined, envMixin };
}
case 'pwsh': {
if (!originalArgs || arePwshImpliedArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Pwsh);
} else if (arePwshLoginArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.PwshLogin);
}
if (!newArgs) {
return undefined;
}
if (options.shellIntegration.suggestEnabled) {
envMixin['VSCODE_SUGGEST'] = '1';
}
newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array
newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot, '');
return { newArgs, envMixin };
}
case 'zsh': {
if (!originalArgs || originalArgs.length === 0) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh);
} else if (areZshBashLoginArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin);
addEnvMixinPathPrefix(options, envMixin);
} else if (originalArgs === shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh) || originalArgs === shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin)) {
newArgs = originalArgs;
}
if (!newArgs) {
return undefined;
}
newArgs = [...newArgs]; // Shallow clone the array to avoid setting the default array
newArgs[newArgs.length - 1] = format(newArgs[newArgs.length - 1], appRoot);
// Move .zshrc into $ZDOTDIR as the way to activate the script
let username: string;
try {
username = os.userInfo().username;
} catch {
username = 'unknown';
}
const zdotdir = path.join(os.tmpdir(), `${username}-${productService.applicationName}-zsh`);
envMixin['ZDOTDIR'] = zdotdir;
const userZdotdir = env?.ZDOTDIR ?? os.homedir() ?? `~`;
envMixin['USER_ZDOTDIR'] = userZdotdir;
const filesToCopy: IShellIntegrationConfigInjection['filesToCopy'] = [];
filesToCopy.push({
source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh'),
dest: path.join(zdotdir, '.zshrc')
});
filesToCopy.push({
source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-profile.zsh'),
dest: path.join(zdotdir, '.zprofile')
});
filesToCopy.push({
source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-env.zsh'),
dest: path.join(zdotdir, '.zshenv')
});
filesToCopy.push({
source: path.join(appRoot, 'out/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh'),
dest: path.join(zdotdir, '.zlogin')
});
return { newArgs, envMixin, filesToCopy };
}
}
logService.warn(`Shell integration cannot be enabled for executable "${shellLaunchConfig.executable}" and args`, shellLaunchConfig.args);
return undefined;
}