introduce application config model (#152889)

* introduce application config model
- application configuration is active and used only in non default profiles
- read/write application scoped settings only from application layer and not from user layer
- extensions get application scoped values as global values
- settings editor does not show application scoped settings in non default profle
- added unit tests

* fix tests
This commit is contained in:
Sandeep Somavarapu 2022-06-22 20:57:39 +02:00 committed by GitHub
parent a1b53fde82
commit a1e1e307e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 464 additions and 90 deletions

View file

@ -78,6 +78,10 @@
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
"url": "vscode://schemas/settings/user"
},
{
"fileMatch": "%APP_SETTINGS_HOME%/profiles/*/settings.json",
"url": "vscode://schemas/settings/profile"
},
{
"fileMatch": "%MACHINE_SETTINGS_HOME%/settings.json",
"url": "vscode://schemas/settings/machine"

View file

@ -522,7 +522,7 @@ export class StandaloneConfigurationService implements IConfigurationService {
private readonly _configuration: Configuration;
constructor() {
this._configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
this._configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
}
getValue<T>(): T;
@ -584,6 +584,7 @@ export class StandaloneConfigurationService implements IConfigurationService {
return {
defaults: emptyModel,
policy: emptyModel,
application: emptyModel,
user: emptyModel,
workspace: emptyModel,
folders: []

View file

@ -74,6 +74,7 @@ export interface IConfigurationChangeEvent {
export interface IConfigurationValue<T> {
readonly defaultValue?: T;
readonly applicationValue?: T;
readonly userValue?: T;
readonly userLocalValue?: T;
readonly userRemoteValue?: T;
@ -84,6 +85,7 @@ export interface IConfigurationValue<T> {
readonly value?: T;
readonly default?: { value?: T; override?: T };
readonly application?: { value?: T; override?: T };
readonly user?: { value?: T; override?: T };
readonly userLocal?: { value?: T; override?: T };
readonly userRemote?: { value?: T; override?: T };
@ -166,6 +168,7 @@ export interface IOverrides {
export interface IConfigurationData {
defaults: IConfigurationModel;
policy: IConfigurationModel;
application: IConfigurationModel;
user: IConfigurationModel;
workspace: IConfigurationModel;
folders: [UriComponents, IConfigurationModel][];

View file

@ -95,6 +95,9 @@ export class ConfigurationModel implements IConfigurationModel {
const keys = [...this.keys];
for (const other of others) {
if (other.isEmpty()) {
continue;
}
this.mergeContents(contents, other.contents);
for (const otherOverride of other.overrides) {
@ -455,6 +458,7 @@ export class Configuration {
constructor(
private _defaultConfiguration: ConfigurationModel,
private _policyConfiguration: ConfigurationModel,
private _applicationConfiguration: ConfigurationModel,
private _localUserConfiguration: ConfigurationModel,
private _remoteUserConfiguration: ConfigurationModel = new ConfigurationModel(),
private _workspaceConfiguration: ConfigurationModel = new ConfigurationModel(),
@ -499,6 +503,7 @@ export class Configuration {
const defaultValue = overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue<C>(key) : this._defaultConfiguration.freeze().getValue<C>(key);
const policyValue = this._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration.freeze().getValue<C>(key);
const applicationValue = this.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration.freeze().getValue<C>(key);
const userValue = overrides.overrideIdentifier ? this.userConfiguration.freeze().override(overrides.overrideIdentifier).getValue<C>(key) : this.userConfiguration.freeze().getValue<C>(key);
const userLocalValue = overrides.overrideIdentifier ? this.localUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue<C>(key) : this.localUserConfiguration.freeze().getValue<C>(key);
const userRemoteValue = overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue<C>(key) : this.remoteUserConfiguration.freeze().getValue<C>(key);
@ -511,6 +516,7 @@ export class Configuration {
return {
defaultValue,
policyValue,
applicationValue,
userValue,
userLocalValue,
userRemoteValue,
@ -521,6 +527,7 @@ export class Configuration {
default: defaultValue !== undefined ? { value: this._defaultConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
policy: policyValue !== undefined ? { value: policyValue } : undefined,
application: applicationValue !== undefined ? { value: applicationValue, override: overrides.overrideIdentifier ? this.applicationConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
user: userValue !== undefined ? { value: this.userConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.userConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
userLocal: userLocalValue !== undefined ? { value: this.localUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.localUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
userRemote: userRemoteValue !== undefined ? { value: this.remoteUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
@ -557,6 +564,12 @@ export class Configuration {
this._policyConfiguration = policyConfiguration;
}
updateApplicationConfiguration(applicationConfiguration: ConfigurationModel): void {
this._applicationConfiguration = applicationConfiguration;
this._workspaceConsolidatedConfiguration = null;
this._foldersConsolidatedConfigurations.clear();
}
updateLocalUserConfiguration(localUserConfiguration: ConfigurationModel): void {
this._localUserConfiguration = localUserConfiguration;
this._userConfiguration = null;
@ -618,6 +631,15 @@ export class Configuration {
return { keys, overrides: [] };
}
compareAndUpdateApplicationConfiguration(application: ConfigurationModel): IConfigurationChange {
const { added, updated, removed, overrides } = compare(this.applicationConfiguration, application);
const keys = [...added, ...updated, ...removed];
if (keys.length) {
this.updateApplicationConfiguration(application);
}
return { keys, overrides };
}
compareAndUpdateLocalUserConfiguration(user: ConfigurationModel): IConfigurationChange {
const { added, updated, removed, overrides } = compare(this.localUserConfiguration, user);
const keys = [...added, ...updated, ...removed];
@ -669,6 +691,10 @@ export class Configuration {
return this._defaultConfiguration;
}
get applicationConfiguration(): ConfigurationModel {
return this._applicationConfiguration;
}
private _userConfiguration: ConfigurationModel | null = null;
get userConfiguration(): ConfigurationModel {
if (!this._userConfiguration) {
@ -726,7 +752,7 @@ export class Configuration {
private getWorkspaceConsolidatedConfiguration(): ConfigurationModel {
if (!this._workspaceConsolidatedConfiguration) {
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.applicationConfiguration, this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
if (this._freeze) {
this._workspaceConfiguration = this._workspaceConfiguration.freeze();
}
@ -774,6 +800,11 @@ export class Configuration {
overrides: this._policyConfiguration.overrides,
keys: this._policyConfiguration.keys
},
application: {
contents: this.applicationConfiguration.contents,
overrides: this.applicationConfiguration.overrides,
keys: this.applicationConfiguration.keys
},
user: {
contents: this.userConfiguration.contents,
overrides: this.userConfiguration.overrides,
@ -822,13 +853,14 @@ export class Configuration {
static parse(data: IConfigurationData): Configuration {
const defaultConfiguration = this.parseConfigurationModel(data.defaults);
const policyConfiguration = this.parseConfigurationModel(data.policy);
const applicationConfiguration = this.parseConfigurationModel(data.application);
const userConfiguration = this.parseConfigurationModel(data.user);
const workspaceConfiguration = this.parseConfigurationModel(data.workspace);
const folders: ResourceMap<ConfigurationModel> = data.folders.reduce((result, value) => {
result.set(URI.revive(value[0]), this.parseConfigurationModel(value[1]));
return result;
}, new ResourceMap<ConfigurationModel>());
return new Configuration(defaultConfiguration, policyConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), false);
return new Configuration(defaultConfiguration, policyConfiguration, applicationConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), false);
}
private static parseConfigurationModel(model: IConfigurationModel): ConfigurationModel {

View file

@ -38,7 +38,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
this.defaultConfiguration = this._register(new DefaultConfiguration());
this.policyConfiguration = policyService instanceof NullPolicyService ? new NullPolicyConfiguration() : this._register(new PolicyConfiguration(this.defaultConfiguration, policyService, logService));
this.userConfiguration = this._register(new UserSettings(this.settingsResource, undefined, extUriBiasedIgnorePathCase, fileService));
this.configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, new ConfigurationModel());
this.configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, new ConfigurationModel(), new ConfigurationModel());
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reloadConfiguration(), 50));
this._register(this.defaultConfiguration.onDidChangeConfiguration(({ defaults, properties }) => this.onDidDefaultConfigurationChange(defaults, properties)));
@ -48,7 +48,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
async initialize(): Promise<void> {
const [defaultModel, policyModel, userModel] = await Promise.all([this.defaultConfiguration.initialize(), this.policyConfiguration.initialize(), this.userConfiguration.loadConfiguration()]);
this.configuration = new Configuration(defaultModel, policyModel, userModel);
this.configuration = new Configuration(defaultModel, policyModel, new ConfigurationModel(), userModel);
}
getConfigurationData(): IConfigurationData {

View file

@ -497,7 +497,7 @@ suite('Configuration', () => {
test('Test update value', () => {
const parser = new ConfigurationModelParser('test');
parser.parse(JSON.stringify({ 'a': 1 }));
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel(), new ConfigurationModel());
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateValue('a', 2);
@ -507,7 +507,7 @@ suite('Configuration', () => {
test('Test update value after inspect', () => {
const parser = new ConfigurationModelParser('test');
parser.parse(JSON.stringify({ 'a': 1 }));
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel(), new ConfigurationModel());
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.inspect('a', {}, undefined);
testObject.updateValue('a', 2);
@ -516,7 +516,7 @@ suite('Configuration', () => {
});
test('Test compare and update default configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateDefaultConfiguration(toConfigurationModel({
'editor.lineNumbers': 'on',
}));
@ -532,8 +532,25 @@ suite('Configuration', () => {
});
test('Test compare and update application configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateApplicationConfiguration(toConfigurationModel({
'update.mode': 'on',
}));
const actual = testObject.compareAndUpdateApplicationConfiguration(toConfigurationModel({
'update.mode': 'none',
'[typescript]': {
'editor.wordWrap': 'off'
}
}));
assert.deepStrictEqual(actual, { keys: ['[typescript]', 'update.mode',], overrides: [['typescript', ['editor.wordWrap']]] });
});
test('Test compare and update user configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateLocalUserConfiguration(toConfigurationModel({
'editor.lineNumbers': 'off',
'editor.fontSize': 12,
@ -556,7 +573,7 @@ suite('Configuration', () => {
});
test('Test compare and update workspace configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateWorkspaceConfiguration(toConfigurationModel({
'editor.lineNumbers': 'off',
'editor.fontSize': 12,
@ -579,7 +596,7 @@ suite('Configuration', () => {
});
test('Test compare and update workspace folder configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateFolderConfiguration(URI.file('file1'), toConfigurationModel({
'editor.lineNumbers': 'off',
'editor.fontSize': 12,
@ -602,7 +619,7 @@ suite('Configuration', () => {
});
test('Test compare and delete workspace folder configuration', () => {
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const testObject = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
testObject.updateFolderConfiguration(URI.file('file1'), toConfigurationModel({
'editor.lineNumbers': 'off',
'editor.fontSize': 12,
@ -628,7 +645,7 @@ suite('Configuration', () => {
suite('ConfigurationChangeEvent', () => {
test('changeEvent affecting keys with new configuration', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const change = configuration.compareAndUpdateLocalUserConfiguration(toConfigurationModel({
'window.zoomLevel': 1,
'workbench.editor.enablePreview': false,
@ -654,7 +671,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent affecting keys when configuration changed', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
configuration.updateLocalUserConfiguration(toConfigurationModel({
'window.zoomLevel': 2,
'workbench.editor.enablePreview': true,
@ -683,7 +700,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent affecting overrides with new configuration', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const change = configuration.compareAndUpdateLocalUserConfiguration(toConfigurationModel({
'files.autoSave': 'off',
'[markdown]': {
@ -725,7 +742,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent affecting overrides when configuration changed', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
configuration.updateLocalUserConfiguration(toConfigurationModel({
'workbench.editor.enablePreview': true,
'[markdown]': {
@ -792,7 +809,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent affecting workspace folders', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
configuration.updateWorkspaceConfiguration(toConfigurationModel({ 'window.title': 'custom' }));
configuration.updateFolderConfiguration(URI.file('folder1'), toConfigurationModel({ 'window.zoomLevel': 2, 'window.restoreFullscreen': true }));
configuration.updateFolderConfiguration(URI.file('folder2'), toConfigurationModel({ 'workbench.editor.enablePreview': true, 'window.restoreWindows': true }));
@ -882,7 +899,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent - all', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
configuration.updateFolderConfiguration(URI.file('file1'), toConfigurationModel({ 'window.zoomLevel': 2, 'window.restoreFullscreen': true }));
const data = configuration.toData();
const change = mergeChanges(
@ -977,7 +994,7 @@ suite('ConfigurationChangeEvent', () => {
});
test('changeEvent affecting tasks and launches', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const change = configuration.compareAndUpdateLocalUserConfiguration(toConfigurationModel({
'launch': {
'configuraiton': {}
@ -1000,7 +1017,7 @@ suite('ConfigurationChangeEvent', () => {
suite('AllKeysConfigurationChangeEvent', () => {
test('changeEvent', () => {
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
const configuration = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel());
configuration.updateDefaultConfiguration(toConfigurationModel({
'editor.lineNumbers': 'off',
'[markdown]': {

View file

@ -141,7 +141,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf
protected createDefaultUserDataProfile(extensions: boolean): IUserDataProfile {
const profile = toUserDataProfile(localize('defaultProfile', "Default"), this.environmentService.userRoamingDataHome);
return { ...profile, extensionsResource: extensions ? profile.extensionsResource : undefined };
return { ...profile, isDefault: true, extensionsResource: extensions ? profile.extensionsResource : undefined };
}
createProfile(profile: IUserDataProfile, workspaceIdentifier?: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise<IUserDataProfile> { throw new Error('Not implemented'); }

View file

@ -257,12 +257,12 @@ export class ExtHostConfigProvider {
key,
defaultValue: config.policy?.value ?? config.default?.value,
globalValue: config.user?.value,
globalValue: config.user?.value ?? config.application?.value,
workspaceValue: config.workspace?.value,
workspaceFolderValue: config.workspaceFolder?.value,
defaultLanguageValue: config.default?.override,
globalLanguageValue: config.user?.override,
globalLanguageValue: config.user?.override ?? config.application?.override,
workspaceLanguageValue: config.workspace?.override,
workspaceFolderLanguageValue: config.workspaceFolder?.override,

View file

@ -44,6 +44,7 @@ suite('ExtHostConfiguration', function () {
return {
defaults: new ConfigurationModel(contents),
policy: new ConfigurationModel(),
application: new ConfigurationModel(),
user: new ConfigurationModel(contents),
workspace: new ConfigurationModel(),
folders: [],
@ -281,6 +282,7 @@ suite('ExtHostConfiguration', function () {
}
}, ['editor.wordWrap']),
policy: new ConfigurationModel(),
application: new ConfigurationModel(),
user: new ConfigurationModel({
'editor': {
'wordWrap': 'on'
@ -331,6 +333,7 @@ suite('ExtHostConfiguration', function () {
}
}, ['editor.wordWrap']),
policy: new ConfigurationModel(),
application: new ConfigurationModel(),
user: new ConfigurationModel({
'editor': {
'wordWrap': 'on'
@ -409,6 +412,7 @@ suite('ExtHostConfiguration', function () {
}
}, ['editor.wordWrap']),
policy: new ConfigurationModel(),
application: new ConfigurationModel(),
user: new ConfigurationModel({
'editor': {
'wordWrap': 'on'
@ -513,6 +517,7 @@ suite('ExtHostConfiguration', function () {
}
}),
policy: new ConfigurationModel(),
application: new ConfigurationModel(),
user: toConfigurationModel({
'editor.wordWrap': 'bounded',
'[typescript]': {
@ -554,6 +559,59 @@ suite('ExtHostConfiguration', function () {
assert.deepStrictEqual(actual.languageIds, ['markdown', 'typescript']);
});
test('application is not set in inspect', () => {
const testObject = new ExtHostConfigProvider(
new class extends mock<MainThreadConfigurationShape>() { },
createExtHostWorkspace(),
{
defaults: new ConfigurationModel({
'editor': {
'wordWrap': 'off',
'lineNumbers': 'on',
'fontSize': '12px'
}
}, ['editor.wordWrap']),
policy: new ConfigurationModel(),
application: new ConfigurationModel({
'editor': {
'wordWrap': 'on'
}
}, ['editor.wordWrap']),
user: new ConfigurationModel({
'editor': {
'wordWrap': 'auto',
'lineNumbers': 'off'
}
}, ['editor.wordWrap']),
workspace: new ConfigurationModel({}, []),
folders: [],
configurationScopes: []
},
new NullLogService()
);
let actual = testObject.getConfiguration().inspect('editor.wordWrap')!;
assert.strictEqual(actual.defaultValue, 'off');
assert.strictEqual(actual.globalValue, 'auto');
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(testObject.getConfiguration().get('editor.wordWrap'), 'auto');
actual = testObject.getConfiguration().inspect('editor.lineNumbers')!;
assert.strictEqual(actual.defaultValue, 'on');
assert.strictEqual(actual.globalValue, 'off');
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(testObject.getConfiguration().get('editor.lineNumbers'), 'off');
actual = testObject.getConfiguration().inspect('editor.fontSize')!;
assert.strictEqual(actual.defaultValue, '12px');
assert.strictEqual(actual.globalValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(testObject.getConfiguration().get('editor.fontSize'), '12px');
});
test('getConfiguration vs get', function () {

View file

@ -14,13 +14,14 @@ import { ITOCEntry, knownAcronyms, knownTermMappings, tocData } from 'vs/workben
import { ENABLE_LANGUAGE_FILTER, MODIFIED_SETTING_TAG, POLICY_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences';
import { IExtensionSetting, ISearchResult, ISetting, SettingValueType } from 'vs/workbench/services/preferences/common/preferences';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { FOLDER_SCOPES, WORKSPACE_SCOPES, REMOTE_MACHINE_SCOPES, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_SCOPES, WORKSPACE_SCOPES, REMOTE_MACHINE_SCOPES, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, LOCAL_MACHINE_PROFILE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { ConfigurationScope, EditPresentationTypes, Extensions, IConfigurationRegistry, IExtensionInfo } from 'vs/platform/configuration/common/configurationRegistry';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { Registry } from 'vs/platform/registry/common/platform';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices';
@ -166,7 +167,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
parent: SettingsTreeGroupElement,
inspectResult: IInspectResult,
isWorkspaceTrusted: boolean,
private readonly languageService: ILanguageService
private readonly languageService: ILanguageService,
private readonly userDataProfileService: IUserDataProfileService,
) {
super(sanitizeId(parent.id + '_' + setting.key));
this.setting = setting;
@ -362,8 +364,13 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
return REMOTE_MACHINE_SCOPES.indexOf(this.setting.scope) !== -1;
}
if (configTarget === ConfigurationTarget.USER_LOCAL && isRemote) {
return LOCAL_MACHINE_SCOPES.indexOf(this.setting.scope) !== -1;
if (configTarget === ConfigurationTarget.USER_LOCAL) {
if (!this.userDataProfileService.currentProfile.isDefault) {
return LOCAL_MACHINE_PROFILE_SCOPES.indexOf(this.setting.scope) !== -1;
}
if (isRemote) {
return LOCAL_MACHINE_SCOPES.indexOf(this.setting.scope) !== -1;
}
}
return true;
@ -450,7 +457,8 @@ export class SettingsTreeModel {
protected _viewState: ISettingsEditorViewState,
private _isWorkspaceTrusted: boolean,
@IWorkbenchConfigurationService private readonly _configurationService: IWorkbenchConfigurationService,
@ILanguageService private readonly _languageService: ILanguageService
@ILanguageService private readonly _languageService: ILanguageService,
@IUserDataProfileService private readonly _userDataProfileService: IUserDataProfileService,
) {
}
@ -548,7 +556,7 @@ export class SettingsTreeModel {
private createSettingsTreeSettingElement(setting: ISetting, parent: SettingsTreeGroupElement): SettingsTreeSettingElement {
const inspectResult = inspectSetting(setting.key, this._viewState.settingsTarget, this._viewState.languageFilter, this._configurationService);
const element = new SettingsTreeSettingElement(setting, parent, inspectResult, this._isWorkspaceTrusted, this._languageService);
const element = new SettingsTreeSettingElement(setting, parent, inspectResult, this._isWorkspaceTrusted, this._languageService, this._userDataProfileService);
const nameElements = this._treeElementsBySettingName.get(setting.key) || [];
nameElements.push(element);
@ -791,9 +799,10 @@ export class SearchResultModel extends SettingsTreeModel {
isWorkspaceTrusted: boolean,
@IWorkbenchConfigurationService configurationService: IWorkbenchConfigurationService,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
@ILanguageService languageService: ILanguageService
@ILanguageService languageService: ILanguageService,
@IUserDataProfileService userDataProfileService: IUserDataProfileService,
) {
super(viewState, isWorkspaceTrusted, configurationService, languageService);
super(viewState, isWorkspaceTrusted, configurationService, languageService, userDataProfileService);
this.update({ id: 'searchResultModel', label: '' });
}

View file

@ -123,7 +123,7 @@ registerAction2(class RemoveProfileAction extends Action2 {
const userDataProfilesService = accessor.get(IUserDataProfilesService);
const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService);
const profiles = userDataProfilesService.profiles.filter(p => p.name !== userDataProfileService.currentProfile.name && p.name !== userDataProfilesService.defaultProfile.name);
const profiles = userDataProfilesService.profiles.filter(p => p.id !== userDataProfileService.currentProfile.id && !p.isDefault);
if (profiles.length) {
const pick = await quickInputService.pick(profiles.map(profile => ({ label: profile.name, profile })), { placeHolder: localize('pick profile', "Select Settings Profile") });
if (pick) {
@ -153,8 +153,9 @@ registerAction2(class SwitchProfileAction extends Action2 {
const userDataProfilesService = accessor.get(IUserDataProfilesService);
const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService);
if (userDataProfilesService.profiles) {
const picks: Array<IQuickPickItem & { profile: IUserDataProfile }> = userDataProfilesService.profiles.map(profile => ({
const profiles = userDataProfilesService.profiles.filter(p => p.id !== userDataProfileService.currentProfile.id);
if (profiles.length) {
const picks: Array<IQuickPickItem & { profile: IUserDataProfile }> = profiles.map(profile => ({
label: profile.name!,
description: profile.name === userDataProfileService.currentProfile.name ? localize('current', "Current") : undefined,
profile

View file

@ -27,7 +27,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { isObject } from 'vs/base/common/types';
import { DefaultConfiguration as BaseDefaultConfiguration } from 'vs/platform/configuration/common/configurations';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
export class DefaultConfiguration extends BaseDefaultConfiguration {
@ -124,34 +123,32 @@ export class UserConfiguration extends Disposable {
private readonly userConfigurationChangeDisposable = this._register(new MutableDisposable<IDisposable>());
private readonly reloadConfigurationScheduler: RunOnceScheduler;
private readonly configurationParseOptions: ConfigurationParseOptions;
private configurationParseOptions: ConfigurationParseOptions;
get hasTasksLoaded(): boolean { return this.userConfiguration.value instanceof FileServiceBasedConfiguration; }
constructor(
private settingsResource: URI,
private tasksResource: URI | undefined,
scopes: ConfigurationScope[] | undefined,
private readonly userDataProfileService: IUserDataProfileService,
private readonly fileService: IFileService,
private readonly uriIdentityService: IUriIdentityService,
private readonly logService: ILogService,
) {
super();
this.configurationParseOptions = { scopes, skipRestricted: false };
this.userConfiguration.value = new UserSettings(this.userDataProfileService.currentProfile.settingsResource, scopes, uriIdentityService.extUri, this.fileService);
this._register(this.userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.onDidChangeCurrentProfile())));
this.userConfiguration.value = new UserSettings(settingsResource, scopes, uriIdentityService.extUri, this.fileService);
this.userConfigurationChangeDisposable.value = this.userConfiguration.value.onDidChange(() => this.reloadConfigurationScheduler.schedule());
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.userConfiguration.value!.loadConfiguration().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
}
private async onDidChangeCurrentProfile(): Promise<void> {
await this.resetUserConfiguration();
this.reloadConfigurationScheduler.schedule();
}
private async resetUserConfiguration(): Promise<ConfigurationModel> {
const folder = this.uriIdentityService.extUri.dirname(this.userDataProfileService.currentProfile.settingsResource);
const standAloneConfigurationResources: [string, URI][] = [[TASKS_CONFIGURATION_KEY, this.userDataProfileService.currentProfile.tasksResource]];
const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), this.userDataProfileService.currentProfile.settingsResource, standAloneConfigurationResources, this.configurationParseOptions, this.fileService, this.uriIdentityService, this.logService);
async reset(settingsResource: URI, tasksResource: URI | undefined, scopes: ConfigurationScope[] | undefined): Promise<ConfigurationModel> {
this.settingsResource = settingsResource;
this.tasksResource = tasksResource;
this.configurationParseOptions = { scopes, skipRestricted: false };
const folder = this.uriIdentityService.extUri.dirname(this.settingsResource);
const standAloneConfigurationResources: [string, URI][] = this.tasksResource ? [[TASKS_CONFIGURATION_KEY, this.tasksResource]] : [];
const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), this.settingsResource, standAloneConfigurationResources, this.configurationParseOptions, this.fileService, this.uriIdentityService, this.logService);
const configurationModel = await fileServiceBasedConfiguration.loadConfiguration();
this.userConfiguration.value = fileServiceBasedConfiguration;
@ -171,7 +168,7 @@ export class UserConfiguration extends Disposable {
if (this.hasTasksLoaded) {
return this.userConfiguration.value!.loadConfiguration();
}
return this.resetUserConfiguration();
return this.reset(this.settingsResource, this.tasksResource, this.configurationParseOptions.scopes);
}
reparse(): ConfigurationModel {

View file

@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { ResourceMap } from 'vs/base/common/map';
import { equals } from 'vs/base/common/objects';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Queue, Barrier, runWhenIdle, Promises } from 'vs/base/common/async';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IWorkspaceContextService, Workspace as BaseWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder, isWorkspaceFolder, IWorkspaceFoldersWillChangeEvent, IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier, IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
@ -15,7 +15,7 @@ import { ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChang
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString, IConfigurationUpdateOverrides, isConfigurationUpdateOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IPolicyConfiguration, NullPolicyConfiguration, PolicyConfiguration } from 'vs/platform/configuration/common/configurations';
import { Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, RestrictedSettings } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, RestrictedSettings, PROFILE_SCOPES, LOCAL_MACHINE_PROFILE_SCOPES, profileSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings, machineOverridableSettings, ConfigurationScope, IConfigurationPropertySchema, keyFromOverrideIdentifiers, OVERRIDE_PROPERTY_PATTERN, resourceLanguageSettingsSchemaId, configurationDefaultsSchemaId } from 'vs/platform/configuration/common/configurationRegistry';
import { IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, useSlashForPath, getStoredWorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces';
@ -40,8 +40,15 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
import { isUndefined } from 'vs/base/common/types';
import { localize } from 'vs/nls';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy';
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
function getLocalUserConfigurationScopes(userDataProfile: IUserDataProfile, hasRemote: boolean): ConfigurationScope[] | undefined {
return userDataProfile.isDefault
? hasRemote ? LOCAL_MACHINE_SCOPES : undefined
: hasRemote ? LOCAL_MACHINE_PROFILE_SCOPES : PROFILE_SCOPES;
}
class Workspace extends BaseWorkspace {
initialized: boolean = false;
@ -59,15 +66,13 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
private initialized: boolean = false;
private readonly defaultConfiguration: DefaultConfiguration;
private readonly policyConfiguration: IPolicyConfiguration;
private localUserConfiguration: UserConfiguration;
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
private workspaceConfiguration: WorkspaceConfiguration;
private applicationConfiguration: UserConfiguration | null = null;
private readonly applicationConfigurationDisposables: DisposableStore;
private readonly localUserConfiguration: UserConfiguration;
private readonly remoteUserConfiguration: RemoteUserConfiguration | null = null;
private readonly workspaceConfiguration: WorkspaceConfiguration;
private cachedFolderConfigs: ResourceMap<FolderConfiguration>;
private workspaceEditingQueue: Queue<void>;
private readonly logService: ILogService;
private readonly fileService: IFileService;
private readonly uriIdentityService: IUriIdentityService;
private readonly workspaceEditingQueue: Queue<void>;
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
public readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
@ -102,11 +107,11 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
constructor(
{ remoteAuthority, configurationCache }: { remoteAuthority?: string; configurationCache: IConfigurationCache },
environmentService: IWorkbenchEnvironmentService,
userDataProfileService: IUserDataProfileService,
fileService: IFileService,
private readonly userDataProfileService: IUserDataProfileService,
private readonly fileService: IFileService,
remoteAgentService: IRemoteAgentService,
uriIdentityService: IUriIdentityService,
logService: ILogService,
private readonly uriIdentityService: IUriIdentityService,
private readonly logService: ILogService,
policyService: IPolicyService
) {
super();
@ -118,12 +123,11 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
this.defaultConfiguration = this._register(new DefaultConfiguration(configurationCache, environmentService));
this.policyConfiguration = policyService instanceof NullPolicyService ? new NullPolicyConfiguration() : this._register(new PolicyConfiguration(this.defaultConfiguration, policyService, logService));
this.configurationCache = configurationCache;
this.fileService = fileService;
this.uriIdentityService = uriIdentityService;
this.logService = logService;
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
this.applicationConfigurationDisposables = this._register(new DisposableStore());
this.createApplicationConfiguration();
this.localUserConfiguration = this._register(new UserConfiguration(userDataProfileService.currentProfile.settingsResource, userDataProfileService.currentProfile.tasksResource, getLocalUserConfigurationScopes(userDataProfileService.currentProfile, !!remoteAuthority), fileService, uriIdentityService, logService));
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
this.localUserConfiguration = this._register(new UserConfiguration(remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, userDataProfileService, fileService, uriIdentityService, logService));
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
if (remoteAuthority) {
const remoteUserConfiguration = this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, fileService, uriIdentityService, remoteAgentService));
@ -146,10 +150,21 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
this._register(this.defaultConfiguration.onDidChangeConfiguration(({ properties, defaults }) => this.onDefaultConfigurationChanged(defaults, properties)));
this._register(this.policyConfiguration.onDidChangeConfiguration(configurationModel => this.onPolicyConfigurationChanged(configurationModel)));
this._register(userDataProfileService.onDidChangeCurrentProfile(e => this.onUserDataProfileChanged(e)));
this.workspaceEditingQueue = new Queue<void>();
}
private createApplicationConfiguration(): void {
this.applicationConfigurationDisposables.clear();
if (this.userDataProfileService.currentProfile.isDefault) {
this.applicationConfiguration = null;
} else {
this.applicationConfiguration = this.applicationConfigurationDisposables.add(this._register(new UserConfiguration(this.userDataProfileService.defaultProfile.settingsResource, undefined, [ConfigurationScope.APPLICATION], this.fileService, this.uriIdentityService, this.logService)));
this.applicationConfigurationDisposables.add(this.applicationConfiguration.onDidChangeConfiguration(configurationModel => this.onApplicationConfigurationChanged(configurationModel)));
}
}
// Workspace Context Service Impl
public async getCompleteWorkspace(): Promise<Workspace> {
@ -347,9 +362,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
async reloadConfiguration(target?: ConfigurationTarget | IWorkspaceFolder): Promise<void> {
if (target === undefined) {
this.reloadDefaultConfiguration();
const application = await this.reloadApplicationConfiguration(true);
const { local, remote } = await this.reloadUserConfiguration();
await this.reloadWorkspaceConfiguration();
await this.loadConfiguration(local, remote);
await this.loadConfiguration(application, local, remote);
return;
}
@ -365,7 +381,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
case ConfigurationTarget.USER: {
const { local, remote } = await this.reloadUserConfiguration();
await this.loadConfiguration(local, remote);
await this.loadConfiguration(this._configuration.applicationConfiguration, local, remote);
return;
}
case ConfigurationTarget.USER_LOCAL:
@ -579,8 +595,9 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
private async initializeConfiguration(): Promise<void> {
await this.defaultConfiguration.initialize();
const [, user] = await Promise.all([
const [, application, user] = await Promise.all([
this.policyConfiguration.initialize(),
this.initializeApplicationConfiguration(),
(async () => {
mark('code/willInitUserConfiguration');
const result = await this.initializeUserConfiguration();
@ -590,10 +607,14 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
]);
mark('code/willInitWorkspaceConfiguration');
await this.loadConfiguration(user.local, user.remote);
await this.loadConfiguration(application, user.local, user.remote);
mark('code/didInitWorkspaceConfiguration');
}
private async initializeApplicationConfiguration(): Promise<ConfigurationModel> {
return this.applicationConfiguration ? this.applicationConfiguration.initialize() : Promise.resolve(new ConfigurationModel());
}
private async initializeUserConfiguration(): Promise<{ local: ConfigurationModel; remote: ConfigurationModel }> {
const [local, remote] = await Promise.all([this.localUserConfiguration.initialize(), this.remoteUserConfiguration ? this.remoteUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel())]);
return { local, remote };
@ -603,6 +624,17 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
this.onDefaultConfigurationChanged(this.defaultConfiguration.reload());
}
private async reloadApplicationConfiguration(donotTrigger?: boolean): Promise<ConfigurationModel> {
if (!this.applicationConfiguration) {
return new ConfigurationModel();
}
const model = await this.applicationConfiguration.reload();
if (!donotTrigger) {
this.onApplicationConfigurationChanged(model);
}
return model;
}
private async reloadUserConfiguration(): Promise<{ local: ConfigurationModel; remote: ConfigurationModel }> {
const [local, remote] = await Promise.all([this.reloadLocalUserConfiguration(true), this.reloadRemoteUserConfiguration(true)]);
return { local, remote };
@ -641,7 +673,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
return this.onWorkspaceFolderConfigurationChanged(folder);
}
private async loadConfiguration(userConfigurationModel: ConfigurationModel, remoteUserConfigurationModel: ConfigurationModel): Promise<void> {
private async loadConfiguration(applicationConfigurationModel: ConfigurationModel, userConfigurationModel: ConfigurationModel, remoteUserConfigurationModel: ConfigurationModel): Promise<void> {
// reset caches
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
@ -653,7 +685,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
const currentConfiguration = this._configuration;
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
this._configuration = new Configuration(this.defaultConfiguration.configurationModel, this.policyConfiguration.configurationModel, applicationConfigurationModel, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
if (this.initialized) {
const change = this._configuration.compare(currentConfiguration);
@ -677,6 +709,21 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
}
}
private onUserDataProfileChanged(e: DidChangeUserDataProfileEvent): void {
const promises: Promise<ConfigurationModel>[] = [];
promises.push(this.localUserConfiguration.reset(e.profile.settingsResource, e.profile.tasksResource, getLocalUserConfigurationScopes(e.profile, !!this.remoteUserConfiguration)));
if (e.previous.isDefault !== e.profile.isDefault) {
this.createApplicationConfiguration();
if (this.applicationConfiguration) {
promises.push(this.reloadApplicationConfiguration(true));
}
}
e.join((async () => {
const [localUser, application] = await Promise.all(promises);
await this.loadConfiguration(application ?? this._configuration.applicationConfiguration, localUser, this._configuration.remoteUserConfiguration);
})());
}
private onDefaultConfigurationChanged(configurationModel: ConfigurationModel, properties?: string[]): void {
if (this.workspace) {
const previousData = this._configuration.toData();
@ -711,6 +758,12 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
this.triggerConfigurationChange(change, previous, ConfigurationTarget.DEFAULT);
}
private onApplicationConfigurationChanged(applicationConfiguration: ConfigurationModel): void {
const previous = { data: this._configuration.toData(), workspace: this.workspace };
const change = this._configuration.compareAndUpdateApplicationConfiguration(applicationConfiguration);
this.triggerConfigurationChange(change, previous, ConfigurationTarget.USER);
}
private onLocalUserConfigurationChanged(userConfiguration: ConfigurationModel): void {
const previous = { data: this._configuration.toData(), workspace: this.workspace };
const change = this._configuration.compareAndUpdateLocalUserConfiguration(userConfiguration);
@ -916,7 +969,12 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
await this.configurationEditingService.writeConfiguration(editableConfigurationTarget, { key, value }, { scopes: overrides, donotNotifyError });
switch (editableConfigurationTarget) {
case EditableConfigurationTarget.USER_LOCAL:
return this.reloadLocalUserConfiguration().then(() => undefined);
if (this.applicationConfiguration && this.configurationRegistry.getConfigurationProperties()[key].scope === ConfigurationScope.APPLICATION) {
await this.reloadApplicationConfiguration();
} else {
await this.reloadLocalUserConfiguration();
}
return;
case EditableConfigurationTarget.USER_REMOTE:
return this.reloadRemoteUserConfiguration().then(() => undefined);
case EditableConfigurationTarget.WORKSPACE:
@ -1049,6 +1107,19 @@ class RegisterConfigurationSchemasContribution extends Disposable implements IWo
}
: allSettingsSchema;
const profileSettingsSchema: IJSONSchema = {
properties: {
...machineSettings.properties,
...machineOverridableSettings.properties,
...windowSettings.properties,
...resourceSettings.properties
},
patternProperties: allSettings.patternProperties,
additionalProperties: true,
allowTrailingCommas: true,
allowComments: true
};
const machineSettingsSchema: IJSONSchema = {
properties: {
...machineSettings.properties,
@ -1094,6 +1165,7 @@ class RegisterConfigurationSchemasContribution extends Disposable implements IWo
allowComments: true
});
jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema);
jsonRegistry.registerSchema(profileSettingsSchemaId, profileSettingsSchema);
jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema);
if (WorkbenchState.WORKSPACE === this.workspaceContextService.getWorkbenchState()) {

View file

@ -17,13 +17,16 @@ export const FOLDER_SETTINGS_PATH = `${FOLDER_CONFIG_FOLDER_NAME}/${FOLDER_SETTI
export const defaultSettingsSchemaId = 'vscode://schemas/settings/default';
export const userSettingsSchemaId = 'vscode://schemas/settings/user';
export const profileSettingsSchemaId = 'vscode://schemas/settings/profile';
export const machineSettingsSchemaId = 'vscode://schemas/settings/machine';
export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace';
export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
export const launchSchemaId = 'vscode://schemas/launch';
export const tasksSchemaId = 'vscode://schemas/tasks';
export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE];
export const PROFILE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE];
export const LOCAL_MACHINE_PROFILE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE];
export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ...LOCAL_MACHINE_PROFILE_SCOPES];
export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];
export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE, ConfigurationScope.MACHINE_OVERRIDABLE];

View file

@ -576,7 +576,7 @@ export class ConfigurationEditingService {
const standaloneConfigurationMap = target === EditableConfigurationTarget.USER_LOCAL ? USER_STANDALONE_CONFIGURATIONS : WORKSPACE_STANDALONE_CONFIGURATIONS;
const standaloneConfigurationKeys = Object.keys(standaloneConfigurationMap);
for (const key of standaloneConfigurationKeys) {
const resource = this.getConfigurationFileResource(target, key, standaloneConfigurationMap[key], overrides.resource);
const resource = this.getConfigurationFileResource(target, key, standaloneConfigurationMap[key], overrides.resource, undefined);
// Check for prefix
if (config.key === key) {
@ -594,12 +594,14 @@ export class ConfigurationEditingService {
}
const key = config.key;
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
const configurationScope = configurationProperties[key]?.scope;
let jsonPath = overrides.overrideIdentifiers?.length ? [keyFromOverrideIdentifiers(overrides.overrideIdentifiers), key] : [key];
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, undefined, '', null)), target };
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, undefined, '', null, configurationScope)), target };
}
const resource = this.getConfigurationFileResource(target, undefined, FOLDER_SETTINGS_PATH, overrides.resource);
const resource = this.getConfigurationFileResource(target, undefined, FOLDER_SETTINGS_PATH, overrides.resource, configurationScope);
if (this.isWorkspaceConfigurationResource(resource)) {
jsonPath = ['settings', ...jsonPath];
}
@ -611,11 +613,14 @@ export class ConfigurationEditingService {
return !!(workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath);
}
private getConfigurationFileResource(target: EditableConfigurationTarget, standAloneConfigurationKey: string | undefined, relativePath: string, resource: URI | null | undefined): URI | null {
private getConfigurationFileResource(target: EditableConfigurationTarget, standAloneConfigurationKey: string | undefined, relativePath: string, resource: URI | null | undefined, scope: ConfigurationScope | undefined): URI | null {
if (target === EditableConfigurationTarget.USER_LOCAL) {
if (standAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return this.userDataProfileService.currentProfile.tasksResource;
} else {
if (scope === ConfigurationScope.APPLICATION && !this.userDataProfileService.currentProfile.isDefault) {
return this.userDataProfileService.defaultProfile.settingsResource;
}
return this.userDataProfileService.currentProfile.settingsResource;
}
}

View file

@ -99,6 +99,7 @@ export class Configuration extends BaseConfiguration {
constructor(
defaults: ConfigurationModel,
policy: ConfigurationModel,
application: ConfigurationModel,
localUser: ConfigurationModel,
remoteUser: ConfigurationModel,
workspaceConfiguration: ConfigurationModel,
@ -106,7 +107,7 @@ export class Configuration extends BaseConfiguration {
memoryConfiguration: ConfigurationModel,
memoryConfigurationByResource: ResourceMap<ConfigurationModel>,
private readonly _workspace?: Workspace) {
super(defaults, policy, localUser, remoteUser, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource);
super(defaults, policy, application, localUser, remoteUser, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource);
}
override getValue(key: string | undefined, overrides: IConfigurationOverrides = {}): any {

View file

@ -68,7 +68,7 @@ export class ConfigurationCache implements IConfigurationCache {
const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });
function aUserDataProfileService(environmentService: IEnvironmentService): IUserDataProfileService {
const profile = toUserDataProfile('temp', environmentService.userRoamingDataHome);
const profile = { ...toUserDataProfile('temp', environmentService.userRoamingDataHome), isDefault: true };
return new UserDataProfileService(profile, profile);
}
@ -683,7 +683,7 @@ suite('WorkspaceService - Initialization', () => {
suite('WorkspaceConfigurationService - Folder', () => {
let testObject: WorkspaceService, workspaceService: WorkspaceService, fileService: IFileService, environmentService: IWorkbenchEnvironmentService, userDataProfileService: IUserDataProfileService;
let testObject: WorkspaceService, workspaceService: WorkspaceService, fileService: IFileService, environmentService: IWorkbenchEnvironmentService, userDataProfileService: IUserDataProfileService, instantiationService: TestInstantiationService;
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
const disposables: DisposableStore = new DisposableStore();
@ -751,7 +751,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
const folder = joinPath(ROOT, 'a');
await fileService.createFolder(folder);
const instantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);
instantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);
environmentService = TestEnvironmentService;
environmentService.policyFile = joinPath(folder, 'policies.json');
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, null);
@ -1028,6 +1028,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
test('inspect', async () => {
let actual = testObject.inspect('something.missing');
assert.strictEqual(actual.defaultValue, undefined);
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
@ -1035,6 +1036,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
actual = testObject.inspect('configurationService.folder.testSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
@ -1044,6 +1046,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
await testObject.reloadConfiguration();
actual = testObject.inspect('configurationService.folder.testSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, 'userValue');
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
@ -1053,6 +1056,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
await testObject.reloadConfiguration();
actual = testObject.inspect('configurationService.folder.testSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, 'userValue');
assert.strictEqual(actual.workspaceValue, 'workspaceValue');
assert.strictEqual(actual.workspaceFolderValue, undefined);
@ -1370,6 +1374,164 @@ suite('WorkspaceConfigurationService - Folder', () => {
});
});
suite('WorkspaceConfigurationService - Profiles', () => {
let testObject: WorkspaceService, workspaceService: WorkspaceService, fileService: IFileService, environmentService: IWorkbenchEnvironmentService, userDataProfileService: IUserDataProfileService, instantiationService: TestInstantiationService;
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
const disposables: DisposableStore = new DisposableStore();
suiteSetup(() => {
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'configurationService.profiles.applicationSetting': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.APPLICATION
},
'configurationService.profiles.testSetting': {
'type': 'string',
'default': 'isSet',
},
'configurationService.profiles.applicationSetting2': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.APPLICATION
},
'configurationService.profiles.testSetting2': {
'type': 'string',
'default': 'isSet',
},
}
});
});
setup(async () => {
const logService = new NullLogService();
fileService = disposables.add(new FileService(logService));
const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());
fileService.registerProvider(ROOT.scheme, fileSystemProvider);
const folder = joinPath(ROOT, 'a');
await fileService.createFolder(folder);
instantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);
environmentService = TestEnvironmentService;
environmentService.policyFile = joinPath(folder, 'policies.json');
const remoteAgentService = instantiationService.createInstance(RemoteAgentService, null);
instantiationService.stub(IRemoteAgentService, remoteAgentService);
fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService())));
userDataProfileService = new UserDataProfileService({ ...toUserDataProfile('default', environmentService.userRoamingDataHome), isDefault: true }, toUserDataProfile('custom', joinPath(environmentService.userRoamingDataHome, 'profiles', 'temp')));
instantiationService.stub(IUserDataProfileService, userDataProfileService);
workspaceService = testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new FilePolicyService(environmentService.policyFile, fileService, logService)));
instantiationService.stub(IFileService, fileService);
instantiationService.stub(IWorkspaceContextService, testObject);
instantiationService.stub(IConfigurationService, testObject);
instantiationService.stub(IEnvironmentService, environmentService);
await fileService.writeFile(userDataProfileService.defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting2": "applicationValue", "configurationService.profiles.testSetting2": "userValue" }'));
await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting2": "profileValue", "configurationService.profiles.testSetting2": "profileValue" }'));
await workspaceService.initialize(convertToWorkspacePayload(folder));
instantiationService.stub(IKeybindingEditingService, instantiationService.createInstance(KeybindingsEditingService));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.acquireInstantiationService(instantiationService);
});
teardown(() => disposables.clear());
test('initialize', async () => {
assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting2'), 'applicationValue');
assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting2'), 'profileValue');
});
test('inspect', async () => {
let actual = testObject.inspect('something.missing');
assert.strictEqual(actual.defaultValue, undefined);
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(actual.value, undefined);
actual = testObject.inspect('configurationService.profiles.applicationSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.application, undefined);
assert.strictEqual(actual.userValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(actual.value, 'isSet');
await fileService.writeFile(userDataProfileService.defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "applicationValue" }'));
await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue" }'));
await testObject.reloadConfiguration();
actual = testObject.inspect('configurationService.profiles.applicationSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.applicationValue, 'applicationValue');
assert.strictEqual(actual.userValue, undefined);
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(actual.value, 'applicationValue');
await fileService.writeFile(userDataProfileService.defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.testSetting": "applicationValue" }'));
await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.testSetting": "profileValue" }'));
await testObject.reloadConfiguration();
actual = testObject.inspect('configurationService.profiles.testSetting');
assert.strictEqual(actual.defaultValue, 'isSet');
assert.strictEqual(actual.applicationValue, undefined);
assert.strictEqual(actual.userValue, 'profileValue');
assert.strictEqual(actual.workspaceValue, undefined);
assert.strictEqual(actual.workspaceFolderValue, undefined);
assert.strictEqual(actual.value, 'profileValue');
});
test('update application scope setting', async () => {
await testObject.updateValue('configurationService.profiles.applicationSetting', 'applicationValue');
assert.deepStrictEqual(JSON.parse((await fileService.readFile(userDataProfileService.defaultProfile.settingsResource)).value.toString()), { 'configurationService.profiles.applicationSetting': 'applicationValue', 'configurationService.profiles.applicationSetting2': 'applicationValue', 'configurationService.profiles.testSetting2': 'userValue' });
assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue');
});
test('update normal setting', async () => {
await testObject.updateValue('configurationService.profiles.testSetting', 'profileValue');
assert.deepStrictEqual(JSON.parse((await fileService.readFile(userDataProfileService.currentProfile.settingsResource)).value.toString()), { 'configurationService.profiles.testSetting': 'profileValue', 'configurationService.profiles.testSetting2': 'profileValue', 'configurationService.profiles.applicationSetting2': 'profileValue' });
assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'profileValue');
});
test('switch to default profile', async () => {
await fileService.writeFile(userDataProfileService.defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "applicationValue", "configurationService.profiles.testSetting": "userValue" }'));
await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue", "configurationService.profiles.testSetting": "profileValue" }'));
await testObject.reloadConfiguration();
const promise = Event.toPromise(testObject.onDidChangeConfiguration);
await userDataProfileService.updateCurrentProfile(userDataProfileService.defaultProfile, false);
const changeEvent = await promise;
assert.deepStrictEqual(changeEvent.affectedKeys, ['configurationService.profiles.testSetting']);
assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue');
assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'userValue');
});
test('switch to non default profile', async () => {
await fileService.writeFile(userDataProfileService.defaultProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "applicationValue", "configurationService.profiles.testSetting": "userValue" }'));
await fileService.writeFile(userDataProfileService.currentProfile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue", "configurationService.profiles.testSetting": "profileValue" }'));
await testObject.reloadConfiguration();
const profile = toUserDataProfile('custom2', joinPath(environmentService.userRoamingDataHome, 'profiles', 'custom2'));
await fileService.writeFile(profile.settingsResource, VSBuffer.fromString('{ "configurationService.profiles.applicationSetting": "profileValue2", "configurationService.profiles.testSetting": "profileValue2" }'));
const promise = Event.toPromise(testObject.onDidChangeConfiguration);
await userDataProfileService.updateCurrentProfile(profile, false);
const changeEvent = await promise;
assert.deepStrictEqual(changeEvent.affectedKeys, ['configurationService.profiles.testSetting']);
assert.strictEqual(testObject.getValue('configurationService.profiles.applicationSetting'), 'applicationValue');
assert.strictEqual(testObject.getValue('configurationService.profiles.testSetting'), 'profileValue2');
});
});
suite('WorkspaceConfigurationService-Multiroot', () => {
let workspaceContextService: IWorkspaceContextService, jsonEditingServce: IJSONEditingService, testObject: WorkspaceService, fileService: IFileService, environmentService: BrowserWorkbenchEnvironmentService, userDataProfileService: IUserDataProfileService;

View file

@ -155,14 +155,14 @@ suite('Workspace Configuration', () => {
test('Test compare same configurations', () => {
const workspace = new Workspace('a', [new WorkspaceFolder({ index: 0, name: 'a', uri: URI.file('folder1') }), new WorkspaceFolder({ index: 1, name: 'b', uri: URI.file('folder2') }), new WorkspaceFolder({ index: 2, name: 'c', uri: URI.file('folder3') })]);
const configuration1 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
const configuration1 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
configuration1.updateDefaultConfiguration(defaultConfigurationModel);
configuration1.updateLocalUserConfiguration(toConfigurationModel({ 'window.title': 'native', '[typescript]': { 'editor.insertSpaces': false } }));
configuration1.updateWorkspaceConfiguration(toConfigurationModel({ 'editor.lineNumbers': 'on' }));
configuration1.updateFolderConfiguration(URI.file('folder1'), toConfigurationModel({ 'editor.fontSize': 14 }));
configuration1.updateFolderConfiguration(URI.file('folder2'), toConfigurationModel({ 'editor.wordWrap': 'on' }));
const configuration2 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
const configuration2 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
configuration2.updateDefaultConfiguration(defaultConfigurationModel);
configuration2.updateLocalUserConfiguration(toConfigurationModel({ 'window.title': 'native', '[typescript]': { 'editor.insertSpaces': false } }));
configuration2.updateWorkspaceConfiguration(toConfigurationModel({ 'editor.lineNumbers': 'on' }));
@ -176,14 +176,14 @@ suite('Workspace Configuration', () => {
test('Test compare different configurations', () => {
const workspace = new Workspace('a', [new WorkspaceFolder({ index: 0, name: 'a', uri: URI.file('folder1') }), new WorkspaceFolder({ index: 1, name: 'b', uri: URI.file('folder2') }), new WorkspaceFolder({ index: 2, name: 'c', uri: URI.file('folder3') })]);
const configuration1 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
const configuration1 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
configuration1.updateDefaultConfiguration(defaultConfigurationModel);
configuration1.updateLocalUserConfiguration(toConfigurationModel({ 'window.title': 'native', '[typescript]': { 'editor.insertSpaces': false } }));
configuration1.updateWorkspaceConfiguration(toConfigurationModel({ 'editor.lineNumbers': 'on' }));
configuration1.updateFolderConfiguration(URI.file('folder1'), toConfigurationModel({ 'editor.fontSize': 14 }));
configuration1.updateFolderConfiguration(URI.file('folder2'), toConfigurationModel({ 'editor.wordWrap': 'on' }));
const configuration2 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
const configuration2 = new Configuration(new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), workspace);
configuration2.updateDefaultConfiguration(defaultConfigurationModel);
configuration2.updateLocalUserConfiguration(toConfigurationModel({ 'workbench.enableTabs': true, '[typescript]': { 'editor.insertSpaces': true } }));
configuration2.updateWorkspaceConfiguration(toConfigurationModel({ 'editor.fontSize': 11 }));

View file

@ -100,6 +100,9 @@ export class UserDataProfileManagementService extends Disposable implements IUse
if (!this.userDataProfilesService.profiles.some(p => p.id === profile.id)) {
throw new Error(`Profile ${profile.name} does not exist`);
}
if (this.userDataProfileService.currentProfile.id === profile.id) {
return;
}
await this.userDataProfilesService.setProfileForWorkspace(profile, workspaceIdentifier);
await this.enterProfile(profile, false);
}

View file

@ -12,6 +12,7 @@ import { IUserDataProfile, UseDefaultProfileFlags } from 'vs/platform/userDataPr
export interface DidChangeUserDataProfileEvent {
readonly preserveData: boolean;
readonly previous: IUserDataProfile;
readonly profile: IUserDataProfile;
join(promise: Promise<void>): void;
}

View file

@ -31,10 +31,15 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi
}
async updateCurrentProfile(userDataProfile: IUserDataProfile, preserveData: boolean): Promise<void> {
if (this._currentProfile.id === userDataProfile.id) {
return;
}
const previous = this._currentProfile;
this._currentProfile = userDataProfile;
const joiners: Promise<void>[] = [];
this._onDidChangeCurrentProfile.fire({
preserveData,
previous,
profile: userDataProfile,
join(promise) {
joiners.push(promise);