From 22523dd6bca65ad1f95cbb2f7bf9178bb414ccde Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 19 Apr 2023 15:11:19 -0700 Subject: [PATCH] Go through storage service for edit session payload --- src/vs/platform/storage/common/storage.ts | 29 +++++++++++- src/vs/workbench/common/memento.ts | 3 ++ .../browser/editSessions.contribution.ts | 46 +++++++++++-------- .../editSessions/common/editSessions.ts | 2 +- .../contrib/scm/common/scmService.ts | 29 +++++++++++- 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index 89f781b00b154..a81a5eea3b835 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -183,7 +183,14 @@ export const enum StorageScope { /** * The stored data will be scoped to the current workspace. */ - WORKSPACE = 1 + WORKSPACE = 1, + + /** + * The stored data will be scoped to workspaces which share the same edit session identity. + * Note, this is actually represented by {@link StorageScope.WORKSPACE} and {@link StorageTarget.USER}, + * but there are already adoptions of that pairing which need to be migrated. + */ + ROAMABLE_WORKSPACE = 2, } export const enum StorageTarget { @@ -334,6 +341,9 @@ export abstract class AbstractStorageService extends Disposable implements IStor case StorageScope.PROFILE: this._profileKeyTargets = undefined; break; + case StorageScope.ROAMABLE_WORKSPACE: + this._roamableWorkspaceKeyTargets = undefined; + break; case StorageScope.WORKSPACE: this._workspaceKeyTargets = undefined; break; @@ -462,6 +472,15 @@ export abstract class AbstractStorageService extends Disposable implements IStor return this._workspaceKeyTargets; } + private _roamableWorkspaceKeyTargets: IKeyTargets | undefined = undefined; + private get roamableWorkspaceKeyTargets(): IKeyTargets { + if (!this._roamableWorkspaceKeyTargets) { + this._roamableWorkspaceKeyTargets = this.loadKeyTargets(StorageScope.ROAMABLE_WORKSPACE); + } + + return this._roamableWorkspaceKeyTargets; + } + private _profileKeyTargets: IKeyTargets | undefined = undefined; private get profileKeyTargets(): IKeyTargets { if (!this._profileKeyTargets) { @@ -486,6 +505,8 @@ export abstract class AbstractStorageService extends Disposable implements IStor return this.applicationKeyTargets; case StorageScope.PROFILE: return this.profileKeyTargets; + case StorageScope.ROAMABLE_WORKSPACE: + return this.roamableWorkspaceKeyTargets; default: return this.workspaceKeyTargets; } @@ -626,6 +647,7 @@ export class InMemoryStorageService extends AbstractStorageService { private readonly applicationStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY })); private readonly profileStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY })); private readonly workspaceStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY })); + private readonly roamableWorkspaceStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY })); constructor() { super(); @@ -633,6 +655,7 @@ export class InMemoryStorageService extends AbstractStorageService { this._register(this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key))); this._register(this.profileStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.PROFILE, key))); this._register(this.applicationStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.APPLICATION, key))); + this._register(this.roamableWorkspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.ROAMABLE_WORKSPACE, key))); } protected getStorage(scope: StorageScope): IStorage { @@ -641,6 +664,8 @@ export class InMemoryStorageService extends AbstractStorageService { return this.applicationStorage; case StorageScope.PROFILE: return this.profileStorage; + case StorageScope.ROAMABLE_WORKSPACE: + return this.roamableWorkspaceStorage; default: return this.workspaceStorage; } @@ -652,6 +677,8 @@ export class InMemoryStorageService extends AbstractStorageService { return 'inMemory (application)'; case StorageScope.PROFILE: return 'inMemory (profile)'; + case StorageScope.ROAMABLE_WORKSPACE: + return 'inMemory (roamable workspace)'; default: return 'inMemory (workspace)'; } diff --git a/src/vs/workbench/common/memento.ts b/src/vs/workbench/common/memento.ts index 4c6cea091239c..204d02341c68f 100644 --- a/src/vs/workbench/common/memento.ts +++ b/src/vs/workbench/common/memento.ts @@ -58,6 +58,9 @@ export class Memento { return applicationMemento.getMemento(); } + + case StorageScope.ROAMABLE_WORKSPACE: + throw new Error('Not implemented'); } } diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index 7f4164603a683..0810120351dbc 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -62,7 +62,6 @@ import { CancellationError } from 'vs/base/common/errors'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IExtensionsViewPaneContainer, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; -import { EditSessionRegistry } from 'vs/platform/workspace/browser/editSessionsStorageService'; registerSingleton(IEditSessionsLogService, EditSessionsLogService, InstantiationType.Delayed); registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, InstantiationType.Delayed); @@ -641,23 +640,29 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } } - EditSessionRegistry.getEditSessionContributions().forEach(([key, contrib]) => { - const state = editSession.state[key]; - if (state) { - contributedStateHandlers.push(() => contrib.resumeState(state, (incomingUri: URI) => { - for (const absoluteUri of incomingFolderUrisToIdentifiers.keys()) { - if (isEqualOrParent(incomingUri, URI.parse(absoluteUri))) { - const [workspaceFolderUri, match] = incomingFolderUrisToIdentifiers.get(absoluteUri)!; - if (match === EditSessionIdentityMatch.Complete) { - const relativeFilePath = relativePath(URI.parse(absoluteUri), incomingUri); - return relativeFilePath ? joinPath(URI.parse(workspaceFolderUri), relativeFilePath) : incomingUri; - } - - } + const resolveUri = (incomingUri: URI) => { + for (const absoluteUri of incomingFolderUrisToIdentifiers.keys()) { + if (isEqualOrParent(incomingUri, URI.parse(absoluteUri))) { + const [workspaceFolderUri, match] = incomingFolderUrisToIdentifiers.get(absoluteUri)!; + if (match === EditSessionIdentityMatch.Complete) { + const relativeFilePath = relativePath(URI.parse(absoluteUri), incomingUri); + return relativeFilePath ? joinPath(URI.parse(workspaceFolderUri), relativeFilePath) : incomingUri; } - return incomingUri; - })); + + } } + return incomingUri; + }; + + Object.entries(editSession.state).forEach(([key, state]) => { + try { + const deserializedState = JSON.parse(state); + if (typeof deserializedState === 'object' && deserializedState && 'absoluteUris' in deserializedState) { + const convertedUris = deserializedState.absoluteUris.map((uri: string) => resolveUri(URI.parse(uri))); + state = JSON.stringify({ ...deserializedState, convertedUris }); + } + this.storageService.store(key, state, StorageScope.ROAMABLE_WORKSPACE, StorageTarget.USER); + } catch (ex) { } }); return { changes, conflictingChanges, contributedStateHandlers }; @@ -748,9 +753,12 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo } // Look through all registered contributions to gather additional state - const contributedData: { [key: string]: unknown } = {}; - EditSessionRegistry.getEditSessionContributions().forEach(([key, contrib]) => { - contributedData[key] = contrib.getStateToStore(); + const contributedData: { [key: string]: string } = {}; + this.storageService.keys(StorageScope.ROAMABLE_WORKSPACE, StorageTarget.USER).forEach((key) => { + const state = this.storageService.get(key, StorageScope.ROAMABLE_WORKSPACE); + if (typeof state === 'string') { + contributedData[key] = state; + } }); if (!hasEdits) { diff --git a/src/vs/workbench/contrib/editSessions/common/editSessions.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts index 17ef4749019a5..77034b8edbff5 100644 --- a/src/vs/workbench/contrib/editSessions/common/editSessions.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -79,7 +79,7 @@ export interface EditSession { version: number; machine?: string; folders: Folder[]; - state: { [key: string]: unknown }; + state: { [key: string]: string }; } export const EDIT_SESSIONS_SIGNED_IN_KEY = 'editSessionsSignedIn'; diff --git a/src/vs/workbench/contrib/scm/common/scmService.ts b/src/vs/workbench/contrib/scm/common/scmService.ts index 38867b0e96abd..684881d3481b6 100644 --- a/src/vs/workbench/contrib/scm/common/scmService.ts +++ b/src/vs/workbench/contrib/scm/common/scmService.ts @@ -94,6 +94,8 @@ class SCMInput implements ISCMInput { private readonly _onDidChangeValidateInput = new Emitter(); readonly onDidChangeValidateInput: Event = this._onDidChangeValidateInput.event; + private static readonly roamableWorkspaceInputKey = 'scmInputHistory'; + private historyNavigator: HistoryNavigator2; private didChangeHistory: boolean; @@ -191,10 +193,35 @@ class SCMInput implements ISCMInput { if (history.length === 0 || (history.length === 1 && history[0] === '')) { storageService.remove(key, StorageScope.APPLICATION); } else { - storageService.store(key, JSON.stringify({ timestamp: new Date().getTime(), history }), StorageScope.APPLICATION, StorageTarget.MACHINE); + const timestamp = new Date().getTime(); + storageService.store(key, JSON.stringify({ timestamp: timestamp, history }), StorageScope.APPLICATION, StorageTarget.MACHINE); + storageService.store(SCMInput.roamableWorkspaceInputKey, + JSON.stringify({ + absoluteUris: [this.repository.provider.rootUri!.toString()], + timestamp: timestamp, + history + }), + StorageScope.ROAMABLE_WORKSPACE, + StorageTarget.USER + ); } this.didChangeHistory = false; }); + + this.storageService.onDidChangeValue((e) => { + if (e.scope === StorageScope.ROAMABLE_WORKSPACE && e.target === StorageTarget.USER && e.key === SCMInput.roamableWorkspaceInputKey) { + const value = this.storageService.get(e.key, StorageScope.ROAMABLE_WORKSPACE); + if (value) { + const deserializedHistory = JSON.parse(value); + if (deserializedHistory.convertedUris[0] === this.repository.provider.rootUri!.toString()) { + for (const item of deserializedHistory.history) { + this.historyNavigator.add(item); + } + this._value = deserializedHistory.history[deserializedHistory.history.length - 1]; + } + } + } + }); } }