Skip to content

Commit

Permalink
#51935 support updating configuration for multiple language identifie…
Browse files Browse the repository at this point in the history
…rs in configuration service
  • Loading branch information
sandy081 committed Nov 16, 2021
1 parent 7131e48 commit f647097
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 75 deletions.
18 changes: 12 additions & 6 deletions src/vs/platform/configuration/common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ export interface IConfigurationOverrides {
resource?: URI | null;
}

export function isConfigurationUpdateOverrides(thing: any): thing is IConfigurationUpdateOverrides {
return thing
&& typeof thing === 'object'
&& (!thing.overrideIdentifiers || types.isArray(thing.overrideIdentifiers))
&& !thing.overrideIdentifier
&& (!thing.resource || thing.resource instanceof URI);
}

export type IConfigurationUpdateOverrides = Omit<IConfigurationOverrides, 'overrideIdentifier'> & { overrideIdentifiers?: string[] | null; };

export const enum ConfigurationTarget {
USER = 1,
USER_LOCAL,
Expand Down Expand Up @@ -106,9 +116,9 @@ export interface IConfigurationService {
getValue<T>(section: string, overrides: IConfigurationOverrides): T;

updateValue(key: string, value: any): Promise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides): Promise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides): Promise<void>;
updateValue(key: string, value: any, target: ConfigurationTarget): Promise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError?: boolean): Promise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides, target: ConfigurationTarget, donotNotifyError?: boolean): Promise<void>;

inspect<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<Readonly<T>>;

Expand Down Expand Up @@ -269,10 +279,6 @@ export function getDefaultValues(): any {
return valueTreeRoot;
}

export function keyFromOverrideIdentifier(overrideIdentifier: string): string {
return `[${overrideIdentifier}]`;
}

