diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 54e3ef5bf78..5d8e7648c1d 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -198,21 +198,27 @@ export abstract class AbstractSynchroniser extends Disposable { const { ref, content } = await this.getUserData(lastSyncData); let syncData: ISyncData | null = null; if (content !== null) { - try { - syncData = JSON.parse(content); - - // Migration from old content to sync data - if (!isSyncData(syncData)) { - syncData = { version: this.version, content }; - } - - } catch (e) { - this.logService.error(e); - } + syncData = this.parseSyncData(content); } return { ref, syncData }; } + protected parseSyncData(content: string): ISyncData | null { + let syncData: ISyncData | null = null; + try { + syncData = JSON.parse(content); + + // Migration from old content to sync data + if (!isSyncData(syncData)) { + syncData = { version: this.version, content }; + } + + } catch (e) { + this.logService.error(e); + } + return syncData; + } + private async getUserData(refOrLastSyncData: string | IRemoteUserData | null): Promise { if (isString(refOrLastSyncData)) { const content = await this.userDataSyncStoreService.resolveContent(this.resourceKey, refOrLastSyncData); diff --git a/src/vs/platform/userDataSync/common/keybindingsSync.ts b/src/vs/platform/userDataSync/common/keybindingsSync.ts index d6bd759c239..33f5eb92dd7 100644 --- a/src/vs/platform/userDataSync/common/keybindingsSync.ts +++ b/src/vs/platform/userDataSync/common/keybindingsSync.ts @@ -161,6 +161,21 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem return content !== null ? this.getKeybindingsContentFromSyncContent(content) : null; } + async getRemoteContent(ref?: string, fragment?: string): Promise { + const content = await super.getRemoteContent(ref); + if (content !== null && fragment) { + const syncData = this.parseSyncData(content); + if (syncData) { + switch (fragment) { + case 'keybindings': + return this.getKeybindingsContentFromSyncContent(syncData.content); + } + } + return null; + } + return content; + } + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { try { const result = await this.getPreview(remoteUserData, lastSyncUserData); diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index c1876d666f1..79d0b2494e8 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -202,6 +202,24 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement return content; } + async getRemoteContent(ref?: string, fragment?: string): Promise { + let content = await super.getRemoteContent(ref); + if (content !== null && fragment) { + const syncData = this.parseSyncData(content); + if (syncData) { + const settingsSyncContent = this.parseSettingsSyncContent(syncData.content); + if (settingsSyncContent) { + switch (fragment) { + case 'settings': + return settingsSyncContent.settings; + } + } + } + return null; + } + return content; + } + async accept(content: string): Promise { if (this.status === SyncStatus.HasConflicts) { const preview = await this.syncPreviewResultPromise!; diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 30c25f16104..e85515b3984 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -255,7 +255,7 @@ export interface IUserDataSynchroniser { resetLocal(): Promise; getRemoteContentFromPreview(): Promise; - getRemoteContent(ref?: string): Promise; + getRemoteContent(ref?: string, fragment?: string): Promise; accept(content: string): Promise; } @@ -350,11 +350,11 @@ export function toSyncResource(resourceKey: ResourceKey, ref?: string): URI { return URI.from({ scheme: USER_DATA_SYNC_SCHEME, path: `${resourceKey}/${ref ? ref : 'latest'}` }); } -export function resolveSyncResource(resource: URI): { resourceKey: ResourceKey, ref?: string, query?: string } | null { +export function resolveSyncResource(resource: URI): { resourceKey: ResourceKey, ref?: string } | null { const resourceKey: ResourceKey = basename(dirname(resource)) as ResourceKey; const ref = basename(resource); if (resourceKey && ref) { - return { resourceKey, ref: ref !== 'latest' ? ref : undefined, query: resource.query }; + return { resourceKey, ref: ref !== 'latest' ? ref : undefined }; } return null; } diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 2f25ff6ae66..08e0a4c9aa3 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -68,7 +68,7 @@ export class SettingsSyncChannel implements IServerChannel { case 'hasLocalData': return this.service.hasLocalData(); case 'resolveSettingsConflicts': return this.service.resolveSettingsConflicts(args[0]); case 'getRemoteContentFromPreview': return this.service.getRemoteContentFromPreview(); - case 'getRemoteContent': return this.service.getRemoteContent(args[0]); + case 'getRemoteContent': return this.service.getRemoteContent(args[0], args[1]); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 0928911e167..90a7cf151f8 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -182,10 +182,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ if (result) { const synchronizer = this.synchronisers.filter(s => s.resourceKey === result.resourceKey)[0]; if (synchronizer) { - if (PREVIEW_QUERY === result.query) { + if (PREVIEW_QUERY === resource.query) { return synchronizer.getRemoteContentFromPreview(); } - return synchronizer.getRemoteContent(result.ref); + return synchronizer.getRemoteContent(result.ref, resource.fragment); } } return null; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index e24b4fcfbf1..6dc2bf59441 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -1113,7 +1113,7 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio return true; } - if (resolveSyncResource(model.uri)?.query === PREVIEW_QUERY) { + if (resolveSyncResource(model.uri) !== null && model.uri.query === PREVIEW_QUERY) { return this.configurationService.getValue('diffEditor.renderSideBySide'); } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncHistory.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncHistory.ts index 1be5e2cced4..09519bc05fd 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncHistory.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncHistory.ts @@ -11,13 +11,13 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { TreeViewPane, TreeView } from 'vs/workbench/browser/parts/views/treeView'; import { VIEW_CONTAINER } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { ALL_RESOURCE_KEYS, CONTEXT_SYNC_ENABLEMENT, IUserDataSyncStoreService, ResourceKey, toSyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { ALL_RESOURCE_KEYS, CONTEXT_SYNC_ENABLEMENT, IUserDataSyncStoreService, toSyncResource, resolveSyncResource } from 'vs/platform/userDataSync/common/userDataSync'; import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions'; import { IContextKeyService, RawContextKey, ContextKeyExpr, ContextKeyEqualsExpr } from 'vs/platform/contextkey/common/contextkey'; import { URI } from 'vs/base/common/uri'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { FolderThemeIcon, FileThemeIcon } from 'vs/platform/theme/common/themeService'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; const CONTEXT_SHOW_USER_DATA_SYNC_HISTORY_VIEW = new RawContextKey('showUserDataSyncHistoryView', false); @@ -93,22 +93,38 @@ export class UserDataSyncHistoryViewContribution implements IWorkbenchContributi registerAction2(class extends Action2 { constructor() { super({ - id: 'workbench.actions.deleteRef', - title: localize('workbench.action.deleteRef', "Delete"), + id: 'workbench.actions.commpareWithLocal', + title: localize('workbench.action.deleteRef', "Compare with Local"), menu: { id: MenuId.ViewItemContext, - when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.viewId), ContextKeyExpr.regex('viewItem', /sync-.*/i)) + when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.viewId), ContextKeyExpr.regex('viewItem', /syncref-(settings|keybindings).*/i)) }, }); } async run(accessor: ServicesAccessor, handle: TreeViewItemHandleArg): Promise { - const dialogService = accessor.get(IDialogService); - const userDataSyncStoreService = accessor.get(IUserDataSyncStoreService); - const result = await dialogService.confirm({ - message: 'Would you like to delete' - }); + const editorService = accessor.get(IEditorService); + const environmentService = accessor.get(IEnvironmentService); + const resource = URI.parse(handle.$treeItemHandle); + const result = resolveSyncResource(resource); if (result) { - return userDataSyncStoreService.delete(handle.$treeItemHandle as ResourceKey); + let leftResource: URI; + let rightResource: URI; + if (result.resourceKey === 'settings') { + leftResource = resource.with({ fragment: 'settings' }); + rightResource = environmentService.settingsResource; + } else { + leftResource = resource.with({ fragment: 'keybindings' }); + rightResource = environmentService.keybindingsResource; + } + await editorService.openEditor({ + leftResource, + rightResource, + options: { + preserveFocus: false, + pinned: true, + revealIfVisible: true, + }, + }); } } }); @@ -143,7 +159,7 @@ class UserDataSyncHistoryViewDataProvider implements ITreeViewDataProvider { return refs.map(ref => { const resourceUri = toSyncResource(resourceKey, ref); return { - handle: `${resourceKey}/${ref}`, + handle: resourceUri.toString(), collapsibleState: TreeItemCollapsibleState.None, label: { label: ref }, command: { id: 'workbench.actions.openRef', title: '', arguments: [resourceUri] }, diff --git a/src/vs/workbench/services/userDataSync/electron-browser/settingsSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/settingsSyncService.ts index 429517bea3e..8fe78318d4c 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/settingsSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/settingsSyncService.ts @@ -84,8 +84,8 @@ export class SettingsSyncService extends Disposable implements ISettingsSyncServ return this.channel.call('resolveConflicts', [conflicts]); } - getRemoteContent(ref?: string): Promise { - return this.channel.call('getRemoteContent', [ref]); + getRemoteContent(ref?: string, fragment?: string): Promise { + return this.channel.call('getRemoteContent', [ref, fragment]); } getRemoteContentFromPreview(): Promise {