Skip to content

Commit 6387e66

Browse files
authored
Merge pull request #104927 from microsoft/sandy081/fix-103839
Fix syncing empty keybindings file with only comments
2 parents 6d3ef15 + aaba520 commit 6387e66

File tree

3 files changed

+74
-6
lines changed

3 files changed

+74
-6
lines changed

src/vs/platform/userDataSync/common/keybindingsMerge.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ interface IMergeResult {
2828
conflicts: Set<string>;
2929
}
3030

31+
export function parseKeybindings(content: string): IUserFriendlyKeybinding[] {
32+
return parse(content) || [];
33+
}
34+
3135
export async function merge(localContent: string, remoteContent: string, baseContent: string | null, formattingOptions: FormattingOptions, userDataSyncUtilService: IUserDataSyncUtilService): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> {
32-
const local = <IUserFriendlyKeybinding[]>parse(localContent);
33-
const remote = <IUserFriendlyKeybinding[]>parse(remoteContent);
34-
const base = baseContent ? <IUserFriendlyKeybinding[]>parse(baseContent) : null;
36+
const local = parseKeybindings(localContent);
37+
const remote = parseKeybindings(remoteContent);
38+
const base = baseContent ? parseKeybindings(baseContent) : null;
3539

3640
const userbindings: string[] = [...local, ...remote, ...(base || [])].map(keybinding => keybinding.key);
3741
const normalizedKeys = await userDataSyncUtilService.resolveUserBindings(userbindings);
@@ -331,7 +335,7 @@ function addKeybindings(content: string, keybindings: IUserFriendlyKeybinding[],
331335
}
332336

333337
function removeKeybindings(content: string, command: string, formattingOptions: FormattingOptions): string {
334-
const keybindings = <IUserFriendlyKeybinding[]>parse(content);
338+
const keybindings = parseKeybindings(content);
335339
for (let index = keybindings.length - 1; index >= 0; index--) {
336340
if (keybindings[index].command === command || keybindings[index].command === `-${command}`) {
337341
content = contentUtil.edit(content, [index], undefined, formattingOptions);
@@ -341,7 +345,7 @@ function removeKeybindings(content: string, command: string, formattingOptions:
341345
}
342346

343347
function updateKeybindings(content: string, command: string, keybindings: IUserFriendlyKeybinding[], formattingOptions: FormattingOptions): string {
344-
const allKeybindings = <IUserFriendlyKeybinding[]>parse(content);
348+
const allKeybindings = parseKeybindings(content);
345349
const location = findFirstIndex(allKeybindings, keybinding => keybinding.command === command || keybinding.command === `-${command}`);
346350
// Remove all entries with this command
347351
for (let index = allKeybindings.length - 1; index >= 0; index--) {

src/vs/platform/userDataSync/common/keybindingsSync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
209209

210210
if (lastSyncUserData?.ref !== remoteUserData.ref) {
211211
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized keybindings...`);
212-
const lastSyncContent = content !== null ? this.toSyncContent(content, null) : null;
212+
const lastSyncContent = content !== null ? this.toSyncContent(content, null) : remoteUserData.syncData?.content;
213213
await this.updateLastSyncUserData({
214214
ref: remoteUserData.ref,
215215
syncData: lastSyncContent ? {

src/vs/platform/userDataSync/test/common/keybindingsSync.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,70 @@ suite('KeybindingsSync', () => {
100100
assert.equal((await fileService.readFile(keybindingsResource)).value.toString(), content);
101101
});
102102

103+
test('when keybindings file is empty with comment and remote has no changes', async () => {
104+
const fileService = client.instantiationService.get(IFileService);
105+
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;
106+
const expectedContent = '// Empty Keybindings';
107+
await fileService.writeFile(keybindingsResource, VSBuffer.fromString(expectedContent));
108+
109+
await testObject.sync(await client.manifest());
110+
111+
const lastSyncUserData = await testObject.getLastSyncUserData();
112+
const remoteUserData = await testObject.getRemoteUserData(null);
113+
assert.equal(testObject.getKeybindingsContentFromSyncContent(lastSyncUserData!.syncData!.content!), expectedContent);
114+
assert.equal(testObject.getKeybindingsContentFromSyncContent(remoteUserData!.syncData!.content!), expectedContent);
115+
assert.equal((await fileService.readFile(keybindingsResource)).value.toString(), expectedContent);
116+
});
117+
118+
test('when keybindings file is empty and remote has keybindings', async () => {
119+
const client2 = disposableStore.add(new UserDataSyncClient(server));
120+
await client2.setUp(true);
121+
const content = JSON.stringify([
122+
{
123+
'key': 'shift+cmd+w',
124+
'command': 'workbench.action.closeAllEditors',
125+
}
126+
]);
127+
await client2.instantiationService.get(IFileService).writeFile(client2.instantiationService.get(IEnvironmentService).keybindingsResource, VSBuffer.fromString(content));
128+
await client2.sync();
129+
130+
const fileService = client.instantiationService.get(IFileService);
131+
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;
132+
await fileService.writeFile(keybindingsResource, VSBuffer.fromString('// Empty Keybindings'));
133+
134+
await testObject.sync(await client.manifest());
135+
136+
const lastSyncUserData = await testObject.getLastSyncUserData();
137+
const remoteUserData = await testObject.getRemoteUserData(null);
138+
assert.equal(testObject.getKeybindingsContentFromSyncContent(lastSyncUserData!.syncData!.content!), content);
139+
assert.equal(testObject.getKeybindingsContentFromSyncContent(remoteUserData!.syncData!.content!), content);
140+
assert.equal((await fileService.readFile(keybindingsResource)).value.toString(), content);
141+
});
142+
143+
test('when keybindings file is empty and remote has empty array', async () => {
144+
const client2 = disposableStore.add(new UserDataSyncClient(server));
145+
await client2.setUp(true);
146+
const content =
147+
`// Place your key bindings in this file to override the defaults
148+
[
149+
]`;
150+
await client2.instantiationService.get(IFileService).writeFile(client2.instantiationService.get(IEnvironmentService).keybindingsResource, VSBuffer.fromString(content));
151+
await client2.sync();
152+
153+
const fileService = client.instantiationService.get(IFileService);
154+
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;
155+
const expectedLocalContent = '// Empty Keybindings';
156+
await fileService.writeFile(keybindingsResource, VSBuffer.fromString(expectedLocalContent));
157+
158+
await testObject.sync(await client.manifest());
159+
160+
const lastSyncUserData = await testObject.getLastSyncUserData();
161+
const remoteUserData = await testObject.getRemoteUserData(null);
162+
assert.equal(testObject.getKeybindingsContentFromSyncContent(lastSyncUserData!.syncData!.content!), content);
163+
assert.equal(testObject.getKeybindingsContentFromSyncContent(remoteUserData!.syncData!.content!), content);
164+
assert.equal((await fileService.readFile(keybindingsResource)).value.toString(), expectedLocalContent);
165+
});
166+
103167
test('when keybindings file is created after first sync', async () => {
104168
const fileService = client.instantiationService.get(IFileService);
105169
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;

0 commit comments

Comments
 (0)