export function getMigratedSettingValue<T>(configurationService: IConfigurationService, currentSettingName: string, legacySettingName: string): T {
const setting = configurationService.inspect<T>(currentSettingName);
const legacySetting = configurationService.inspect<T>(legacySettingName);
Expand Down
12 changes: 6 additions & 6 deletions src/vs/platform/configuration/common/configurationModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import * as objects from 'vs/base/common/objects';
import { IExtUri } from 'vs/base/common/resources';
import * as types from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { addToValueTree, ConfigurationTarget, getConfigurationKeys, getConfigurationValue, getDefaultValues, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationValue, IOverrides, removeFromValueTree, toValuesTree } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { addToValueTree, ConfigurationTarget, getConfigurationKeys, getConfigurationValue, getDefaultValues, IConfigurationChange, IConfigurationChangeEvent, IConfigurationCompareResult, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationUpdateOverrides, IConfigurationValue, IOverrides, removeFromValueTree, toValuesTree } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
import { IFileService } from 'vs/platform/files/common/files';
import { Registry } from 'vs/platform/registry/common/platform';
import { Workspace } from 'vs/platform/workspace/common/workspace';
Expand Down Expand Up @@ -239,7 +239,7 @@ export class DefaultConfigurationModel extends ConfigurationModel {
const keys = getConfigurationKeys();
const overrides: IOverrides[] = [];
for (const key of Object.keys(contents)) {
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
overrides.push({
identifiers: overrideIdentifiersFromKey(key),
keys: Object.keys(contents[key]),
Expand Down Expand Up @@ -371,7 +371,7 @@ export class ConfigurationModelParser {
const raw: any = {};
const restricted: string[] = [];
for (let key in properties) {
if (OVERRIDE_PROPERTY_PATTERN.test(key) && filterOverriddenProperties) {
if (OVERRIDE_PROPERTY_REGEX.test(key) && filterOverriddenProperties) {
const result = this.filter(properties[key], configurationProperties, false, options);
raw[key] = result.raw;
restricted.push(...result.restricted);
Expand All @@ -395,7 +395,7 @@ export class ConfigurationModelParser {
private toOverrides(raw: any, conflictReporter: (message: string) => void): IOverrides[] {
const overrides: IOverrides[] = [];
for (const key of Object.keys(raw)) {
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
const overrideRaw: any = {};
for (const keyInOverrideRaw in raw[key]) {
overrideRaw[keyInOverrideRaw] = raw[key][keyInOverrideRaw];
Expand Down Expand Up @@ -476,7 +476,7 @@ export class Configuration {
return consolidateConfigurationModel.getValue(section);
}

updateValue(key: string, value: any, overrides: IConfigurationOverrides = {}): void {
updateValue(key: string, value: any, overrides: IConfigurationUpdateOverrides = {}): void {
let memoryConfiguration: ConfigurationModel | undefined;
if (overrides.resource) {
memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource);
Expand Down
39 changes: 21 additions & 18 deletions src/vs/platform/configuration/common/configurationRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
for (const key in defaultConfiguration) {
properties.push(key);

if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
this.defaultValues[key] = { ...(this.defaultValues[key] || {}), ...defaultConfiguration[key] };
const property: IConfigurationPropertySchema = {
type: 'object',
Expand Down Expand Up @@ -291,7 +291,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
for (const key in defaultConfiguration) {
properties.push(key);
delete this.defaultValues[key];
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
delete this.configurationProperties[key];
delete this.defaultLanguageConfigurationOverridesNode.properties![key];
} else {
Expand Down Expand Up @@ -371,7 +371,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
this.updatePropertyDefaultValue(key, property);

// update scope
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
property.scope = undefined; // No scope for overridable properties `[${identifier}]`
} else {
property.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;
Expand Down Expand Up @@ -507,12 +507,12 @@ class ConfigurationRegistry implements IConfigurationRegistry {
errorMessage: nls.localize('overrideSettings.errorMessage', "This setting does not support per-language configuration."),
$ref: resourceLanguageSettingsSchemaId,
};
allSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
applicationSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
machineSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
machineOverridableSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
windowSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
resourceSettings.patternProperties[OVERRIDE_PROPERTY] = resourceLanguagePropertiesSchema;
allSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
applicationSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
machineSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
machineOverridableSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
windowSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
resourceSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
this._onDidSchemaChange.fire();
}

Expand All @@ -528,26 +528,30 @@ class ConfigurationRegistry implements IConfigurationRegistry {
}
}

const OVERRIDE_IDENTIFIER = `\\[([^\\]]+)\\]`;
const OVERRIDE_IDENTIFIER_PATTERN = new RegExp(OVERRIDE_IDENTIFIER, 'g');
export const OVERRIDE_PROPERTY = `^(${OVERRIDE_IDENTIFIER})+$`;
export const OVERRIDE_PROPERTY_PATTERN = new RegExp(OVERRIDE_PROPERTY);
const OVERRIDE_IDENTIFIER_PATTERN = `\\[([^\\]]+)\\]`;
const OVERRIDE_IDENTIFIER_REGEX = new RegExp(OVERRIDE_IDENTIFIER_PATTERN, 'g');
export const OVERRIDE_PROPERTY_PATTERN = `^(${OVERRIDE_IDENTIFIER_PATTERN})+$`;
export const OVERRIDE_PROPERTY_REGEX = new RegExp(OVERRIDE_PROPERTY_PATTERN);

export function overrideIdentifiersFromKey(key: string): string[] {
const identifiers: string[] = [];
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
let matches = OVERRIDE_IDENTIFIER_PATTERN.exec(key);
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
let matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
while (matches?.length) {
const identifier = matches[1].trim();
if (identifier) {
identifiers.push(identifier);
}
matches = OVERRIDE_IDENTIFIER_PATTERN.exec(key);
matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
}
}
return distinct(identifiers);
}

export function keyFromOverrideIdentifiers(overrideIdentifiers: string[]): string {
return overrideIdentifiers.reduce((result, overrideIdentifier) => `${result}[${overrideIdentifier}]`, '');
}

export function getDefaultValue(type: string | string[] | undefined): any {
const t = Array.isArray(type) ? (<string[]>type)[0] : <string>type;
switch (t) {
Expand All @@ -567,15 +571,14 @@ export function getDefaultValue(type: string | string[] | undefined): any {
}
}


const configurationRegistry = new ConfigurationRegistry();
Registry.add(Extensions.Configuration, configurationRegistry);

export function validateProperty(property: string): string | null {
if (!property.trim()) {
return nls.localize('config.property.empty', "Cannot register an empty property");
}
if (OVERRIDE_PROPERTY_PATTERN.test(property)) {
if (OVERRIDE_PROPERTY_REGEX.test(property)) {
return nls.localize('config.property.languageDefault', "Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.", property);
}
if (configurationRegistry.getConfigurationProperties()[property] !== undefined) {
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/api/common/configurationExtensionPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as objects from 'vs/base/common/objects';
import { Registry } from 'vs/platform/registry/common/platform';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN, OVERRIDE_PROPERTY } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { isObject } from 'vs/base/common/types';
Expand Down Expand Up @@ -110,7 +110,7 @@ const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<I
description: nls.localize('vscode.extension.contributes.defaultConfiguration', 'Contributes default editor configuration settings by language.'),
type: 'object',
patternProperties: {
[OVERRIDE_PROPERTY]: {
[OVERRIDE_PROPERTY_PATTERN]: {
type: 'object',
default: {},
$ref: resourceLanguageSettingsSchemaId,
Expand All @@ -129,7 +129,7 @@ defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
const addedDefaultConfigurations = added.map<IStringDictionary<any>>(extension => {
const defaults: IStringDictionary<any> = objects.deepClone(extension.value);
for (const key of Object.keys(defaults)) {
if (!OVERRIDE_PROPERTY_PATTERN.test(key) || typeof defaults[key] !== 'object') {
if (!OVERRIDE_PROPERTY_REGEX.test(key) || typeof defaults[key] !== 'object') {
extension.collector.warn(nls.localize('config.property.defaultConfiguration.warning', "Cannot register configuration defaults for '{0}'. Only defaults for language specific settings are supported.", key));
delete defaults[key];
}
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/common/extHostConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ExtHostConfigurationShape, MainThreadConfigurationShape, IConfiguration
import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes';
import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { Configuration, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationScope, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { ConfigurationScope, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
import { isObject } from 'vs/base/common/types';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { Barrier } from 'vs/base/common/async';
Expand Down Expand Up @@ -297,7 +297,7 @@ export class ExtHostConfigProvider {
}

private _validateConfigurationAccess(key: string, overrides?: IConfigurationOverrides, extensionId?: ExtensionIdentifier): void {
const scope = OVERRIDE_PROPERTY_PATTERN.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes.get(key);
const scope = OVERRIDE_PROPERTY_REGEX.test(key) ? ConfigurationScope.RESOURCE : this._configurationScopes.get(key);
const extensionIdText = extensionId ? `[${extensionId.value}] ` : '';
if (ConfigurationScope.RESOURCE === scope) {
if (typeof overrides?.resource === 'undefined') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import * as modes from 'vs/editor/common/modes';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
import * as nls from 'vs/nls';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IMarkerData, IMarkerService, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
Expand Down Expand Up @@ -76,9 +76,9 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
}

updatePreference(key: string, value: any, source: IIndexedSetting): void {
const overrideIdentifier = source.overrideOf ? source.overrideOf.key.substring(1, source.overrideOf.key.length - 1) : null;
const overrideIdentifiers = source.overrideOf ? overrideIdentifiersFromKey(source.overrideOf.key) : null;
const resource = this.preferencesModel.uri;
this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget)
this.configurationService.updateValue(key, value, { overrideIdentifiers, resource }, this.preferencesModel.configurationTarget)
.then(() => this.onSettingUpdated(source));
}

Expand Down Expand Up @@ -533,7 +533,7 @@ class UnsupportedSettingsRenderer extends Disposable implements modes.CodeAction
this.handleWorkspaceFolderConfiguration(setting, configuration, markerData);
break;
}
} else if (!OVERRIDE_PROPERTY_PATTERN.test(setting.key)) { // Ignore override settings (language specific settings)
} else if (!OVERRIDE_PROPERTY_REGEX.test(setting.key)) { // Ignore override settings (language specific settings)
markerData.push({
severity: MarkerSeverity.Hint,
tags: [MarkerTag.Unnecessary],
Expand Down
Loading

0 comments on commit f647097

Please sign in to comment.