in src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts [1033:1193]
private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise<IShellLaunchConfig | undefined> {
let shellLaunchConfig: IShellLaunchConfig;
let isShellCommand = task.command.runtime === RuntimeType.Shell;
let needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE;
let terminalName = this.createTerminalName(task);
const description = nls.localize('TerminalTaskSystem.terminalDescription', 'Task');
let originalCommand = task.command.name;
if (isShellCommand) {
let os: Platform.OperatingSystem;
switch (platform) {
case Platform.Platform.Windows: os = Platform.OperatingSystem.Windows; break;
case Platform.Platform.Mac: os = Platform.OperatingSystem.Macintosh; break;
case Platform.Platform.Linux:
default: os = Platform.OperatingSystem.Linux; break;
}
const defaultProfile = await this.terminalProfileResolverService.getDefaultProfile({
allowAutomationShell: true,
os,
remoteAuthority: this.environmentService.remoteAuthority
});
shellLaunchConfig = {
name: terminalName,
description,
executable: defaultProfile.path,
args: defaultProfile.args,
icon: defaultProfile.icon,
env: { ...defaultProfile.env },
color: defaultProfile.color,
waitOnExit
};
let shellSpecified: boolean = false;
let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell;
if (shellOptions) {
if (shellOptions.executable) {
// Clear out the args so that we don't end up with mismatched args.
if (shellOptions.executable !== shellLaunchConfig.executable) {
shellLaunchConfig.args = undefined;
}
shellLaunchConfig.executable = await this.resolveVariable(variableResolver, shellOptions.executable);
shellSpecified = true;
}
if (shellOptions.args) {
shellLaunchConfig.args = await this.resolveVariables(variableResolver, shellOptions.args.slice());
}
}
if (shellLaunchConfig.args === undefined) {
shellLaunchConfig.args = [];
}
let shellArgs = Array.isArray(shellLaunchConfig.args!) ? <string[]>shellLaunchConfig.args!.slice(0) : [shellLaunchConfig.args!];
let toAdd: string[] = [];
let basename = path.posix.basename((await this.pathService.fileURI(shellLaunchConfig.executable!)).path).toLowerCase();
let commandLine = this.buildShellCommandLine(platform, basename, shellOptions, command, originalCommand, args);
let windowsShellArgs: boolean = false;
if (platform === Platform.Platform.Windows) {
windowsShellArgs = true;
// If we don't have a cwd, then the terminal uses the home dir.
const userHome = await this.pathService.userHome();
if (basename === 'cmd.exe' && ((options.cwd && isUNC(options.cwd)) || (!options.cwd && isUNC(userHome.fsPath)))) {
return undefined;
}
if ((basename === 'powershell.exe') || (basename === 'pwsh.exe')) {
if (!shellSpecified) {
toAdd.push('-Command');
}
} else if ((basename === 'bash.exe') || (basename === 'zsh.exe')) {
windowsShellArgs = false;
if (!shellSpecified) {
toAdd.push('-c');
}
} else if (basename === 'wsl.exe') {
if (!shellSpecified) {
toAdd.push('-e');
}
} else {
if (!shellSpecified) {
toAdd.push('/d', '/c');
}
}
} else {
if (!shellSpecified) {
// Under Mac remove -l to not start it as a login shell.
if (platform === Platform.Platform.Mac) {
// Background on -l on osx https://github.com/microsoft/vscode/issues/107563
const osxShellArgs = this.configurationService.inspect(TerminalSettingId.ShellArgsMacOs);
if ((osxShellArgs.user === undefined) && (osxShellArgs.userLocal === undefined) && (osxShellArgs.userLocalValue === undefined)
&& (osxShellArgs.userRemote === undefined) && (osxShellArgs.userRemoteValue === undefined)
&& (osxShellArgs.userValue === undefined) && (osxShellArgs.workspace === undefined)
&& (osxShellArgs.workspaceFolder === undefined) && (osxShellArgs.workspaceFolderValue === undefined)
&& (osxShellArgs.workspaceValue === undefined)) {
let index = shellArgs.indexOf('-l');
if (index !== -1) {
shellArgs.splice(index, 1);
}
}
}
toAdd.push('-c');
}
}
const combinedShellArgs = this.addAllArgument(toAdd, shellArgs);
combinedShellArgs.push(commandLine);
shellLaunchConfig.args = windowsShellArgs ? combinedShellArgs.join(' ') : combinedShellArgs;
if (task.command.presentation && task.command.presentation.echo) {
if (needsFolderQualification && workspaceFolder) {
shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${commandLine} <\x1b[0m\n`;
} else {
shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`;
}
}
} else {
let commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution) ? CommandString.value(command) : undefined;
let executable = !isShellCommand
? await this.resolveVariable(variableResolver, await this.resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}'))
: commandExecutable;
// When we have a process task there is no need to quote arguments. So we go ahead and take the string value.
shellLaunchConfig = {
name: terminalName,
description,
executable: executable,
args: args.map(a => Types.isString(a) ? a : a.value),
waitOnExit
};
if (task.command.presentation && task.command.presentation.echo) {
let getArgsToEcho = (args: string | string[] | undefined): string => {
if (!args || args.length === 0) {
return '';
}
if (Types.isString(args)) {
return args;
}
return args.join(' ');
};
if (needsFolderQualification && workspaceFolder) {
shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`;
} else {
shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`;
}
}
}
if (options.cwd) {
let cwd = options.cwd;
if (!path.isAbsolute(cwd)) {
if (workspaceFolder && (workspaceFolder.uri.scheme === Schemas.file)) {
cwd = path.join(workspaceFolder.uri.fsPath, cwd);
}
}
// This must be normalized to the OS
shellLaunchConfig.cwd = isUNC(cwd) ? cwd : resources.toLocalResource(URI.from({ scheme: Schemas.file, path: cwd }), this.environmentService.remoteAuthority, this.pathService.defaultUriScheme);
}
if (options.env) {
if (shellLaunchConfig.env) {
shellLaunchConfig.env = { ...shellLaunchConfig.env, ...options.env };
} else {
shellLaunchConfig.env = options.env;
}
}
shellLaunchConfig.isFeatureTerminal = true;
shellLaunchConfig.useShellEnvironment = true;
return shellLaunchConfig;
}