Path: blob/main/src/vs/workbench/services/configuration/common/configurationModels.ts
5241 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { equals } from '../../../../base/common/objects.js';6import { toValuesTree, IConfigurationModel, IConfigurationOverrides, IConfigurationValue, IConfigurationChange } from '../../../../platform/configuration/common/configuration.js';7import { Configuration as BaseConfiguration, ConfigurationModelParser, ConfigurationModel, ConfigurationParseOptions } from '../../../../platform/configuration/common/configurationModels.js';8import { IStoredWorkspaceFolder } from '../../../../platform/workspaces/common/workspaces.js';9import { Workspace } from '../../../../platform/workspace/common/workspace.js';10import { ResourceMap } from '../../../../base/common/map.js';11import { URI } from '../../../../base/common/uri.js';12import { isBoolean } from '../../../../base/common/types.js';13import { distinct } from '../../../../base/common/arrays.js';14import { ILogService } from '../../../../platform/log/common/log.js';15import { IStringDictionary } from '../../../../base/common/collections.js';1617export class WorkspaceConfigurationModelParser extends ConfigurationModelParser {1819private _folders: IStoredWorkspaceFolder[] = [];20private _transient: boolean = false;21private _settingsModelParser: ConfigurationModelParser;22private _launchModel: ConfigurationModel;23private _tasksModel: ConfigurationModel;2425constructor(name: string, logService: ILogService) {26super(name, logService);27this._settingsModelParser = new ConfigurationModelParser(name, logService);28this._launchModel = ConfigurationModel.createEmptyModel(logService);29this._tasksModel = ConfigurationModel.createEmptyModel(logService);30}3132get folders(): IStoredWorkspaceFolder[] {33return this._folders;34}3536get transient(): boolean {37return this._transient;38}3940get settingsModel(): ConfigurationModel {41return this._settingsModelParser.configurationModel;42}4344get launchModel(): ConfigurationModel {45return this._launchModel;46}4748get tasksModel(): ConfigurationModel {49return this._tasksModel;50}5152reparseWorkspaceSettings(configurationParseOptions: ConfigurationParseOptions): void {53this._settingsModelParser.reparse(configurationParseOptions);54}5556getRestrictedWorkspaceSettings(): string[] {57return this._settingsModelParser.restrictedConfigurations;58}5960protected override doParseRaw(raw: IStringDictionary<unknown>, configurationParseOptions?: ConfigurationParseOptions): IConfigurationModel {61this._folders = (raw['folders'] || []) as IStoredWorkspaceFolder[];62this._transient = isBoolean(raw['transient']) && raw['transient'];63this._settingsModelParser.parseRaw(raw['settings'] as IStringDictionary<unknown>, configurationParseOptions);64this._launchModel = this.createConfigurationModelFrom(raw, 'launch');65this._tasksModel = this.createConfigurationModelFrom(raw, 'tasks');66return super.doParseRaw(raw, configurationParseOptions);67}6869private createConfigurationModelFrom(raw: IStringDictionary<unknown>, key: string): ConfigurationModel {70const data = raw[key] as IStringDictionary<unknown> | undefined;71if (data) {72const contents = toValuesTree(data, message => console.error(`Conflict in settings file ${this._name}: ${message}`));73const scopedContents = Object.create(null);74scopedContents[key] = contents;75const keys = Object.keys(data).map(k => `${key}.${k}`);76return new ConfigurationModel(scopedContents, keys, [], undefined, this.logService);77}78return ConfigurationModel.createEmptyModel(this.logService);79}80}8182export class StandaloneConfigurationModelParser extends ConfigurationModelParser {8384constructor(name: string, private readonly scope: string, logService: ILogService,) {85super(name, logService);86}8788protected override doParseRaw(raw: IStringDictionary<unknown>, configurationParseOptions?: ConfigurationParseOptions): IConfigurationModel {89const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));90const scopedContents = Object.create(null);91scopedContents[this.scope] = contents;92const keys = Object.keys(raw).map(key => `${this.scope}.${key}`);93return { contents: scopedContents, keys, overrides: [] };94}9596}9798export class Configuration extends BaseConfiguration {99100constructor(101defaults: ConfigurationModel,102policy: ConfigurationModel,103application: ConfigurationModel,104localUser: ConfigurationModel,105remoteUser: ConfigurationModel,106workspaceConfiguration: ConfigurationModel,107folders: ResourceMap<ConfigurationModel>,108memoryConfiguration: ConfigurationModel,109memoryConfigurationByResource: ResourceMap<ConfigurationModel>,110private readonly _workspace: Workspace | undefined,111logService: ILogService112) {113super(defaults, policy, application, localUser, remoteUser, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource, logService);114}115116override getValue(key: string | undefined, overrides: IConfigurationOverrides = {}): unknown {117return super.getValue(key, overrides, this._workspace);118}119120override inspect<C>(key: string, overrides: IConfigurationOverrides = {}): IConfigurationValue<C> {121return super.inspect(key, overrides, this._workspace);122}123124override keys(): {125default: string[];126policy: string[];127user: string[];128workspace: string[];129workspaceFolder: string[];130} {131return super.keys(this._workspace);132}133134override compareAndDeleteFolderConfiguration(folder: URI): IConfigurationChange {135if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) {136// Do not remove workspace configuration137return { keys: [], overrides: [] };138}139return super.compareAndDeleteFolderConfiguration(folder);140}141142compare(other: Configuration): IConfigurationChange {143const compare = (fromKeys: string[], toKeys: string[], overrideIdentifier?: string): string[] => {144const keys: string[] = [];145keys.push(...toKeys.filter(key => fromKeys.indexOf(key) === -1));146keys.push(...fromKeys.filter(key => toKeys.indexOf(key) === -1));147keys.push(...fromKeys.filter(key => {148// Ignore if the key does not exist in both models149if (toKeys.indexOf(key) === -1) {150return false;151}152// Compare workspace value153if (!equals(this.getValue(key, { overrideIdentifier }), other.getValue(key, { overrideIdentifier }))) {154return true;155}156// Compare workspace folder value157return this._workspace && this._workspace.folders.some(folder => !equals(this.getValue(key, { resource: folder.uri, overrideIdentifier }), other.getValue(key, { resource: folder.uri, overrideIdentifier })));158}));159return keys;160};161const keys = compare(this.allKeys(), other.allKeys());162const overrides: [string, string[]][] = [];163const allOverrideIdentifiers = distinct([...this.allOverrideIdentifiers(), ...other.allOverrideIdentifiers()]);164for (const overrideIdentifier of allOverrideIdentifiers) {165const keys = compare(this.getAllKeysForOverrideIdentifier(overrideIdentifier), other.getAllKeysForOverrideIdentifier(overrideIdentifier), overrideIdentifier);166if (keys.length) {167overrides.push([overrideIdentifier, keys]);168}169}170return { keys, overrides };171}172173}174175176