private async _createShellLaunchConfig()

in patched-vscode/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts [1064:1263]


	private async _createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: WaitOnExitValue): Promise<IShellLaunchConfig | undefined> {
		let shellLaunchConfig: IShellLaunchConfig;
		const isShellCommand = task.command.runtime === RuntimeType.Shell;
		const needsFolderQualification = this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE;
		const terminalName = this._createTerminalName(task);
		const type = ReconnectionType;
		const originalCommand = task.command.name;
		let cwd: string | URI | undefined;
		if (options.cwd) {
			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
			cwd = isUNC(cwd) ? cwd : resources.toLocalResource(URI.from({ scheme: Schemas.file, path: cwd }), this._environmentService.remoteAuthority, this._pathService.defaultUriScheme);
		}
		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
			});
			let icon: URI | ThemeIcon | { light: URI; dark: URI } | undefined;
			if (task.configurationProperties.icon?.id) {
				icon = ThemeIcon.fromId(task.configurationProperties.icon.id);
			} else {
				const taskGroupKind = task.configurationProperties.group ? GroupKind.to(task.configurationProperties.group) : undefined;
				const kindId = typeof taskGroupKind === 'string' ? taskGroupKind : taskGroupKind?.kind;
				icon = kindId === 'test' ? ThemeIcon.fromId(Codicon.beaker.id) : defaultProfile.icon;
			}
			shellLaunchConfig = {
				name: terminalName,
				type,
				executable: defaultProfile.path,
				args: defaultProfile.args,
				env: { ...defaultProfile.env },
				icon,
				color: task.configurationProperties.icon?.color || undefined,
				waitOnExit
			};
			let shellSpecified: boolean = false;
			const shellOptions: IShellConfiguration | 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 = [];
			}
			const shellArgs = Array.isArray(shellLaunchConfig.args) ? <string[]>shellLaunchConfig.args.slice(0) : [shellLaunchConfig.args];
			const toAdd: string[] = [];
			const basename = path.posix.basename((await this._pathService.fileURI(shellLaunchConfig.executable!)).path).toLowerCase();
			const 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
						// TODO: Handle by pulling the default terminal profile?
						// 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)) {
						// 	const 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) {
					const folder = cwd && typeof cwd === 'object' && 'path' in cwd ? path.basename(cwd.path) : workspaceFolder.name;
					shellLaunchConfig.initialText = this.taskShellIntegrationStartSequence(cwd) + formatMessageForTerminal(nls.localize({
						key: 'task.executingInFolder',
						comment: ['The workspace folder the task is running in', 'The task command line or label']

					}, 'Executing task in folder {0}: {1}', folder, commandLine), { excludeLeadingNewLine: true }) + this.taskShellIntegrationOutputSequence;
				} else {
					shellLaunchConfig.initialText = this.taskShellIntegrationStartSequence(cwd) + formatMessageForTerminal(nls.localize({
						key: 'task.executing.shellIntegration',
						comment: ['The task command line or label']
					}, 'Executing task: {0}', commandLine), { excludeLeadingNewLine: true }) + this.taskShellIntegrationOutputSequence;
				}
			} else {
				shellLaunchConfig.initialText = {
					text: this.taskShellIntegrationStartSequence(cwd) + this.taskShellIntegrationOutputSequence,
					trailingNewLine: false
				};
			}
		} else {
			const commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution) ? CommandString.value(command) : undefined;
			const 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,
				type,
				icon: task.configurationProperties.icon?.id ? ThemeIcon.fromId(task.configurationProperties.icon.id) : undefined,
				color: task.configurationProperties.icon?.color || undefined,
				executable: executable,
				args: args.map(a => Types.isString(a) ? a : a.value),
				waitOnExit
			};
			if (task.command.presentation && task.command.presentation.echo) {
				const 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 = this.taskShellIntegrationStartSequence(cwd) + formatMessageForTerminal(nls.localize({
						key: 'task.executingInFolder',
						comment: ['The workspace folder the task is running in', 'The task command line or label']
					}, 'Executing task in folder {0}: {1}', workspaceFolder.name, `${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)}`), { excludeLeadingNewLine: true }) + this.taskShellIntegrationOutputSequence;
				} else {
					shellLaunchConfig.initialText = this.taskShellIntegrationStartSequence(cwd) + formatMessageForTerminal(nls.localize({
						key: 'task.executing.shell-integration',
						comment: ['The task command line or label']
					}, 'Executing task: {0}', `${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)}`), { excludeLeadingNewLine: true }) + this.taskShellIntegrationOutputSequence;
				}
			} else {
				shellLaunchConfig.initialText = {
					text: this.taskShellIntegrationStartSequence(cwd) + this.taskShellIntegrationOutputSequence,
					trailingNewLine: false
				};
			}
		}

		if (cwd) {
			shellLaunchConfig.cwd = cwd;
		}
		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;
	}