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