Path: blob/main/src/vs/sessions/contrib/changes/browser/changesMultiDiffSourceResolver.ts
13401 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 { Disposable } from '../../../../base/common/lifecycle.js';6import { derivedObservableWithCache, derivedOpts, ValueWithChangeEventFromObservable } from '../../../../base/common/observable.js';7import { equals as arraysEqual } from '../../../../base/common/arrays.js';8import { isEqual } from '../../../../base/common/resources.js';9import { URI } from '../../../../base/common/uri.js';10import { comparePaths } from '../../../../base/common/comparers.js';11import { isIChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';12import { IMultiDiffSourceResolver, IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MultiDiffEditorItem } from '../../../../workbench/contrib/multiDiffEditor/browser/multiDiffSourceResolverService.js';13import { ISessionFileChange } from '../../../services/sessions/common/session.js';14import { ChangesViewModel } from './changesViewModel.js';1516const CHANGES_MULTI_DIFF_SOURCE_SCHEME = 'changes-multi-diff-source';1718interface ChangesMultiDiffUriFields {19readonly sessionResource: string;20}2122/**23* Build the multi-diff source URI for a session. The URI is used to identify24* the multi-diff editor so subsequent opens with the same session reuse the25* same input while the resource list updates reactively.26*/27export function getChangesMultiDiffSourceUri(sessionResource: URI): URI {28return URI.from({29scheme: CHANGES_MULTI_DIFF_SOURCE_SCHEME,30query: JSON.stringify({ sessionResource: sessionResource.toString() } satisfies ChangesMultiDiffUriFields),31});32}3334function parseUri(uri: URI): { sessionResource: URI } | undefined {35if (uri.scheme !== CHANGES_MULTI_DIFF_SOURCE_SCHEME) {36return undefined;37}3839let query: ChangesMultiDiffUriFields;40try {41query = JSON.parse(uri.query) as ChangesMultiDiffUriFields;42} catch {43return undefined;44}4546if (typeof query !== 'object' || query === null || typeof query.sessionResource !== 'string') {47return undefined;48}4950return { sessionResource: URI.parse(query.sessionResource) };51}5253function compareChanges(a: ISessionFileChange, b: ISessionFileChange): number {54const aPath = isIChatSessionFileChange2(a) ? a.uri.fsPath : a.modifiedUri.fsPath;55const bPath = isIChatSessionFileChange2(b) ? b.uri.fsPath : b.modifiedUri.fsPath;56return comparePaths(aPath, bPath);57}5859export class ChangesMultiDiffSourceResolver extends Disposable implements IMultiDiffSourceResolver {6061constructor(62private readonly _viewModel: ChangesViewModel,63@IMultiDiffSourceResolverService multiDiffSourceResolverService: IMultiDiffSourceResolverService64) {65super();66this._register(multiDiffSourceResolverService.registerResolver(this));67}6869canHandleUri(uri: URI): boolean {70return parseUri(uri) !== undefined;71}7273async resolveDiffSource(uri: URI): Promise<IResolvedMultiDiffSource> {74const parsed = parseUri(uri)!;7576const changesObs = derivedObservableWithCache<readonly ISessionFileChange[]>({77owner: this,78}, (reader, lastValue) => {79if (this._viewModel.activeSessionIsLoadingObs.read(reader)) {80return lastValue ?? [];81}8283const activeSessionResource = this._viewModel.activeSessionResourceObs.read(reader);84if (!activeSessionResource || !isEqual(activeSessionResource, parsed.sessionResource)) {85return lastValue ?? [];86}8788return this._viewModel.activeSessionChangesObs.read(reader);89});9091const resourcesObs = derivedOpts<readonly MultiDiffEditorItem[]>({92owner: this,93equalsFn: (a, b) => arraysEqual(a, b, (x, y) =>94isEqual(x.originalUri, y.originalUri) &&95isEqual(x.modifiedUri, y.modifiedUri)),96}, reader => {97const changes = changesObs.read(reader);98return [...changes].sort(compareChanges).map(change =>99new MultiDiffEditorItem(change.originalUri, change.modifiedUri, change.modifiedUri));100});101102return { resources: new ValueWithChangeEventFromObservable(resourcesObs) };103}104}105106107