From b1a7b1ec1bd180e93061983d61e6224979725826 Mon Sep 17 00:00:00 2001 From: Sam van Vuuren Date: Wed, 3 Jun 2026 16:20:00 -0400 Subject: [PATCH] fix(navigation): wait for target pane before jumping to a cell on cold open (#996) Clicking a text-only cell in the export wizard's audio-stats popover is supposed to open the source+target editors at that cell's chapter/verse. When the book was not already open, it instead opened at chapter 1. openCodexDocumentWithSourcePair waited for the source pane's webview to be ready but not the target .codex pane. Callers publish the navigation jump (the `cellToJumpTo` workspace-state key) immediately after this helper returns; the per-editor jump listener is registered while the editor resolves, and waitForWebviewReady only returns once a pane has signalled ready. With the target pane not waited for, a cold-opened editor could miss the jump and fall back to its default page (chapter 1). When the book was already open (warm), both panes were ready, so it worked. Resolve the provider once and wait for BOTH panes (source and target) to be ready before returning, in the normal path, the source-failed fallback, and the no-workspace path. Cold-open now behaves like warm-open. Fixes #996 Co-Authored-By: Claude Opus 4.8 (1M context) --- src/utils/openCodexDocumentWithSourcePair.ts | 45 ++++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/utils/openCodexDocumentWithSourcePair.ts b/src/utils/openCodexDocumentWithSourcePair.ts index 10ad19355..3ee12e0ae 100644 --- a/src/utils/openCodexDocumentWithSourcePair.ts +++ b/src/utils/openCodexDocumentWithSourcePair.ts @@ -11,8 +11,36 @@ export async function openCodexDocumentWithSourcePair( ): Promise { const normalizedPath = codexUri.fsPath.replace(/\\/g, "/"); + // Resolve the editor provider once so we can wait for each pane's webview to + // become ready before returning. Callers frequently publish a navigation jump + // (e.g. the `cellToJumpTo` workspace-state key) immediately after this resolves. + // The provider registers that jump listener while resolving each editor, and + // `waitForWebviewReady` only returns once a pane has signalled ready (i.e. after + // it resolved + registered its listener). If we don't wait for the TARGET pane, + // a cold-opened editor can miss the jump and land on chapter 1 instead of the + // requested cell. See issue #996. + let provider: + | { waitForWebviewReady(uri: string, maxWaitMs?: number): Promise; } + | undefined; + try { + const { CodexCellEditorProvider } = await import( + "../providers/codexCellEditorProvider/codexCellEditorProvider" + ); + provider = CodexCellEditorProvider.getInstance() ?? undefined; + } catch { + provider = undefined; + } + const waitForPaneReady = async (uri: vscode.Uri) => { + if (provider) { + await provider.waitForWebviewReady(uri.toString(), 3000); + } else { + await new Promise((resolve) => setTimeout(resolve, 100)); + } + }; + if (!workspaceFolderUri) { await vscode.commands.executeCommand("vscode.openWith", codexUri, "codex.cellEditor"); + await waitForPaneReady(codexUri); return; } @@ -32,20 +60,7 @@ export async function openCodexDocumentWithSourcePair( "codex.cellEditor", { viewColumn: vscode.ViewColumn.One } ); - - try { - const { CodexCellEditorProvider } = await import( - "../providers/codexCellEditorProvider/codexCellEditorProvider" - ); - const provider = CodexCellEditorProvider.getInstance(); - if (provider) { - await provider.waitForWebviewReady(sourceUri.toString(), 3000); - } else { - await new Promise((resolve) => setTimeout(resolve, 100)); - } - } catch { - await new Promise((resolve) => setTimeout(resolve, 100)); - } + await waitForPaneReady(sourceUri); await vscode.commands.executeCommand( "vscode.openWith", @@ -53,6 +68,7 @@ export async function openCodexDocumentWithSourcePair( "codex.cellEditor", { viewColumn: vscode.ViewColumn.Two } ); + await waitForPaneReady(codexUri); } catch (sourceError) { console.warn("Could not open source file:", sourceError); await vscode.commands.executeCommand( @@ -61,5 +77,6 @@ export async function openCodexDocumentWithSourcePair( "codex.cellEditor", { viewColumn: vscode.ViewColumn.Two } ); + await waitForPaneReady(codexUri); } }