Skip to content

Commit ec9b27d

Browse files
daniel-lxsMnehmos
andauthored
Resolve diff editor race condition in multi-monitor setups (#4578)
Co-authored-by: Daniel <[email protected]> Co-authored-by: Mnehmos <[email protected]>
1 parent c0876d0 commit ec9b27d

File tree

1 file changed

+72
-22
lines changed

1 file changed

+72
-22
lines changed

src/integrations/editor/DiffViewProvider.ts

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,7 @@ export class DiffViewProvider {
349349
// Remove only the directories we created, in reverse order.
350350
for (let i = this.createdDirs.length - 1; i >= 0; i--) {
351351
await fs.rmdir(this.createdDirs[i])
352-
console.log(`Directory ${this.createdDirs[i]} has been deleted.`)
353352
}
354-
355-
console.log(`File ${absolutePath} has been deleted.`)
356353
} else {
357354
// Revert document.
358355
const edit = new vscode.WorkspaceEdit()
@@ -369,7 +366,6 @@ export class DiffViewProvider {
369366
// changes and saved during the edit.
370367
await vscode.workspace.applyEdit(edit)
371368
await updatedDocument.save()
372-
console.log(`File ${absolutePath} has been reverted to its original content.`)
373369

374370
if (this.documentWasOpen) {
375371
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), {
@@ -408,7 +404,9 @@ export class DiffViewProvider {
408404

409405
private async openDiffEditor(): Promise<vscode.TextEditor> {
410406
if (!this.relPath) {
411-
throw new Error("No file path set")
407+
throw new Error(
408+
"No file path set for opening diff editor. Ensure open() was called before openDiffEditor()",
409+
)
412410
}
413411

414412
const uri = vscode.Uri.file(path.resolve(this.cwd, this.relPath))
@@ -434,29 +432,81 @@ export class DiffViewProvider {
434432
return new Promise<vscode.TextEditor>((resolve, reject) => {
435433
const fileName = path.basename(uri.fsPath)
436434
const fileExists = this.editType === "modify"
435+
const DIFF_EDITOR_TIMEOUT = 10_000 // ms
436+
437+
let timeoutId: NodeJS.Timeout | undefined
438+
const disposables: vscode.Disposable[] = []
437439

438-
const disposable = vscode.window.onDidChangeActiveTextEditor((editor) => {
439-
if (editor && arePathsEqual(editor.document.uri.fsPath, uri.fsPath)) {
440-
disposable.dispose()
441-
resolve(editor)
440+
const cleanup = () => {
441+
if (timeoutId) {
442+
clearTimeout(timeoutId)
443+
timeoutId = undefined
442444
}
443-
})
445+
disposables.forEach((d) => d.dispose())
446+
disposables.length = 0
447+
}
448+
449+
// Set timeout for the entire operation
450+
timeoutId = setTimeout(() => {
451+
cleanup()
452+
reject(
453+
new Error(
454+
`Failed to open diff editor for ${uri.fsPath} within ${DIFF_EDITOR_TIMEOUT / 1000} seconds. The editor may be blocked or VS Code may be unresponsive.`,
455+
),
456+
)
457+
}, DIFF_EDITOR_TIMEOUT)
458+
459+
// Listen for document open events - more efficient than scanning all tabs
460+
disposables.push(
461+
vscode.workspace.onDidOpenTextDocument(async (document) => {
462+
if (arePathsEqual(document.uri.fsPath, uri.fsPath)) {
463+
// Wait a tick for the editor to be available
464+
await new Promise((r) => setTimeout(r, 0))
465+
466+
// Find the editor for this document
467+
const editor = vscode.window.visibleTextEditors.find((e) =>
468+
arePathsEqual(e.document.uri.fsPath, uri.fsPath),
469+
)
470+
471+
if (editor) {
472+
cleanup()
473+
resolve(editor)
474+
}
475+
}
476+
}),
477+
)
444478

445-
vscode.commands.executeCommand(
446-
"vscode.diff",
447-
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${fileName}`).with({
448-
query: Buffer.from(this.originalContent ?? "").toString("base64"),
479+
// Also listen for visible editor changes as a fallback
480+
disposables.push(
481+
vscode.window.onDidChangeVisibleTextEditors((editors) => {
482+
const editor = editors.find((e) => arePathsEqual(e.document.uri.fsPath, uri.fsPath))
483+
if (editor) {
484+
cleanup()
485+
resolve(editor)
486+
}
449487
}),
450-
uri,
451-
`${fileName}: ${fileExists ? "Original ↔ Roo's Changes" : "New File"} (Editable)`,
452-
{ preserveFocus: true },
453488
)
454489

455-
// This may happen on very slow machines i.e. project idx.
456-
setTimeout(() => {
457-
disposable.dispose()
458-
reject(new Error("Failed to open diff editor, please try again..."))
459-
}, 10_000)
490+
// Execute the diff command
491+
vscode.commands
492+
.executeCommand(
493+
"vscode.diff",
494+
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${fileName}`).with({
495+
query: Buffer.from(this.originalContent ?? "").toString("base64"),
496+
}),
497+
uri,
498+
`${fileName}: ${fileExists ? "Original ↔ Roo's Changes" : "New File"} (Editable)`,
499+
{ preserveFocus: true },
500+
)
501+
.then(
502+
() => {
503+
// Command executed successfully, now wait for the editor to appear
504+
},
505+
(err: any) => {
506+
cleanup()
507+
reject(new Error(`Failed to execute diff command for ${uri.fsPath}: ${err.message}`))
508+
},
509+
)
460510
})
461511
}
462512

0 commit comments

Comments
 (0)