Update edit session view to show decoded working changes

Previously edit sessions only accounted for text files, so a `TextModelContentProvider` was sufficient, but now we need to register a file system provider because image data is handled by extensions and we don't own the model for that
This commit is contained in:
Joyce Er 2022-08-08 16:18:34 -07:00
parent cd477d6fa1
commit 950d2106ad
No known key found for this signature in database
GPG key ID: A15311FAE9EC8CD6
3 changed files with 66 additions and 37 deletions

View file

@ -10,7 +10,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { localize } from 'vs/nls';
import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions';
import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions';
import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm';
import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
@ -45,7 +45,7 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { EditSessionsContentProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsContentProvider';
import { EditSessionsFileSystemProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsFileSystemProvider';
import { isNative } from 'vs/base/common/platform';
import { WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys';
@ -148,7 +148,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService);
textModelResolverService.registerTextModelContentProvider(EDIT_SESSIONS_SCHEME, instantiationService.createInstance(EditSessionsContentProvider));
this._register(this.fileService.registerProvider(EditSessionsFileSystemProvider.SCHEMA, new EditSessionsFileSystemProvider(this.editSessionsWorkbenchService)));
}
private registerViews() {

View file

@ -1,34 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/model';
import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
import { EDIT_SESSIONS_SCHEME, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions';
export class EditSessionsContentProvider implements ITextModelContentProvider {
constructor(
@IEditSessionsWorkbenchService private editSessionsWorkbenchService: IEditSessionsWorkbenchService,
@IModelService private readonly modelService: IModelService,
) { }
async provideTextContent(uri: URI): Promise<ITextModel | null> {
let model: ITextModel | null = null;
if (uri.scheme === EDIT_SESSIONS_SCHEME) {
const match = /(?<ref>[^/]+)\/(?<folderName>[^/]+)\/(?<filePath>.*)/.exec(uri.path.substring(1));
if (match?.groups) {
const { ref, folderName, filePath } = match.groups;
const data = await this.editSessionsWorkbenchService.read(ref);
const content = data?.editSession.folders.find((f) => f.name === folderName)?.workingChanges.find((change) => change.relativeFilePath === filePath)?.contents;
if (content) {
model = this.modelService.createModel(content, null, uri);
}
}
}
return model;
}
}

View file

@ -0,0 +1,63 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { FilePermission, FileSystemProviderCapabilities, FileSystemProviderErrorCode, FileType, IFileDeleteOptions, IFileOverwriteOptions, IFileSystemProviderWithFileReadCapability, IStat, IWatchOptions } from 'vs/platform/files/common/files';
import { decodeEditSessionFileContent, EDIT_SESSIONS_SCHEME, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions';
export class EditSessionsFileSystemProvider implements IFileSystemProviderWithFileReadCapability {
static readonly SCHEMA = EDIT_SESSIONS_SCHEME;
constructor(
@IEditSessionsWorkbenchService private editSessionsWorkbenchService: IEditSessionsWorkbenchService,
) { }
readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly;
async readFile(resource: URI): Promise<Uint8Array> {
const match = /(?<ref>[^/]+)\/(?<folderName>[^/]+)\/(?<filePath>.*)/.exec(resource.path.substring(1));
if (!match?.groups) {
throw FileSystemProviderErrorCode.FileNotFound;
}
const { ref, folderName, filePath } = match.groups;
const data = await this.editSessionsWorkbenchService.read(ref);
if (!data) {
throw FileSystemProviderErrorCode.FileNotFound;
}
const content = data?.editSession.folders.find((f) => f.name === folderName)?.workingChanges.find((change) => change.relativeFilePath === filePath)?.contents;
if (!content) {
throw FileSystemProviderErrorCode.FileNotFound;
}
return decodeEditSessionFileContent(data.editSession.version, content).buffer;
}
async stat(resource: URI): Promise<IStat> {
const content = await this.readFile(resource);
const currentTime = Date.now();
return {
type: FileType.File,
permissions: FilePermission.Readonly,
mtime: currentTime,
ctime: currentTime,
size: content.byteLength
};
}
//#region Unsupported file operations
readonly onDidChangeCapabilities = Event.None;
readonly onDidChangeFile = Event.None;
watch(resource: URI, opts: IWatchOptions): IDisposable { return Disposable.None; }
async mkdir(resource: URI): Promise<void> { }
async readdir(resource: URI): Promise<[string, FileType][]> { return []; }
async rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void> { }
async delete(resource: URI, opts: IFileDeleteOptions): Promise<void> { }
//#endregion
}