提交 4b0a066b 编写于 作者: S Sandeep Somavarapu

- Get formatting options using text model

- Send only bindings to resolve
上级 46d85906
......@@ -50,7 +50,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IProductService } from 'vs/platform/product/common/productService';
import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration, IUserDataSyncLogService, IUserKeybindingsResolverService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncService, UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
......@@ -63,7 +63,7 @@ import { AuthTokenService } from 'vs/platform/auth/electron-browser/authTokenSer
import { AuthTokenChannel } from 'vs/platform/auth/common/authTokenIpc';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
import { UserKeybindingsResolverServiceClient } from 'vs/platform/userDataSync/common/keybindingsSyncIpc';
import { UserDataSyncUtilServiceClient } from 'vs/platform/userDataSync/common/keybindingsSyncIpc';
export interface ISharedProcessConfiguration {
readonly machineId: string;
......@@ -187,7 +187,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IUserDataSyncLogService, new SyncDescriptor(UserDataSyncLogService));
const settingsMergeChannel = server.getChannel('settingsMerge', activeWindowRouter);
services.set(ISettingsMergeService, new SettingsMergeChannelClient(settingsMergeChannel));
services.set(IUserKeybindingsResolverService, new UserKeybindingsResolverServiceClient(server.getChannel('userKeybindingsResolver', activeWindowRouter)));
services.set(IUserDataSyncUtilService, new UserDataSyncUtilServiceClient(server.getChannel('userDataSyncUtil', activeWindowRouter)));
services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService));
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService));
registerConfiguration();
......
......@@ -3,13 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { OperatingSystem, OS } from 'vs/base/common/platform';
import { JSONPath } from 'vs/base/common/json';
import { setProperty } from 'vs/base/common/jsonEdit';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
export function edit(content: string, eol: string, originalPath: JSONPath, value: any): string {
const edit = setProperty(content, originalPath, value, { tabSize: 4, insertSpaces: false, eol })[0];
export function edit(content: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions): string {
const edit = setProperty(content, originalPath, value, formattingOptions)[0];
if (edit) {
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
}
......@@ -51,14 +51,3 @@ export function getLineEndOffset(content: string, eol: string, atOffset: number)
}
return content.length - 1;
}
export function getEol(content: string): string {
if (content.indexOf('\r\n') !== -1) {
return '\r\n';
}
if (content.indexOf('\n') !== -1) {
return '\n';
}
return OS === OperatingSystem.Linux || OS === OperatingSystem.Macintosh ? '\n' : '\r\n';
}
......@@ -11,6 +11,8 @@ import { firstIndex as findFirstIndex, equals } from 'vs/base/common/arrays';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import * as contentUtil from 'vs/platform/userDataSync/common/content';
import { IStringDictionary } from 'vs/base/common/collections';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
interface ICompareResult {
added: Set<string>;
......@@ -27,11 +29,13 @@ interface IMergeResult {
conflicts: Set<string>;
}
export function merge(localContent: string, remoteContent: string, baseContent: string | null, normalizedKeys: IStringDictionary<string>): { mergeContent: string, hasChanges: boolean, hasConflicts: boolean } {
export async function merge(localContent: string, remoteContent: string, baseContent: string | null, formattingOptions: FormattingOptions, userDataSyncUtilService: IUserDataSyncUtilService): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> {
const local = <IUserFriendlyKeybinding[]>parse(localContent);
const remote = <IUserFriendlyKeybinding[]>parse(remoteContent);
const base = baseContent ? <IUserFriendlyKeybinding[]>parse(baseContent) : null;
const userbindings: string[] = [...local, ...remote, ...(base || [])].map(keybinding => keybinding.key);
const normalizedKeys = await userDataSyncUtilService.resolveUserBindings(userbindings);
let keybindingsMergeResult = computeMergeResultByKeybinding(local, remote, base, normalizedKeys);
if (!keybindingsMergeResult.hasLocalForwarded && !keybindingsMergeResult.hasRemoteForwarded) {
......@@ -57,7 +61,6 @@ export function merge(localContent: string, remoteContent: string, baseContent:
const baseToRemoteByCommand = baseByCommand ? compareByCommand(baseByCommand, remoteByCommand, normalizedKeys) : { added: keys(remoteByCommand).reduce((r, k) => { r.add(k); return r; }, new Set<string>()), removed: new Set<string>(), updated: new Set<string>() };
const commandsMergeResult = computeMergeResult(localToRemoteByCommand, baseToLocalByCommand, baseToRemoteByCommand);
const eol = contentUtil.getEol(localContent);
let mergeContent = localContent;
// Removed commands in Remote
......@@ -65,7 +68,7 @@ export function merge(localContent: string, remoteContent: string, baseContent:
if (commandsMergeResult.conflicts.has(command)) {
continue;
}
mergeContent = removeKeybindings(mergeContent, eol, command);
mergeContent = removeKeybindings(mergeContent, command, formattingOptions);
}
// Added commands in remote
......@@ -79,7 +82,7 @@ export function merge(localContent: string, remoteContent: string, baseContent:
commandsMergeResult.conflicts.add(command);
continue;
}
mergeContent = addKeybindings(mergeContent, eol, keybindings);
mergeContent = addKeybindings(mergeContent, keybindings, formattingOptions);
}
// Updated commands in Remote
......@@ -93,16 +96,16 @@ export function merge(localContent: string, remoteContent: string, baseContent:
commandsMergeResult.conflicts.add(command);
continue;
}
mergeContent = updateKeybindings(mergeContent, eol, command, keybindings);
mergeContent = updateKeybindings(mergeContent, command, keybindings, formattingOptions);
}
const hasConflicts = commandsMergeResult.conflicts.size > 0;
if (hasConflicts) {
mergeContent = `<<<<<<< local${eol}`
mergeContent = `<<<<<<< local${formattingOptions.eol}`
+ mergeContent
+ `${eol}=======${eol}`
+ `${formattingOptions.eol}=======${formattingOptions.eol}`
+ remoteContent
+ `${eol}>>>>>>> remote`;
+ `${formattingOptions.eol}>>>>>>> remote`;
}
return { mergeContent, hasChanges: true, hasConflicts };
......@@ -330,35 +333,35 @@ function isSameKeybinding(a: IUserFriendlyKeybinding, b: IUserFriendlyKeybinding
return true;
}
function addKeybindings(content: string, eol: string, keybindings: IUserFriendlyKeybinding[]): string {
function addKeybindings(content: string, keybindings: IUserFriendlyKeybinding[], formattingOptions: FormattingOptions): string {
for (const keybinding of keybindings) {
content = contentUtil.edit(content, eol, [-1], keybinding);
content = contentUtil.edit(content, [-1], keybinding, formattingOptions);
}
return content;
}
function removeKeybindings(content: string, eol: string, command: string): string {
function removeKeybindings(content: string, command: string, formattingOptions: FormattingOptions): string {
const keybindings = <IUserFriendlyKeybinding[]>parse(content);
for (let index = keybindings.length - 1; index >= 0; index--) {
if (keybindings[index].command === command || keybindings[index].command === `-${command}`) {
content = contentUtil.edit(content, eol, [index], undefined);
content = contentUtil.edit(content, [index], undefined, formattingOptions);
}
}
return content;
}
function updateKeybindings(content: string, eol: string, command: string, keybindings: IUserFriendlyKeybinding[]): string {
function updateKeybindings(content: string, command: string, keybindings: IUserFriendlyKeybinding[], formattingOptions: FormattingOptions): string {
const allKeybindings = <IUserFriendlyKeybinding[]>parse(content);
const location = findFirstIndex(allKeybindings, keybinding => keybinding.command === command || keybinding.command === `-${command}`);
// Remove all entries with this command
for (let index = allKeybindings.length - 1; index >= 0; index--) {
if (allKeybindings[index].command === command || allKeybindings[index].command === `-${command}`) {
content = contentUtil.edit(content, eol, [index], undefined);
content = contentUtil.edit(content, [index], undefined, formattingOptions);
}
}
// add all entries at the same location where the entry with this command was located.
for (let index = keybindings.length - 1; index >= 0; index--) {
content = contentUtil.edit(content, eol, [location], keybindings[index]);
content = contentUtil.edit(content, [location], keybindings[index], formattingOptions);
}
return content;
}
......@@ -5,7 +5,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files';
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserKeybindingsResolverService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge';
import { VSBuffer } from 'vs/base/common/buffer';
import { parse, ParseError } from 'vs/base/common/json';
......@@ -58,7 +58,7 @@ export class KeybindingsSynchroniser extends Disposable implements ISynchroniser
@IConfigurationService private readonly configurationService: IConfigurationService,
@IFileService private readonly fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IUserKeybindingsResolverService private readonly userKeybindingsResolverService: IUserKeybindingsResolverService,
@IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService,
) {
super();
this.lastSyncKeybindingsResource = joinPath(this.environmentService.userRoamingDataHome, '.lastSyncKeybindings.json');
......@@ -234,8 +234,8 @@ export class KeybindingsSynchroniser extends Disposable implements ISynchroniser
|| lastSyncContent !== remoteContent // Remote has forwarded
) {
this.logService.trace('Keybindings: Merging remote keybindings with local keybindings...');
const keys = await this.userKeybindingsResolverService.resolveUserKeybindings(localContent, remoteContent, lastSyncContent);
const result = merge(localContent, remoteContent, lastSyncContent, keys);
const formattingOptions = await this.userDataSyncUtilService.resolveFormattingOptions(this.environmentService.keybindingsResource);
const result = await merge(localContent, remoteContent, lastSyncContent, formattingOptions, this.userDataSyncUtilService);
// Sync only if there are changes
if (result.hasChanges) {
hasLocalChanged = result.mergeContent !== localContent;
......
......@@ -5,12 +5,14 @@
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { IUserKeybindingsResolverService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
import { IStringDictionary } from 'vs/base/common/collections';
import { URI } from 'vs/base/common/uri';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
export class UserKeybindingsResolverServiceChannel implements IServerChannel {
export class UserDataSycnUtilServiceChannel implements IServerChannel {
constructor(private readonly service: IUserKeybindingsResolverService) { }
constructor(private readonly service: IUserDataSyncUtilService) { }
listen(_: unknown, event: string): Event<any> {
throw new Error(`Event not found: ${event}`);
......@@ -18,21 +20,26 @@ export class UserKeybindingsResolverServiceChannel implements IServerChannel {
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'resolveUserKeybindings': return this.service.resolveUserKeybindings(args[0], args[1], args[2]);
case 'resolveUserKeybindings': return this.service.resolveUserBindings(args[0]);
case 'resolveFormattingOptions': return this.service.resolveFormattingOptions(URI.revive(args[0]));
}
throw new Error('Invalid call');
}
}
export class UserKeybindingsResolverServiceClient implements IUserKeybindingsResolverService {
export class UserDataSyncUtilServiceClient implements IUserDataSyncUtilService {
_serviceBrand: undefined;
constructor(private readonly channel: IChannel) {
}
async resolveUserKeybindings(localContent: string, remoteContent: string, baseContent: string | null): Promise<IStringDictionary<string>> {
return this.channel.call('resolveUserKeybindings', [localContent, remoteContent, baseContent]);
async resolveUserBindings(userbindings: string[]): Promise<IStringDictionary<string>> {
return this.channel.call('resolveUserKeybindings', [userbindings]);
}
async resolveFormattingOptions(file: URI): Promise<FormattingOptions> {
return this.channel.call('resolveFormattingOptions', [file]);
}
}
......@@ -16,6 +16,8 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStringDictionary } from 'vs/base/common/collections';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { URI } from 'vs/base/common/uri';
const CONFIGURATION_SYNC_STORE_KEY = 'configurationSync.store';
......@@ -187,13 +189,15 @@ export interface ISettingsMergeService {
}
export const IUserKeybindingsResolverService = createDecorator<IUserKeybindingsResolverService>('IUserKeybindingsResolverService');
export const IUserDataSyncUtilService = createDecorator<IUserDataSyncUtilService>('IUserDataSyncUtilService');
export interface IUserKeybindingsResolverService {
export interface IUserDataSyncUtilService {
_serviceBrand: undefined;
resolveUserKeybindings(localContent: string, remoteContent: string, baseContent: string | null): Promise<IStringDictionary<string>>;
resolveUserBindings(userbindings: string[]): Promise<IStringDictionary<string>>;
resolveFormattingOptions(resource: URI): Promise<FormattingOptions>;
}
......
......@@ -4,22 +4,22 @@
*--------------------------------------------------------------------------------------------*/
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { ISettingsMergeService, IUserKeybindingsResolverService } from 'vs/platform/userDataSync/common/userDataSync';
import { ISettingsMergeService, IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
import { Registry } from 'vs/platform/registry/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { SettingsMergeChannel } from 'vs/platform/userDataSync/common/settingsSyncIpc';
import { UserKeybindingsResolverServiceChannel } from 'vs/platform/userDataSync/common/keybindingsSyncIpc';
import { UserDataSycnUtilServiceChannel } from 'vs/platform/userDataSync/common/keybindingsSyncIpc';
class UserDataSyncServicesContribution implements IWorkbenchContribution {
constructor(
@ISettingsMergeService settingsMergeService: ISettingsMergeService,
@IUserKeybindingsResolverService keybindingsMergeService: IUserKeybindingsResolverService,
@IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService,
@ISharedProcessService sharedProcessService: ISharedProcessService,
) {
sharedProcessService.registerChannel('settingsMerge', new SettingsMergeChannel(settingsMergeService));
sharedProcessService.registerChannel('userKeybindingsResolver', new UserKeybindingsResolverServiceChannel(keybindingsMergeService));
sharedProcessService.registerChannel('userDataSyncUtil', new UserDataSycnUtilServiceChannel(userDataSyncUtilService));
}
}
......
......@@ -3,30 +3,38 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { parse } from 'vs/base/common/json';
import { IUserFriendlyKeybinding, IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IUserKeybindingsResolverService } from 'vs/platform/userDataSync/common/userDataSync';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IUserDataSyncUtilService } from 'vs/platform/userDataSync/common/userDataSync';
import { IStringDictionary } from 'vs/base/common/collections';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { URI } from 'vs/base/common/uri';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
export class UserKeybindingsResolverService implements IUserKeybindingsResolverService {
class UserDataSyncUtilService implements IUserDataSyncUtilService {
_serviceBrand: undefined;
constructor(
@IKeybindingService private readonly keybindingsService: IKeybindingService
@IKeybindingService private readonly keybindingsService: IKeybindingService,
@ITextModelService private readonly textModelService: ITextModelService,
) { }
public async resolveUserKeybindings(localContent: string, remoteContent: string, baseContent: string | null): Promise<IStringDictionary<string>> {
const local = <IUserFriendlyKeybinding[]>parse(localContent);
const remote = <IUserFriendlyKeybinding[]>parse(remoteContent);
const base = baseContent ? <IUserFriendlyKeybinding[]>parse(baseContent) : null;
public async resolveUserBindings(userBindings: string[]): Promise<IStringDictionary<string>> {
const keys: IStringDictionary<string> = {};
for (const keybinding of [...local, ...remote, ...(base || [])]) {
keys[keybinding.key] = this.keybindingsService.resolveUserBinding(keybinding.key).map(part => part.getUserSettingsLabel()).join(' ');
for (const userbinding of userBindings) {
keys[userbinding] = this.keybindingsService.resolveUserBinding(userbinding).map(part => part.getUserSettingsLabel()).join(' ');
}
return keys;
}
async resolveFormattingOptions(resource: URI): Promise<FormattingOptions> {
const modelReference = await this.textModelService.createModelReference(resource);
const { insertSpaces, tabSize } = modelReference.object.textEditorModel.getOptions();
const eol = modelReference.object.textEditorModel.getEOL();
modelReference.dispose();
return { eol, insertSpaces, tabSize };
}
}
registerSingleton(IUserKeybindingsResolverService, UserKeybindingsResolverService);
registerSingleton(IUserDataSyncUtilService, UserDataSyncUtilService);
......@@ -80,7 +80,7 @@ import 'vs/workbench/services/extensionManagement/common/extensionEnablementServ
import 'vs/workbench/services/notification/common/notificationService';
import 'vs/workbench/services/extensions/common/staticExtensions';
import 'vs/workbench/services/userDataSync/common/settingsMergeService';
import 'vs/workbench/services/userDataSync/common/keybindingsMerge';
import 'vs/workbench/services/userDataSync/common/userDataSyncUtil';
import 'vs/workbench/services/path/common/remotePathService';
import 'vs/workbench/services/remote/common/remoteExplorerService';
import 'vs/workbench/services/workingCopy/common/workingCopyService';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册