diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index fb3907c3f4..0a5e5a6f14 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -473,7 +473,7 @@ export class DiffViewProvider { .map((tab) => vscode.window.tabGroups.close(tab).then( () => undefined, - (err) => { + (err: any) => { console.error(`Failed to close diff tab ${tab.label}`, err) }, ), diff --git a/src/integrations/editor/PostEditBehaviorUtils.ts b/src/integrations/editor/PostEditBehaviorUtils.ts index 50f4549e74..b1ab25d49c 100644 --- a/src/integrations/editor/PostEditBehaviorUtils.ts +++ b/src/integrations/editor/PostEditBehaviorUtils.ts @@ -77,8 +77,18 @@ export class PostEditBehaviorUtils { if (tab.input instanceof vscode.TabInputText) { const tabPath = tab.input.uri.fsPath - // Skip the currently edited file to avoid closing it immediately - if (editedFilePath && arePathsEqual(tabPath, editedFilePath)) { + // If only autoCloseRooTabs is enabled (not autoCloseAllRooTabs), + // only close the edited file tab + if (autoCloseRooTabs && !autoCloseAllRooTabs) { + // Only close if this is the edited file AND it was opened by Roo + if (editedFilePath && arePathsEqual(tabPath, editedFilePath)) { + // Check if this file was opened by Roo + for (const trackedPath of rooOpenedTabs) { + if (arePathsEqual(tabPath, trackedPath)) { + return true + } + } + } return false } @@ -91,16 +101,6 @@ export class PostEditBehaviorUtils { } } } - - // If only autoCloseRooTabs is enabled, close tabs that Roo opened (not pre-existing) - if (autoCloseRooTabs && !autoCloseAllRooTabs) { - // This requires the tab to be in our tracked set - for (const trackedPath of rooOpenedTabs) { - if (arePathsEqual(tabPath, trackedPath)) { - return true - } - } - } } return false @@ -115,32 +115,32 @@ export class PostEditBehaviorUtils { preEditActiveEditor: vscode.TextEditor | undefined, editedFilePath?: string, ): Promise { - // Try to restore focus to the pre-edit active editor if it still exists - if (preEditActiveEditor) { - const stillExists = vscode.window.visibleTextEditors.some( - (editor) => editor.document.uri.toString() === preEditActiveEditor.document.uri.toString(), - ) + try { + // Try to restore focus to the pre-edit active editor if it still exists + if (preEditActiveEditor) { + const stillExists = vscode.window.visibleTextEditors.some( + (editor) => editor.document.uri.toString() === preEditActiveEditor.document.uri.toString(), + ) - if (stillExists) { - await vscode.window.showTextDocument(preEditActiveEditor.document, { - preserveFocus: false, - preview: false, - }) - return + if (stillExists) { + await vscode.window.showTextDocument(preEditActiveEditor.document, { + preserveFocus: false, + preview: false, + }) + return + } } - } - // Otherwise, try to focus on the edited file - if (editedFilePath) { - try { + // Otherwise, try to focus on the edited file + if (editedFilePath) { await vscode.window.showTextDocument(vscode.Uri.file(editedFilePath), { preserveFocus: false, preview: false, }) - } catch (err) { - // File might not exist or be accessible - console.debug(`Could not restore focus to edited file: ${err}`) } + } catch (err) { + // File might not exist or be accessible + console.debug(`Could not restore focus: ${err}`) } } } diff --git a/src/integrations/editor/__tests__/PostEditBehaviorUtils.spec.ts b/src/integrations/editor/__tests__/PostEditBehaviorUtils.spec.ts index f1f2649409..cbe50b3c6e 100644 --- a/src/integrations/editor/__tests__/PostEditBehaviorUtils.spec.ts +++ b/src/integrations/editor/__tests__/PostEditBehaviorUtils.spec.ts @@ -9,6 +9,7 @@ vi.mock("vscode", () => ({ window: { tabGroups: { all: [], + close: vi.fn(), }, showTextDocument: vi.fn(), createTextEditorDecorationType: vi.fn(() => ({ @@ -51,6 +52,7 @@ describe("PostEditBehaviorUtils", () => { // Reset mocks vi.mocked(vscode.window).tabGroups = { all: mockTabGroups, + close: vi.fn().mockResolvedValue(true), } as any vi.mocked(vscode.window).showTextDocument = mockShowTextDocument vi.mocked(vscode.window).visibleTextEditors = mockVisibleTextEditors @@ -68,11 +70,11 @@ describe("PostEditBehaviorUtils", () => { tabs: [ { input: { uri: { fsPath: "/path/to/file1.ts" } }, - close: vi.fn(), + isDirty: false, }, { input: { uri: { fsPath: "/path/to/file2.ts" } }, - close: vi.fn(), + isDirty: false, }, ], } @@ -87,8 +89,7 @@ describe("PostEditBehaviorUtils", () => { ) // Assert - expect(mockTabGroup.tabs[0].close).not.toHaveBeenCalled() - expect(mockTabGroup.tabs[1].close).not.toHaveBeenCalled() + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalled() }) it("should close only the edited file tab when autoCloseRooTabs is true and autoCloseAllRooTabs is false", async () => { @@ -99,11 +100,11 @@ describe("PostEditBehaviorUtils", () => { tabs: [ { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file1.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file2.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, ], } @@ -118,8 +119,8 @@ describe("PostEditBehaviorUtils", () => { ) // Assert - expect(mockTabGroup.tabs[0].close).toHaveBeenCalled() - expect(mockTabGroup.tabs[1].close).not.toHaveBeenCalled() + expect(vi.mocked(vscode.window).tabGroups.close).toHaveBeenCalledWith(mockTabGroup.tabs[0]) + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalledWith(mockTabGroup.tabs[1]) }) it("should close all Roo-opened tabs when autoCloseAllRooTabs is true", async () => { @@ -130,15 +131,15 @@ describe("PostEditBehaviorUtils", () => { tabs: [ { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file1.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file2.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file3.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, ], } @@ -153,9 +154,9 @@ describe("PostEditBehaviorUtils", () => { ) // Assert - expect(mockTabGroup.tabs[0].close).toHaveBeenCalled() - expect(mockTabGroup.tabs[1].close).toHaveBeenCalled() - expect(mockTabGroup.tabs[2].close).not.toHaveBeenCalled() // file3 was not opened by Roo + expect(vi.mocked(vscode.window).tabGroups.close).toHaveBeenCalledWith(mockTabGroup.tabs[0]) + expect(vi.mocked(vscode.window).tabGroups.close).toHaveBeenCalledWith(mockTabGroup.tabs[1]) + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalledWith(mockTabGroup.tabs[2]) // file3 was not opened by Roo }) it("should not close tabs that were not opened by Roo", async () => { @@ -166,11 +167,11 @@ describe("PostEditBehaviorUtils", () => { tabs: [ { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file1.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file2.ts")), // Not in rooOpenedTabs - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, ], } @@ -185,8 +186,8 @@ describe("PostEditBehaviorUtils", () => { ) // Assert - expect(mockTabGroup.tabs[0].close).toHaveBeenCalled() - expect(mockTabGroup.tabs[1].close).not.toHaveBeenCalled() + expect(vi.mocked(vscode.window).tabGroups.close).toHaveBeenCalledWith(mockTabGroup.tabs[0]) + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalledWith(mockTabGroup.tabs[1]) }) it("should handle tabs without URI input gracefully", async () => { @@ -196,15 +197,15 @@ describe("PostEditBehaviorUtils", () => { tabs: [ { input: new (vi.mocked(vscode).TabInputText)(vscode.Uri.file("/path/to/file1.ts")), - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: {}, // No URI - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, { input: null, // Null input - close: vi.fn().mockResolvedValue(true), + isDirty: false, }, ], } @@ -219,9 +220,9 @@ describe("PostEditBehaviorUtils", () => { ) // Assert - expect(mockTabGroup.tabs[0].close).toHaveBeenCalled() - expect(mockTabGroup.tabs[1].close).not.toHaveBeenCalled() - expect(mockTabGroup.tabs[2].close).not.toHaveBeenCalled() + expect(vi.mocked(vscode.window).tabGroups.close).toHaveBeenCalledWith(mockTabGroup.tabs[0]) + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalledWith(mockTabGroup.tabs[1]) + expect(vi.mocked(vscode.window).tabGroups.close).not.toHaveBeenCalledWith(mockTabGroup.tabs[2]) }) })