in src/debugAdapter/goDebug.ts [2149:2265]
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(undefined, 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);
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 | null)[];
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 is DebugBreakpoint => !!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);
}
);
}