дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
fix(debugger): keep execution highlights synchronized (#681)
Inline debugger values looked up source identifiers in a plain object, so a name like toString on a nearby line resolved to an inherited Object.prototype member and crashed the editor's inline-values plugin. The execution-point subscription lived in that plugin, so after the crash the highlighted line stayed on the old position while the stack had moved on, and resume or stop did not clear it. Locals are now kept in a prototype-free dictionary and looked up by own property, and the execution point is synced by its own plugin so an inline-value failure can't freeze it; hidden editors resync when remounted. Stepping, resume, run to cursor, reset frame and smart step clear the old execution point as soon as the request is sent, stale stack/locals responses from a previous stop are ignored, and another thread's continued event no longer clears the selected thread's execution point. Fixes #668
Цей коміт міститься в:
1 джерело
210f9a78ac
коміт
be7e2ff710
10 files changed
+416
-42
No files matched your search
@@ -49,6 +49,7 @@ function currentExec(path: string): Exec | null {
|
||||
export function inlineValuesFor(text: string, values: Record<string, string>): string | null {
|
||||
const parts: string[] = [];
|
||||
for (const id of identifiersIn(text)) {
|
||||
if (!Object.hasOwn(values, id)) continue;
|
||||
const v = values[id];
|
||||
if (v === undefined) continue;
|
||||
parts.push(`${id}: ${inlineValue(v, 40)}`);
|
||||
@@ -80,33 +81,48 @@ export function executionPoint(ctx: EditorDocContext): Extension {
|
||||
provide: (f) => EditorView.decorations.compute([f], (state) => lineDecorations(state, state.field(f))),
|
||||
});
|
||||
|
||||
// Keep the execution line alive even if an inline-value renderer fails.
|
||||
const sync = ViewPlugin.fromClass(
|
||||
class {
|
||||
private unsub: () => void;
|
||||
private pending = false;
|
||||
private destroyed = false;
|
||||
constructor(readonly view: EditorView) {
|
||||
this.unsub = useExecutionPoint.subscribe(() => this.refresh());
|
||||
// Hidden tabs retain EditorState while their views are unmounted.
|
||||
this.refresh();
|
||||
}
|
||||
refresh() {
|
||||
if (this.pending) return;
|
||||
this.pending = true;
|
||||
queueMicrotask(() => {
|
||||
this.pending = false;
|
||||
if (this.destroyed) return;
|
||||
const next = currentExec(path);
|
||||
const cur = this.view.state.field(execField);
|
||||
const moved = cur?.line !== next?.line || cur?.top !== next?.top || !!cur !== !!next;
|
||||
// Locals can change without moving the execution point.
|
||||
this.view.dispatch(moved ? { effects: setExec.of(next) } : {});
|
||||
});
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.unsub();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const inline = ViewPlugin.fromClass(
|
||||
class {
|
||||
decorations: DecorationSet = Decoration.none;
|
||||
private unsub: () => void;
|
||||
private pending = false;
|
||||
private destroyed = false;
|
||||
private unsubSettings: () => void;
|
||||
constructor(readonly view: EditorView) {
|
||||
this.decorations = this.build();
|
||||
// Settings › Debugger › Data Views › Show values inline.
|
||||
this.unsubSettings = onWorkflowSettingsChange(
|
||||
(s) => s.debugger.inlineValues,
|
||||
() => queueMicrotask(() => !this.destroyed && this.view.dispatch({})),
|
||||
);
|
||||
this.unsub = useExecutionPoint.subscribe(() => {
|
||||
if (this.pending) return;
|
||||
this.pending = true;
|
||||
queueMicrotask(() => {
|
||||
this.pending = false;
|
||||
if (this.destroyed) return;
|
||||
const next = currentExec(path);
|
||||
const cur = this.view.state.field(execField);
|
||||
const moved = cur?.line !== next?.line || cur?.top !== next?.top || !!cur !== !!next;
|
||||
// An empty transaction still rebuilds the inline values (locals arrive after the frame).
|
||||
this.view.dispatch(moved ? { effects: setExec.of(next) } : {});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
update(u: ViewUpdate) {
|
||||
@@ -136,12 +152,11 @@ export function executionPoint(ctx: EditorDocContext): Extension {
|
||||
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.unsub();
|
||||
this.unsubSettings();
|
||||
}
|
||||
},
|
||||
{ decorations: (v) => v.decorations },
|
||||
);
|
||||
|
||||
return [execField, inline];
|
||||
return [execField, sync, inline];
|
||||
}
|
||||
Reference in new issue
Заблокувати користувача