Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/configuration/vscode-node/configurationMigration.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
/**
7
* Heavily lifted from https://github.com/microsoft/vscode/tree/main/src/vs/workbench/common/configuration.ts
8
* It is a little simplified and does not handle overrides, but currently we are only migrating experimental configurations
9
*/
10
11
12
import { ConfigurationTarget, l10n, Uri, window, workspace, WorkspaceFolder } from 'vscode';
13
import { ConfigurationKeyValuePairs, ConfigurationMigration, ConfigurationMigrationRegistry, ConfigurationValue } from '../../../platform/configuration/common/configurationService';
14
import { NextCursorLinePrediction } from '../../../platform/inlineEdits/common/dataTypes/nextCursorLinePrediction';
15
import { DisposableStore, IDisposable } from '../../../util/vs/base/common/lifecycle';
16
import { IExtensionContribution } from '../../common/contributions';
17
18
19
interface IConfigurationNode {
20
id: string;
21
title: string;
22
type: string;
23
order?: number;
24
25
}
26
27
export const applicationConfigurationNodeBase = Object.freeze<IConfigurationNode>({
28
'id': 'application',
29
'order': 100,
30
'title': l10n.t("Application"),
31
'type': 'object'
32
});
33
34
export const Extensions = {
35
ConfigurationMigration: 'base.contributions.configuration.migration'
36
};
37
38
export class ConfigurationMigrationContribution implements IExtensionContribution {
39
private readonly _disposables = new DisposableStore();
40
41
constructor() {
42
this._register(workspace.onDidChangeWorkspaceFolders(async (e) => {
43
for (const folder of e.added) {
44
await this.migrateConfigurationForFolder(folder, ConfigurationMigrationRegistry.migrations);
45
}
46
}));
47
this.migrateConfigurations(ConfigurationMigrationRegistry.migrations);
48
this._register(ConfigurationMigrationRegistry.onDidRegisterConfigurationMigration(migration => this.migrateConfigurations(migration)));
49
}
50
51
private async migrateConfigurations(migrations: ConfigurationMigration[]): Promise<void> {
52
if (window.state.focused) {
53
await this.migrateConfigurationForFolder(undefined, migrations);
54
for (const folder of workspace.workspaceFolders ?? []) {
55
await this.migrateConfigurationForFolder(folder, migrations);
56
}
57
}
58
}
59
60
private async migrateConfigurationForFolder(folder: WorkspaceFolder | undefined, migrations: ConfigurationMigration[]): Promise<void> {
61
await Promise.all([migrations.map(migration => this.migrateConfigurationsForFolder(migration, folder?.uri))]);
62
}
63
64
private async migrateConfigurationsForFolder(migration: ConfigurationMigration, resource?: Uri): Promise<void> {
65
66
const configuration = workspace.getConfiguration(undefined, resource);
67
const inspectData = configuration.inspect(migration.key);
68
69
if (!inspectData) {
70
return;
71
}
72
73
const targetPairs: [unknown, ConfigurationTarget][] = [
74
[inspectData.globalValue, ConfigurationTarget.Global],
75
[inspectData.workspaceValue, ConfigurationTarget.Workspace],
76
];
77
78
for (const [inspectValue, target] of targetPairs) {
79
if (!inspectValue) {
80
continue;
81
}
82
83
const migrationValues: [string, ConfigurationValue][] = [];
84
85
if (inspectValue !== undefined) {
86
const keyValuePairs = await this.runMigration(migration, inspectValue);
87
for (const keyValuePair of keyValuePairs ?? []) {
88
migrationValues.push(keyValuePair);
89
}
90
}
91
92
if (migrationValues.length) {
93
// apply migrations
94
await Promise.allSettled(migrationValues.map(async ([key, value]) => {
95
configuration.update(key, value.value, target);
96
}));
97
}
98
}
99
}
100
101
private async runMigration(migration: ConfigurationMigration, value: any): Promise<ConfigurationKeyValuePairs | undefined> {
102
const result = await migration.migrateFn(value);
103
return Array.isArray(result) ? result : [[migration.key, result]];
104
}
105
106
private _register(disposable: IDisposable): void {
107
this._disposables.add(disposable);
108
}
109
110
dispose(): void {
111
this._disposables.dispose();
112
}
113
}
114
115
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
116
key: 'github.copilot.chat.experimental.setupTests.enabled',
117
migrateFn: async (value: any) => {
118
return [
119
['github.copilot.chat.setupTests.enabled', { value }],
120
['github.copilot.chat.experimental.setupTests.enabled', { value: undefined }]
121
];
122
}
123
}]);
124
125
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
126
key: 'github.copilot.chat.experimental.codeGeneration.instructions',
127
migrateFn: async (value: any) => {
128
return [
129
['github.copilot.chat.codeGeneration.instructions', { value }],
130
['github.copilot.chat.experimental.codeGeneration.instructions', { value: undefined }]
131
];
132
}
133
}]);
134
135
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
136
key: 'github.copilot.chat.experimental.codeGeneration.useInstructionFiles',
137
migrateFn: async (value: any) => {
138
return [
139
['github.copilot.chat.codeGeneration.useInstructionFiles', { value }],
140
['github.copilot.chat.experimental.codeGeneration.useInstructionFiles', { value: undefined }]
141
];
142
}
143
}]);
144
145
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
146
key: 'github.copilot.chat.experimental.testGeneration.instructions',
147
migrateFn: async (value: any) => {
148
return [
149
['github.copilot.chat.testGeneration.instructions', { value }],
150
['github.copilot.chat.experimental.testGeneration.instructions', { value: undefined }]
151
];
152
}
153
}]);
154
155
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
156
key: 'github.copilot.chat.planAgent.model',
157
migrateFn: async (value: any) => {
158
return [
159
['chat.planAgent.defaultModel', { value }],
160
['github.copilot.chat.planAgent.model', { value: undefined }]
161
];
162
}
163
}]);
164
165
const oldCursorJumpKey = 'github.copilot.chat.advanced.inlineEdits.nextCursorPrediction.enabled';
166
const newCursorJumpKey = 'github.copilot.nextEditSuggestions.extendedRange';
167
ConfigurationMigrationRegistry.registerConfigurationMigrations([{
168
key: oldCursorJumpKey,
169
migrateFn: async (value: boolean | /* the rest is for backward compat: */ NextCursorLinePrediction | 'labelOnlyWithEdit' | boolean | undefined) => {
170
if (typeof value === 'string') { // for backward compatibility -- one of 'onlyWithEdit' | 'jump' | 'labelOnlyWithEdit'
171
value = true;
172
} else if (value === undefined) {
173
value = false;
174
}
175
return [
176
[newCursorJumpKey, { value }],
177
[oldCursorJumpKey, { value: undefined }]
178
];
179
}
180
}]);
181
182