in src/debugAdapter/goDebug.ts [2131:2247]
private async setBreakPoints(
response: DebugProtocol.SetBreakpointsResponse,
args: DebugProtocol.SetBreakpointsArguments
): Promise<void> {
const file = normalizePath(args.source.path);
if (!this.breakpoints.get(file)) {
this.breakpoints.set(file, []);
}
const remoteFile = await this.toDebuggerPath(file);
return Promise.all(
this.breakpoints.get(file).map((existingBP) => {
log('Clearing: ' + existingBP.id);
return this.delve.callPromise('ClearBreakpoint', [
this.delve.isApiV1 ? existingBP.id : { Id: existingBP.id }
]);
})
)
.then(() => {
log('All cleared');
let existingBreakpoints: DebugBreakpoint[] | undefined;
return Promise.all(
args.breakpoints.map((breakpoint) => {
if (this.delve.remotePath.length === 0) {
log('Creating on: ' + file + ':' + breakpoint.line);
} else {
log('Creating on: ' + file + ' (' + remoteFile + ') :' + breakpoint.line);
}
const breakpointIn = <DebugBreakpoint>{};
breakpointIn.file = remoteFile;
breakpointIn.line = breakpoint.line;
breakpointIn.loadArgs = this.delve.loadConfig;
breakpointIn.loadLocals = this.delve.loadConfig;
breakpointIn.cond = breakpoint.condition;
return this.delve
.callPromise('CreateBreakpoint', [
this.delve.isApiV1 ? breakpointIn : { Breakpoint: breakpointIn }
])
.then(null, async (err) => {
// Delve does not seem to support error code at this time.
// TODO(quoct): Follow up with delve team.
if (err.toString().startsWith('Breakpoint exists at')) {
log('Encounter existing breakpoint: ' + breakpointIn);
// We need to call listbreakpoints to find the ID.
// Otherwise, we would not be able to clear the breakpoints.
if (!existingBreakpoints) {
try {
const listBreakpointsResponse = await this.delve.callPromise<
ListBreakpointsOut | DebugBreakpoint[]
>('ListBreakpoints', this.delve.isApiV1 ? [] : [{}]);
existingBreakpoints = this.delve.isApiV1
? (listBreakpointsResponse as DebugBreakpoint[])
: (listBreakpointsResponse as ListBreakpointsOut).Breakpoints;
} catch (error) {
log('Error listing breakpoints: ' + error.toString());
return null;
}
}
// Make sure that we compare the file names with the same separators.
const matchedBreakpoint = existingBreakpoints.find(
(existingBreakpoint) =>
existingBreakpoint.line === breakpointIn.line &&
compareFilePathIgnoreSeparator(existingBreakpoint.file, breakpointIn.file)
);
if (!matchedBreakpoint) {
log(`Cannot match breakpoint ${breakpointIn} with existing breakpoints.`);
return null;
}
return this.delve.isApiV1 ? matchedBreakpoint : { Breakpoint: matchedBreakpoint };
}
log('Error on CreateBreakpoint: ' + err.toString());
return null;
});
})
);
})
.then((newBreakpoints) => {
let convertedBreakpoints: DebugBreakpoint[];
if (!this.delve.isApiV1) {
// Unwrap breakpoints from v2 apicall
convertedBreakpoints = newBreakpoints.map((bp, i) => {
return bp ? (bp as CreateBreakpointOut).Breakpoint : null;
});
} else {
convertedBreakpoints = newBreakpoints as DebugBreakpoint[];
}
log('All set:' + JSON.stringify(newBreakpoints));
const breakpoints = convertedBreakpoints.map((bp, i) => {
if (bp) {
return { verified: true, line: bp.line };
} else {
return { verified: false, line: args.lines[i] };
}
});
this.breakpoints.set(
file,
convertedBreakpoints.filter((x) => !!x)
);
return breakpoints;
})
.then(
(breakpoints) => {
response.body = { breakpoints };
this.sendResponse(response);
log('SetBreakPointsResponse');
},
(err) => {
this.sendErrorResponse(response, 2002, 'Failed to set breakpoint: "{e}"', {
e: err.toString()
});
logError(err);
}
);
}