Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/diffState.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { ILogger } from '../../../../platform/log/common/logService';
8
9
export interface ActiveDiff {
10
diffId: string;
11
sessionId?: string;
12
tabName: string;
13
originalUri: vscode.Uri;
14
modifiedUri: vscode.Uri;
15
newContents: string;
16
cleanup: () => void;
17
resolve: (result: { status: 'SAVED' | 'REJECTED'; trigger: string }) => void;
18
}
19
20
function isDiffTab(tab: vscode.Tab): tab is vscode.Tab & { input: vscode.TabInputTextDiff } {
21
return tab.input instanceof vscode.TabInputTextDiff;
22
}
23
24
export class DiffStateManager {
25
private readonly _activeDiffs = new Map<string, ActiveDiff>();
26
27
constructor(private readonly _logger: ILogger) { }
28
29
register(diff: ActiveDiff): void {
30
this._logger.trace(`[DIFF] registerActiveDiff: tabName=${diff.tabName}, diffId=${diff.diffId}, mapSize=${this._activeDiffs.size}`);
31
this._activeDiffs.set(diff.diffId, diff);
32
this._logger.trace(`[DIFF] After register, mapSize=${this._activeDiffs.size}`);
33
this._updateContext();
34
}
35
36
unregister(diffId: string): void {
37
const diff = this._activeDiffs.get(diffId);
38
this._logger.trace(`[DIFF] unregisterActiveDiff: diffId=${diffId}, found=${!!diff}, mapSize=${this._activeDiffs.size}`);
39
this._activeDiffs.delete(diffId);
40
this._logger.trace(`[DIFF] After unregister, mapSize=${this._activeDiffs.size}`);
41
this._updateContext();
42
}
43
44
getByTabName(tabName: string): ActiveDiff | undefined {
45
for (const diff of this._activeDiffs.values()) {
46
if (diff.tabName === tabName) {
47
return diff;
48
}
49
}
50
return undefined;
51
}
52
53
getByTab(tab: vscode.Tab): ActiveDiff | undefined {
54
if (!isDiffTab(tab)) {
55
this._logger.trace('[DIFF] getActiveDiffByTab: tab is not a diff tab');
56
return undefined;
57
}
58
const modifiedUri = tab.input.modified.toString();
59
this._logger.trace(`[DIFF] getActiveDiffByTab: looking for modifiedUri=${modifiedUri}, mapSize=${this._activeDiffs.size}`);
60
for (const diff of this._activeDiffs.values()) {
61
this._logger.trace(`[DIFF] checking diff.modifiedUri=${diff.modifiedUri.toString()}`);
62
if (diff.modifiedUri.toString() === modifiedUri) {
63
this._logger.trace('[DIFF] MATCH found');
64
return diff;
65
}
66
}
67
this._logger.trace('[DIFF] No match found');
68
return undefined;
69
}
70
71
getForCurrentTab(): ActiveDiff | undefined {
72
const activeTab = vscode.window.tabGroups.activeTabGroup.activeTab;
73
this._logger.trace(`[DIFF] getActiveDiffForCurrentTab: activeTab=${activeTab?.label ?? 'none'}`);
74
if (activeTab) {
75
return this.getByTab(activeTab);
76
}
77
return undefined;
78
}
79
80
hasActiveDiffs(): boolean {
81
return this._activeDiffs.size > 0;
82
}
83
84
closeAllForSession(sessionId: string): void {
85
const toClose: ActiveDiff[] = [];
86
for (const diff of this._activeDiffs.values()) {
87
if (diff.sessionId === sessionId) {
88
toClose.push(diff);
89
}
90
}
91
this._logger.info(`[DIFF] Closing ${toClose.length} diff(s) for disconnected session ${sessionId}`);
92
for (const diff of toClose) {
93
diff.resolve({ status: 'REJECTED', trigger: 'client_disconnected' });
94
}
95
}
96
97
setupContextTracking(): vscode.Disposable[] {
98
const disposables: vscode.Disposable[] = [];
99
disposables.push(
100
vscode.window.tabGroups.onDidChangeTabGroups(() => {
101
this._updateContext();
102
})
103
);
104
disposables.push(
105
vscode.window.tabGroups.onDidChangeTabs(() => {
106
this._updateContext();
107
})
108
);
109
return disposables;
110
}
111
112
private _updateContext(): void {
113
const activeTab = vscode.window.tabGroups.activeTabGroup.activeTab;
114
const isActiveDiff = activeTab ? this.getByTab(activeTab) !== undefined : false;
115
void vscode.commands.executeCommand('setContext', 'github.copilot.chat.copilotCLI.hasActiveDiff', isActiveDiff).then(undefined, err => {
116
this._logger.error(`[DIFF] Failed to update hasActiveDiff context: ${String(err)}`);
117
});
118
}
119
}
120
121