This commit is contained in:
Deleted user 2026-05-27 10:52:52 +08:00 committed by GitHub
commit e802a82afa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 224 additions and 1 deletions

View file

@ -28,6 +28,7 @@ export class DiffViewProvider {
originalContent: string | undefined
private createdDirs: string[] = []
private documentWasOpen = false
private documentWasPinned = false
private relPath?: string
private newContent?: string
private activeDiffEditor?: vscode.TextEditor
@ -84,6 +85,7 @@ export class DiffViewProvider {
// If the file was already open, close it (must happen after showing the
// diff view since if it's the only tab the column will close).
this.documentWasOpen = false
this.documentWasPinned = false
// Close the tab if it's open (it's already saved above).
const tabs = vscode.window.tabGroups.all
@ -97,6 +99,9 @@ export class DiffViewProvider {
)
for (const tab of tabs) {
if (tab.isPinned) {
this.documentWasPinned = true
}
if (!tab.isDirty) {
try {
await vscode.window.tabGroups.close(tab)
@ -214,6 +219,12 @@ export class DiffViewProvider {
}
await vscode.window.showTextDocument(vscode.Uri.file(absolutePath), { preview: false, preserveFocus: true })
// Restore pinned state if the tab was pinned before editing.
if (this.documentWasPinned) {
await vscode.commands.executeCommand("workbench.action.pinEditor")
}
await this.closeAllDiffViews()
// Getting diagnostics before and after the file edit is a better approach than
@ -405,6 +416,11 @@ export class DiffViewProvider {
preview: false,
preserveFocus: true,
})
// Restore pinned state if the tab was pinned before editing.
if (this.documentWasPinned) {
await vscode.commands.executeCommand("workbench.action.pinEditor")
}
}
await this.closeAllDiffViews()
@ -623,6 +639,7 @@ export class DiffViewProvider {
this.originalContent = undefined
this.createdDirs = []
this.documentWasOpen = false
this.documentWasPinned = false
this.activeDiffEditor = undefined
this.fadedOverlayController = undefined
this.activeLineController = undefined

View file

@ -50,7 +50,7 @@ vi.mock("vscode", () => ({
visibleTextEditors: [],
},
commands: {
executeCommand: vi.fn(),
executeCommand: vi.fn().mockResolvedValue(undefined),
},
languages: {
getDiagnostics: vi.fn(() => []),
@ -84,6 +84,7 @@ vi.mock("vscode", () => ({
TextEditorRevealType: {
InCenter: 2,
},
TabInputText: class TabInputText {},
TabInputTextDiff: class TabInputTextDiff {},
Uri: {
file: vi.fn((path) => ({ fsPath: path })),
@ -517,4 +518,209 @@ describe("DiffViewProvider", () => {
expect(vscode.languages.getDiagnostics).toHaveBeenCalled()
})
})
describe("pinned tab preservation", () => {
describe("open method - pin state capture", () => {
it("should capture pinned state when closing a pinned tab", async () => {
const absolutePath = `${mockCwd}/test.txt`
// Setup a pinned tab
const pinnedTab = {
input: { uri: { scheme: "file", fsPath: absolutePath } },
isDirty: false,
isPinned: true,
}
// Make the tab look like a TabInputText instance
Object.setPrototypeOf(pinnedTab.input, vscode.TabInputText?.prototype ?? {})
Object.defineProperty(vscode.window.tabGroups, "all", {
get: () => [{ tabs: [pinnedTab] }],
configurable: true,
})
vi.mocked(vscode.window.tabGroups.close).mockResolvedValue(true as any)
// Mock for openDiffEditor
const mockEditor = {
document: {
uri: { fsPath: absolutePath, scheme: "file" },
getText: vi.fn().mockReturnValue(""),
lineCount: 0,
},
selection: { active: { line: 0, character: 0 }, anchor: { line: 0, character: 0 } },
edit: vi.fn().mockResolvedValue(true),
revealRange: vi.fn(),
}
vi.mocked(vscode.window.showTextDocument).mockResolvedValue(mockEditor as any)
vi.mocked(vscode.workspace.onDidOpenTextDocument).mockImplementation((callback) => {
setTimeout(() => {
callback({ uri: { fsPath: absolutePath, scheme: "file" } } as any)
}, 0)
return { dispose: vi.fn() }
})
vi.mocked(vscode.window).visibleTextEditors = [mockEditor as any]
;(diffViewProvider as any).editType = "modify"
await diffViewProvider.open("test.txt")
expect((diffViewProvider as any).documentWasPinned).toBe(true)
expect((diffViewProvider as any).documentWasOpen).toBe(true)
})
it("should not set pinned state when closing an unpinned tab", async () => {
const absolutePath = `${mockCwd}/test.txt`
const unpinnedTab = {
input: { uri: { scheme: "file", fsPath: absolutePath } },
isDirty: false,
isPinned: false,
}
Object.setPrototypeOf(unpinnedTab.input, vscode.TabInputText?.prototype ?? {})
Object.defineProperty(vscode.window.tabGroups, "all", {
get: () => [{ tabs: [unpinnedTab] }],
configurable: true,
})
vi.mocked(vscode.window.tabGroups.close).mockResolvedValue(true as any)
const mockEditor = {
document: {
uri: { fsPath: absolutePath, scheme: "file" },
getText: vi.fn().mockReturnValue(""),
lineCount: 0,
},
selection: { active: { line: 0, character: 0 }, anchor: { line: 0, character: 0 } },
edit: vi.fn().mockResolvedValue(true),
revealRange: vi.fn(),
}
vi.mocked(vscode.window.showTextDocument).mockResolvedValue(mockEditor as any)
vi.mocked(vscode.workspace.onDidOpenTextDocument).mockImplementation((callback) => {
setTimeout(() => {
callback({ uri: { fsPath: absolutePath, scheme: "file" } } as any)
}, 0)
return { dispose: vi.fn() }
})
vi.mocked(vscode.window).visibleTextEditors = [mockEditor as any]
;(diffViewProvider as any).editType = "modify"
await diffViewProvider.open("test.txt")
expect((diffViewProvider as any).documentWasPinned).toBe(false)
expect((diffViewProvider as any).documentWasOpen).toBe(true)
})
})
describe("saveChanges - pin state restoration", () => {
beforeEach(() => {
;(diffViewProvider as any).relPath = "test.ts"
;(diffViewProvider as any).newContent = "new content"
;(diffViewProvider as any).activeDiffEditor = {
document: {
getText: vi.fn().mockReturnValue("new content"),
isDirty: false,
save: vi.fn().mockResolvedValue(undefined),
},
}
;(diffViewProvider as any).preDiagnostics = []
;(diffViewProvider as any).closeAllDiffViews = vi.fn().mockResolvedValue(undefined)
vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any)
vi.mocked(vscode.languages.getDiagnostics).mockReturnValue([])
vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined)
})
it("should pin the editor after saving when documentWasPinned is true", async () => {
;(diffViewProvider as any).documentWasPinned = true
await diffViewProvider.saveChanges(false)
expect(vscode.commands.executeCommand).toHaveBeenCalledWith("workbench.action.pinEditor")
})
it("should not pin the editor after saving when documentWasPinned is false", async () => {
;(diffViewProvider as any).documentWasPinned = false
await diffViewProvider.saveChanges(false)
expect(vscode.commands.executeCommand).not.toHaveBeenCalledWith("workbench.action.pinEditor")
})
})
describe("revertChanges - pin state restoration", () => {
beforeEach(() => {
;(diffViewProvider as any).relPath = "test.ts"
;(diffViewProvider as any).newContent = "new content"
;(diffViewProvider as any).originalContent = "original content"
;(diffViewProvider as any).editType = "modify"
;(diffViewProvider as any).activeDiffEditor = {
document: {
uri: { fsPath: `${mockCwd}/test.ts` },
getText: vi.fn().mockReturnValue("new content"),
positionAt: vi.fn().mockReturnValue({ line: 0, character: 0 }),
isDirty: false,
save: vi.fn().mockResolvedValue(undefined),
},
}
vi.mocked(vscode.workspace.applyEdit).mockResolvedValue(true)
vi.mocked(vscode.window.showTextDocument).mockResolvedValue({} as any)
vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined)
// Mock closeAllDiffViews
;(diffViewProvider as any).closeAllDiffViews = vi.fn().mockResolvedValue(undefined)
})
it("should pin the editor after reverting when documentWasPinned is true", async () => {
;(diffViewProvider as any).documentWasOpen = true
;(diffViewProvider as any).documentWasPinned = true
await diffViewProvider.revertChanges()
expect(vscode.commands.executeCommand).toHaveBeenCalledWith("workbench.action.pinEditor")
})
it("should not pin the editor after reverting when documentWasPinned is false", async () => {
;(diffViewProvider as any).documentWasOpen = true
;(diffViewProvider as any).documentWasPinned = false
await diffViewProvider.revertChanges()
expect(vscode.commands.executeCommand).not.toHaveBeenCalledWith("workbench.action.pinEditor")
})
it("should not pin the editor when document was not open", async () => {
;(diffViewProvider as any).documentWasOpen = false
;(diffViewProvider as any).documentWasPinned = true
await diffViewProvider.revertChanges()
expect(vscode.commands.executeCommand).not.toHaveBeenCalledWith("workbench.action.pinEditor")
})
})
describe("reset - pin state cleanup", () => {
it("should reset documentWasPinned to false", async () => {
;(diffViewProvider as any).documentWasPinned = true
// Mock tabGroups.all to return empty for closeAllDiffViews
Object.defineProperty(vscode.window.tabGroups, "all", {
get: () => [],
configurable: true,
})
await (diffViewProvider as any).reset()
expect((diffViewProvider as any).documentWasPinned).toBe(false)
})
})
})
})