in src/goDebugConfiguration.ts [405:501]
public resolveDebugConfigurationWithSubstitutedVariables(
folder: vscode.WorkspaceFolder | undefined,
debugConfiguration: vscode.DebugConfiguration,
token?: vscode.CancellationToken
): vscode.DebugConfiguration | null {
const debugAdapter = debugConfiguration['debugAdapter'];
if (debugAdapter === '') {
return null;
}
// Read debugConfiguration.envFile and
// combine the environment variables from all the env files and
// debugConfiguration.env.
// We also unset 'envFile' from the user-suppled debugConfiguration
// because it is already applied.
//
// For legacy mode, we merge the environment variables on top of
// the tools execution environment variables and update the debugConfiguration
// because VS Code directly handles launch of the legacy debug adapter.
// For dlv-dap mode, we do not merge process.env environment
// variables here to reduce the number of environment variables passed
// as launch/attach parameters.
const mergeProcessEnv = debugAdapter === 'legacy';
const goToolsEnvVars = toolExecutionEnvironment(folder?.uri, mergeProcessEnv);
const fileEnvs = parseEnvFiles(debugConfiguration['envFile']);
const env = debugConfiguration['env'] || {};
debugConfiguration['env'] = Object.assign(goToolsEnvVars, fileEnvs, env);
debugConfiguration['envFile'] = undefined; // unset, since we already processed.
const entriesWithRelativePaths = ['cwd', 'output', 'program'].filter(
(attr) => debugConfiguration[attr] && !path.isAbsolute(debugConfiguration[attr])
);
if (debugAdapter === 'dlv-dap') {
// 1. Relative paths -> absolute paths
if (entriesWithRelativePaths.length > 0) {
const workspaceRoot = folder?.uri.fsPath;
if (workspaceRoot) {
entriesWithRelativePaths.forEach((attr) => {
debugConfiguration[attr] = path.join(workspaceRoot, debugConfiguration[attr]);
});
} else {
this.showWarning(
'relativePathsWithoutWorkspaceFolder',
'Behavior when using relative paths without a workspace folder for `cwd`, `program`, or `output` is undefined.'
);
}
}
// 2. For launch debug/test modes that builds the debug target,
// delve needs to be launched from the right directory (inside the main module of the target).
// Compute the launch dir heuristically, and translate the dirname in program to a path relative to buildDir.
// We skip this step when working with externally launched debug adapter
// because we do not control the adapter's launch process.
if (debugConfiguration.request === 'launch') {
const mode = debugConfiguration['mode'] || 'debug';
if (['debug', 'test', 'auto'].includes(mode)) {
// Massage config to build the target from the package directory
// with a relative path. (https://github.com/golang/vscode-go/issues/1713)
// parseDebugProgramArgSync will throw an error if `program` is invalid.
const { program, dirname, programIsDirectory } = parseDebugProgramArgSync(
debugConfiguration['program']
);
if (
dirname &&
// Presence of the following attributes indicates externally launched debug adapter.
// Don't mess with 'program' if the debug adapter was launched externally.
!debugConfiguration.port &&
!debugConfiguration.debugServer
) {
debugConfiguration['__buildDir'] = dirname;
debugConfiguration['program'] = programIsDirectory
? '.'
: '.' + path.sep + path.relative(dirname, program);
}
}
}
}
// convert args string into string array if needed
if (debugConfiguration.request === 'launch' && typeof debugConfiguration['args'] === 'string') {
const argsOrErrorMsg = parseArgsString(debugConfiguration['args']);
if (typeof argsOrErrorMsg === 'string') {
throw new Error(argsOrErrorMsg);
} else {
debugConfiguration['args'] = argsOrErrorMsg;
}
}
if (debugConfiguration.request === 'attach' && debugConfiguration['mode'] === 'local') {
// processId needs to be an int, but the substituted variables from pickGoProcess and pickProcess
// become a string. Convert any strings to integers.
if (typeof debugConfiguration['processId'] === 'string') {
debugConfiguration['processId'] = parseInt(debugConfiguration['processId'], 10);
}
}
return debugConfiguration;
}