in src/vs/workbench/contrib/debug/browser/debugService.ts [370:462]
private async createSession(launch: ILaunch | undefined, config: IConfig | undefined, options?: IDebugSessionOptions): Promise<boolean> {
// We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes.
// Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config.
let type: string | undefined;
if (config) {
type = config.type;
} else {
// a no-folder workspace has no launch.config
config = Object.create(null);
}
if (options && options.noDebug) {
config!.noDebug = true;
} else if (options && typeof options.noDebug === 'undefined' && options.parentSession && options.parentSession.configuration.noDebug) {
config!.noDebug = true;
}
const unresolvedConfig = deepClone(config);
if (!type) {
const guess = await this.configurationManager.guessDebugger();
if (guess) {
type = guess.type;
}
}
const initCancellationToken = new CancellationTokenSource();
const sessionId = generateUuid();
this.sessionCancellationTokens.set(sessionId, initCancellationToken);
const configByProviders = await this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, initCancellationToken.token);
// a falsy config indicates an aborted launch
if (configByProviders && configByProviders.type) {
try {
let resolvedConfig = await this.substituteVariables(launch, configByProviders);
if (!resolvedConfig) {
// User cancelled resolving of interactive variables, silently return
return false;
}
if (initCancellationToken.token.isCancellationRequested) {
// User cancelled, silently return
return false;
}
const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, initCancellationToken.token);
if (!cfg) {
if (launch && type && cfg === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
await launch.openConfigFile(true, type, initCancellationToken.token);
}
return false;
}
resolvedConfig = cfg;
if (!this.configurationManager.getDebugger(resolvedConfig.type) || (configByProviders.request !== 'attach' && configByProviders.request !== 'launch')) {
let message: string;
if (configByProviders.request !== 'attach' && configByProviders.request !== 'launch') {
message = configByProviders.request ? nls.localize('debugRequestNotSupported', "Attribute '{0}' has an unsupported value '{1}' in the chosen debug configuration.", 'request', configByProviders.request)
: nls.localize('debugRequesMissing', "Attribute '{0}' is missing from the chosen debug configuration.", 'request');
} else {
message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) :
nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration.");
}
await this.showError(message);
return false;
}
const workspace = launch?.workspace || this.contextService.getWorkspace();
const taskResult = await this.taskRunner.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask, (msg, actions) => this.showError(msg, actions));
if (taskResult === TaskRunResult.Success) {
return this.doCreateSession(sessionId, launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
}
return false;
} catch (err) {
if (err && err.message) {
await this.showError(err.message);
} else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
await this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type."));
}
if (launch && !initCancellationToken.token.isCancellationRequested) {
await launch.openConfigFile(true, undefined, initCancellationToken.token);
}
return false;
}
}
if (launch && type && configByProviders === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
await launch.openConfigFile(true, type, initCancellationToken.token);
}
return false;
}