Skip to content

Commit 3d9d0ae

Browse files
committed
fix: resolve diff editor timeout issue when file is pre-opened
- Add immediate check for visible diff editor after command execution - Handles cases where document open events may not fire for pre-opened files - Fixes timeout error "Failed to open diff editor within 10 seconds" - Add test to verify the fix works correctly Fixes #6199
1 parent b140634 commit 3d9d0ae

File tree

2 files changed

+79
-7
lines changed

2 files changed

+79
-7
lines changed

src/integrations/editor/DiffViewProvider.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ export class DiffViewProvider {
187187
}
188188
}
189189

190-
async saveChanges(diagnosticsEnabled: boolean = true, writeDelayMs: number = DEFAULT_WRITE_DELAY_MS): Promise<{
190+
async saveChanges(
191+
diagnosticsEnabled: boolean = true,
192+
writeDelayMs: number = DEFAULT_WRITE_DELAY_MS,
193+
): Promise<{
191194
newProblemsMessage: string | undefined
192195
userEdits: string | undefined
193196
finalContent: string | undefined
@@ -222,22 +225,22 @@ export class DiffViewProvider {
222225
// and can address them accordingly. If problems don't change immediately after
223226
// applying a fix, won't be notified, which is generally fine since the
224227
// initial fix is usually correct and it may just take time for linters to catch up.
225-
228+
226229
let newProblemsMessage = ""
227-
230+
228231
if (diagnosticsEnabled) {
229232
// Add configurable delay to allow linters time to process and clean up issues
230233
// like unused imports (especially important for Go and other languages)
231234
// Ensure delay is non-negative
232235
const safeDelayMs = Math.max(0, writeDelayMs)
233-
236+
234237
try {
235238
await delay(safeDelayMs)
236239
} catch (error) {
237240
// Log error but continue - delay failure shouldn't break the save operation
238241
console.warn(`Failed to apply write delay: ${error}`)
239242
}
240-
243+
241244
const postDiagnostics = vscode.languages.getDiagnostics()
242245

243246
// Get diagnostic settings from state
@@ -551,8 +554,21 @@ export class DiffViewProvider {
551554
)
552555
})
553556
.then(
554-
() => {
555-
// Command executed successfully, now wait for the editor to appear
557+
async () => {
558+
// Command executed successfully, now check if the diff editor is already visible
559+
// This handles cases where the document was pre-opened and events might not fire
560+
await new Promise((r) => setTimeout(r, 100)) // Small delay to ensure UI updates
561+
562+
// Check if the diff editor is already visible
563+
const diffEditor = vscode.window.visibleTextEditors.find((e) =>
564+
arePathsEqual(e.document.uri.fsPath, uri.fsPath),
565+
)
566+
567+
if (diffEditor) {
568+
cleanup()
569+
resolve(diffEditor)
570+
}
571+
// If not found immediately, the event listeners will handle it
556572
},
557573
(err: any) => {
558574
cleanup()

src/integrations/editor/__tests__/DiffViewProvider.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,62 @@ describe("DiffViewProvider", () => {
267267
"Failed to execute diff command for /mock/cwd/test.md: Cannot open file",
268268
)
269269
})
270+
271+
it("should resolve immediately if diff editor is already visible after command", async () => {
272+
// Setup
273+
const mockEditor = {
274+
document: {
275+
uri: { fsPath: `${mockCwd}/test.md` },
276+
getText: vi.fn().mockReturnValue(""),
277+
lineCount: 0,
278+
},
279+
selection: {
280+
active: { line: 0, character: 0 },
281+
anchor: { line: 0, character: 0 },
282+
},
283+
edit: vi.fn().mockResolvedValue(true),
284+
revealRange: vi.fn(),
285+
}
286+
287+
// Mock showTextDocument
288+
vi.mocked(vscode.window.showTextDocument).mockResolvedValue(mockEditor as any)
289+
290+
// Mock executeCommand to succeed
291+
vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined)
292+
293+
// Mock workspace.onDidOpenTextDocument - don't trigger callback
294+
vi.mocked(vscode.workspace.onDidOpenTextDocument).mockReturnValue({ dispose: vi.fn() })
295+
296+
// Mock window.onDidChangeVisibleTextEditors - don't trigger callback
297+
vi.mocked(vscode.window.onDidChangeVisibleTextEditors).mockReturnValue({ dispose: vi.fn() })
298+
299+
// Mock window.visibleTextEditors to return our editor immediately after command
300+
vi.mocked(vscode.window).visibleTextEditors = [mockEditor as any]
301+
302+
// Set up for file
303+
;(diffViewProvider as any).editType = "modify"
304+
305+
// Execute open - should complete successfully
306+
await diffViewProvider.open("test.md")
307+
308+
// Verify that showTextDocument was called
309+
expect(vscode.window.showTextDocument).toHaveBeenCalledWith(
310+
expect.objectContaining({ fsPath: `${mockCwd}/test.md` }),
311+
{ preview: false, viewColumn: vscode.ViewColumn.Active, preserveFocus: true },
312+
)
313+
314+
// Verify that the diff command was executed
315+
expect(vscode.commands.executeCommand).toHaveBeenCalledWith(
316+
"vscode.diff",
317+
expect.any(Object),
318+
expect.any(Object),
319+
`test.md: ${DIFF_VIEW_LABEL_CHANGES} (Editable)`,
320+
{ preserveFocus: true },
321+
)
322+
323+
// Verify that the activeDiffEditor was set
324+
expect((diffViewProvider as any).activeDiffEditor).toBe(mockEditor)
325+
})
270326
})
271327

272328
describe("closeAllDiffViews method", () => {

0 commit comments

Comments
 (0)