diff --git a/src/diffViewController.ts b/src/diffViewController.ts index 11285fb..1d61fb7 100644 --- a/src/diffViewController.ts +++ b/src/diffViewController.ts @@ -143,9 +143,77 @@ export class DiffViewController implements vscode.Disposable { return this.store?.baselinePath(docPath); } - // Replaced by the real implementation in Task 4 (toggle UX, SLICE-3). - private toggle(_editor: vscode.TextEditor | undefined): void { - /* stub */ + // ---- toggle UX (§6.5 PUC-1) -------------------------------------------------------- + + /** + * If this doc's baseline diff is the active/open tab → close it and reveal the + * normal editor; if the active editor is a tracked doc with no diff open → + * open vscode.diff (baseline left, the live document right). Untracked → warn, + * no diff. + */ + private async toggle(editor: vscode.TextEditor | undefined): Promise { + if (!editor || !this.isTracked(editor.document)) { + void vscode.window.showWarningMessage( + "Cowriting: open a tracked workspace document to toggle its diff view.", + ); + return; + } + const document = editor.document; + const docPath = this.docPathOf(document.uri); + const openTab = this.findDiffTab(document.uri); + if (openTab) { + await vscode.window.tabGroups.close(openTab); + await vscode.window.showTextDocument(document, { preview: false }); + return; + } + this.ensureBaseline(document); + const baseline = this.baselines.get(docPath)!; + const title = `${path.basename(docPath)} — my changes since ${this.epochLabel(baseline)}`; + await vscode.commands.executeCommand( + "vscode.diff", + this.baselineUri(docPath), + document.uri, + title, + { preview: false }, + ); + } + + /** The open baseline-diff tab for this document, if any. */ + private findDiffTab(modified: vscode.Uri): vscode.Tab | undefined { + for (const group of vscode.window.tabGroups.all) { + for (const tab of group.tabs) { + const input = tab.input; + if ( + input instanceof vscode.TabInputTextDiff && + input.original.scheme === BASELINE_SCHEME && + input.modified.toString() === modified.toString() + ) { + return tab; + } + } + } + return undefined; + } + + /** Human-readable epoch for the diff tab title (§5 / §6.5). */ + private epochLabel(baseline: Baseline): string { + const time = new Date(baseline.capturedAt).toLocaleTimeString(); + switch (baseline.reason) { + case "opened": + return `opened ${time}`; + case "machine-landing": + return `Claude landed ${time}`; + case "pinned": + return `pinned ${time}`; + } + } + + /** + * Test-facing (§6.4): is this doc's baseline diff currently open in any tab + * group? The diff's `modified` side is the document's own file: URI. + */ + isDiffOpen(docPath: string): boolean { + return this.findDiffTab(vscode.Uri.file(path.join(this.rootDir, docPath))) !== undefined; } dispose(): void {