diff --git a/src/render/diffViewer.ts b/src/render/diffViewer.ts index 29d673f..b3e25f9 100644 --- a/src/render/diffViewer.ts +++ b/src/render/diffViewer.ts @@ -30,6 +30,7 @@ export class DiffViewer { private tmpFiles: string[] = []; /** ★ 原子锁:Diff 正在打开中,禁止清除 session */ private isOpening = false; + private closeListener: vscode.Disposable | null = null; /** 外部回调:Diff 操作完成后通知(用于刷新 UI) */ onDiffAction?: () => void; @@ -51,19 +52,19 @@ export class DiffViewer { const afterPath = this.makeTmpFile(`ai-diff-after-${editRecord.id.slice(0, 8)}${ext}`, editRecord.afterContent); this.isOpening = true; - this.activeSession = { + this.setSession({ fileId: fileChangeId, editId: editRecord.id, beforeTmpPath: beforePath, afterTmpPath: afterPath, beforeUri: vscode.Uri.file(beforePath), afterUri: vscode.Uri.file(afterPath), - }; + }); await vscode.commands.executeCommand( 'vscode.diff', - this.activeSession.beforeUri, - this.activeSession.afterUri, + this.activeSession!.beforeUri, + this.activeSession!.afterUri, `${fileName} — AI ${toolLabel} #${editRecord.id.slice(0, 6)} · 状态栏操作` ); @@ -79,18 +80,18 @@ export class DiffViewer { const afterPath = this.makeTmpFile(`ai-diff-after-${fileChange.id.slice(0, 8)}${ext}`, fileChange.latestContent); this.isOpening = true; - this.activeSession = { + this.setSession({ fileId: fileChange.id, beforeTmpPath: beforePath, afterTmpPath: afterPath, beforeUri: vscode.Uri.file(beforePath), afterUri: vscode.Uri.file(afterPath), - }; + }); await vscode.commands.executeCommand( 'vscode.diff', - this.activeSession.beforeUri, - this.activeSession.afterUri, + this.activeSession!.beforeUri, + this.activeSession!.afterUri, `${fileName} — ${fileChange.edits.length} 次 AI 编辑 · 状态栏操作` ); @@ -188,11 +189,31 @@ export class DiffViewer { if (this.activeSession) { try { await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); } catch { /* ok */ } } - this.activeSession = null; + this.clearSession(); } // ---- 内部 ---- + private setSession(session: DiffSession): void { + this.clearSession(); + this.activeSession = session; + // ★ isOpening 锁保护:只有非 opening 状态下的关闭才清除 session + this.closeListener = vscode.window.onDidChangeVisibleTextEditors(() => { + if (this.isOpening) return; // ← 打开中,不检测 + if (!this.activeSession) return; + const stillOpen = vscode.window.visibleTextEditors.some( + e => e.document.uri.toString() === this.activeSession!.beforeUri.toString() || + e.document.uri.toString() === this.activeSession!.afterUri.toString() + ); + if (!stillOpen) this.clearSession(); + }); + } + + private clearSession(): void { + this.activeSession = null; + if (this.closeListener) { this.closeListener.dispose(); this.closeListener = null; } + } + private makeTmpFile(name: string, content: string): string { const dir = path.join(os.tmpdir(), 'ai-diff-preview'); if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });