Skip to content

Commit 953bdc6

Browse files
debug: fallback to mark breakpoints verified on stopped/breakpoint events
1 parent 88c724a commit 953bdc6

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

src/debugger/logTracker.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker {
114114
return;
115115
}
116116

117+
this.handleBreakpointFallback(debugMessage);
118+
117119
if (debugMessage.event === "exited" && debugMessage.body.exitCode) {
118120
this.exitCode = debugMessage.body.exitCode;
119121
this.exitHandler?.(debugMessage.body.exitCode);
@@ -131,6 +133,102 @@ export class LoggingDebugAdapterTracker implements vscode.DebugAdapterTracker {
131133
}
132134
}
133135

136+
private handleBreakpointFallback(rawMsg: unknown): void {
137+
try {
138+
// Minimal typed view of the event payload we care about.
139+
type FrameLike = { source?: { path?: string }; line?: number };
140+
type BodyLike = {
141+
exitCode?: number;
142+
category?: string;
143+
output?: string;
144+
reason?: string;
145+
thread?: { frames?: FrameLike[] };
146+
source?: { path?: string };
147+
line?: number;
148+
};
149+
150+
const msg = rawMsg as { type?: string; event?: string; body?: BodyLike | undefined };
151+
if (!msg || msg.type !== "event") {
152+
return;
153+
}
154+
155+
// Case A: stopped event with reason = "breakpoint"
156+
if (msg.event === "stopped" && msg.body?.reason === "breakpoint") {
157+
const frames = msg.body.thread?.frames;
158+
if (!Array.isArray(frames) || frames.length === 0) {
159+
return;
160+
}
161+
162+
const top = frames[0];
163+
const sourcePath = top?.source?.path;
164+
const line = top?.line;
165+
if (!sourcePath || typeof line !== "number") {
166+
return;
167+
}
168+
169+
const bpLine0 = line - 1; // VS Code uses 0-based lines
170+
171+
const breakpoints = vscode.debug.breakpoints.filter(
172+
b => b instanceof vscode.SourceBreakpoint
173+
) as vscode.SourceBreakpoint[];
174+
175+
for (const bp of breakpoints) {
176+
const loc = bp.location;
177+
if (!loc) {
178+
continue;
179+
}
180+
if (loc.uri.fsPath !== sourcePath) {
181+
continue;
182+
}
183+
if (loc.range.start.line !== bpLine0) {
184+
continue;
185+
}
186+
187+
// Force a UI refresh so the breakpoint shows as installed.
188+
vscode.debug.removeBreakpoints([bp]);
189+
vscode.debug.addBreakpoints([bp]);
190+
break;
191+
}
192+
return;
193+
}
194+
195+
// Case B: explicit "breakpoint" event that carries source+line info
196+
if (msg.event === "breakpoint" && msg.body) {
197+
const sourcePath = msg.body.source?.path;
198+
const line = msg.body.line;
199+
if (!sourcePath || typeof line !== "number") {
200+
return;
201+
}
202+
203+
const bpLine0 = line - 1;
204+
const breakpoints = vscode.debug.breakpoints.filter(
205+
b => b instanceof vscode.SourceBreakpoint
206+
) as vscode.SourceBreakpoint[];
207+
208+
for (const bp of breakpoints) {
209+
const loc = bp.location;
210+
if (!loc) {
211+
continue;
212+
}
213+
if (loc.uri.fsPath !== sourcePath) {
214+
continue;
215+
}
216+
if (loc.range.start.line !== bpLine0) {
217+
continue;
218+
}
219+
220+
vscode.debug.removeBreakpoints([bp]);
221+
vscode.debug.addBreakpoints([bp]);
222+
break;
223+
}
224+
return;
225+
}
226+
} catch (err) {
227+
// eslint-disable-next-line no-console
228+
console.error("Breakpoint fallback error:", err);
229+
}
230+
}
231+
134232
/**
135233
* The debug adapter session is about to be stopped. Delete the session from
136234
* the tracker

0 commit comments

Comments
 (0)