mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
#51935 support multi lang specific settings
This commit is contained in:
parent
adcda6af72
commit
340338b3b3
|
@ -6,7 +6,7 @@
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Extensions, IConfigurationRegistry, overrideIdentifierFromKey, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -149,24 +149,6 @@ export interface IConfigurationCompareResult {
|
|||
overrides: [string, string[]][];
|
||||
}
|
||||
|
||||
export function toOverrides(raw: any, conflictReporter: (message: string) => void): IOverrides[] {
|
||||
const overrides: IOverrides[] = [];
|
||||
for (const key of Object.keys(raw)) {
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
|
||||
const overrideRaw: any = {};
|
||||
for (const keyInOverrideRaw in raw[key]) {
|
||||
overrideRaw[keyInOverrideRaw] = raw[key][keyInOverrideRaw];
|
||||
}
|
||||
overrides.push({
|
||||
identifiers: [overrideIdentifierFromKey(key).trim()],
|
||||
keys: Object.keys(overrideRaw),
|
||||
contents: toValuesTree(overrideRaw, conflictReporter)
|
||||
});
|
||||
}
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
export function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any {
|
||||
const root = Object.create(null);
|
||||
|
||||
|
|
|
@ -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, toOverrides, toValuesTree } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifierFromKey, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
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 { IFileService } from 'vs/platform/files/common/files';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -241,7 +241,7 @@ export class DefaultConfigurationModel extends ConfigurationModel {
|
|||
for (const key of Object.keys(contents)) {
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
|
||||
overrides.push({
|
||||
identifiers: [overrideIdentifierFromKey(key).trim()],
|
||||
identifiers: overrideIdentifiersFromKey(key),
|
||||
keys: Object.keys(contents[key]),
|
||||
contents: toValuesTree(contents[key], message => console.error(`Conflict in default settings file: ${message}`)),
|
||||
});
|
||||
|
@ -360,7 +360,7 @@ export class ConfigurationModelParser {
|
|||
raw = filtered.raw;
|
||||
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
const keys = Object.keys(raw);
|
||||
const overrides: IOverrides[] = toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
const overrides = this.toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
return { contents, keys, overrides, restricted: filtered.restricted };
|
||||
}
|
||||
|
||||
|
@ -392,6 +392,24 @@ export class ConfigurationModelParser {
|
|||
return { raw, restricted };
|
||||
}
|
||||
|
||||
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)) {
|
||||
const overrideRaw: any = {};
|
||||
for (const keyInOverrideRaw in raw[key]) {
|
||||
overrideRaw[keyInOverrideRaw] = raw[key][keyInOverrideRaw];
|
||||
}
|
||||
overrides.push({
|
||||
identifiers: overrideIdentifiersFromKey(key),
|
||||
keys: Object.keys(overrideRaw),
|
||||
contents: toValuesTree(overrideRaw, conflictReporter)
|
||||
});
|
||||
}
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class UserSettings extends Disposable {
|
||||
|
@ -572,8 +590,7 @@ export class Configuration {
|
|||
compareAndUpdateDefaultConfiguration(defaults: ConfigurationModel, keys: string[]): IConfigurationChange {
|
||||
const overrides: [string, string[]][] = [];
|
||||
for (const key of keys) {
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
|
||||
const overrideIdentifier = overrideIdentifierFromKey(key);
|
||||
for (const overrideIdentifier of overrideIdentifiersFromKey(key)) {
|
||||
const fromKeys = this._defaultConfiguration.getKeysForOverrideIdentifier(overrideIdentifier);
|
||||
const toKeys = defaults.getKeysForOverrideIdentifier(overrideIdentifier);
|
||||
const keys = [
|
||||
|
@ -932,4 +949,3 @@ function compareConfigurationContents(to: { keys: string[], contents: any } | un
|
|||
}
|
||||
return { added, removed, updated };
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
this.excludedConfigurationProperties = {};
|
||||
|
||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||
this.registerOverridePropertyPatternKey();
|
||||
}
|
||||
|
||||
public registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void {
|
||||
|
@ -265,7 +266,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for {0} language.", key),
|
||||
$ref: resourceLanguageSettingsSchemaId
|
||||
};
|
||||
overrideIdentifiers.push(overrideIdentifierFromKey(key));
|
||||
overrideIdentifiers.push(...overrideIdentifiersFromKey(key));
|
||||
this.configurationProperties[key] = property;
|
||||
this.defaultLanguageConfigurationOverridesNode.properties![key] = property;
|
||||
} else {
|
||||
|
@ -499,6 +500,22 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
this._onDidSchemaChange.fire();
|
||||
}
|
||||
|
||||
private registerOverridePropertyPatternKey(): void {
|
||||
const resourceLanguagePropertiesSchema: IJSONSchema = {
|
||||
type: 'object',
|
||||
description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
|
||||
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;
|
||||
this._onDidSchemaChange.fire();
|
||||
}
|
||||
|
||||
private updatePropertyDefaultValue(key: string, property: IConfigurationPropertySchema): void {
|
||||
let defaultValue = this.defaultValues[key];
|
||||
if (types.isUndefined(defaultValue)) {
|
||||
|
@ -511,11 +528,24 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
const OVERRIDE_PROPERTY = '\\[.*\\]$';
|
||||
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);
|
||||
|
||||
export function overrideIdentifierFromKey(key: string): string {
|
||||
return key.substring(1, key.length - 1);
|
||||
export function overrideIdentifiersFromKey(key: string): string[] {
|
||||
const identifiers: string[] = [];
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
|
||||
let matches = OVERRIDE_IDENTIFIER_PATTERN.exec(key);
|
||||
while (matches?.length) {
|
||||
const identifier = matches[1].trim();
|
||||
if (identifier) {
|
||||
identifiers.push(identifier);
|
||||
}
|
||||
matches = OVERRIDE_IDENTIFIER_PATTERN.exec(key);
|
||||
}
|
||||
}
|
||||
return distinct(identifiers);
|
||||
}
|
||||
|
||||
export function getDefaultValue(type: string | string[] | undefined): any {
|
||||
|
|
|
@ -12,6 +12,35 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { Workspace } from 'vs/platform/workspace/test/common/testWorkspace';
|
||||
|
||||
suite('ConfigurationModelParser', () => {
|
||||
|
||||
test('parse configuration model with single override identifier', () => {
|
||||
const testObject = new ConfigurationModelParser('');
|
||||
|
||||
testObject.parse(JSON.stringify({ '[x]': { 'a': 1 } }));
|
||||
|
||||
assert.deepStrictEqual(JSON.stringify(testObject.configurationModel.overrides), JSON.stringify([{ identifiers: ['x'], keys: ['a'], contents: { 'a': 1 } }]));
|
||||
});
|
||||
|
||||
test('parse configuration model with multiple override identifiers', () => {
|
||||
const testObject = new ConfigurationModelParser('');
|
||||
|
||||
testObject.parse(JSON.stringify({ '[x][y]': { 'a': 1 } }));
|
||||
|
||||
assert.deepStrictEqual(JSON.stringify(testObject.configurationModel.overrides), JSON.stringify([{ identifiers: ['x', 'y'], keys: ['a'], contents: { 'a': 1 } }]));
|
||||
});
|
||||
|
||||
test('parse configuration model with multiple duplicate override identifiers', () => {
|
||||
const testObject = new ConfigurationModelParser('');
|
||||
|
||||
testObject.parse(JSON.stringify({ '[x][y][x][z]': { 'a': 1 } }));
|
||||
|
||||
assert.deepStrictEqual(JSON.stringify(testObject.configurationModel.overrides), JSON.stringify([{ identifiers: ['x', 'y', 'z'], keys: ['a'], contents: { 'a': 1 } }]));
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
suite('ConfigurationModel', () => {
|
||||
|
||||
test('setValue for a key that has no sections and not defined', () => {
|
||||
|
@ -621,11 +650,14 @@ suite('ConfigurationChangeEvent', () => {
|
|||
'files.autoSave': 'off',
|
||||
'[markdown]': {
|
||||
'editor.wordWrap': 'off'
|
||||
},
|
||||
'[typescript][jsonc]': {
|
||||
'editor.lineNumbers': 'off'
|
||||
}
|
||||
}));
|
||||
let testObject = new ConfigurationChangeEvent(change, undefined, configuration);
|
||||
|
||||
assert.deepStrictEqual(testObject.affectedKeys, ['files.autoSave', '[markdown]', 'editor.wordWrap']);
|
||||
assert.deepStrictEqual(testObject.affectedKeys, ['files.autoSave', '[markdown]', '[typescript][jsonc]', 'editor.wordWrap', 'editor.lineNumbers']);
|
||||
|
||||
assert.ok(testObject.affectsConfiguration('files'));
|
||||
assert.ok(testObject.affectsConfiguration('files.autoSave'));
|
||||
|
@ -637,8 +669,16 @@ suite('ConfigurationChangeEvent', () => {
|
|||
|
||||
assert.ok(testObject.affectsConfiguration('editor'));
|
||||
assert.ok(testObject.affectsConfiguration('editor.wordWrap'));
|
||||
assert.ok(testObject.affectsConfiguration('editor.lineNumbers'));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'jsonc' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'typescript' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.wordWrap', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.wordWrap', { overrideIdentifier: 'jsonc' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.wordWrap', { overrideIdentifier: 'typescript' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'typescript' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'jsonc' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor', { overrideIdentifier: 'json' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.fontSize', { overrideIdentifier: 'markdown' }));
|
||||
|
||||
|
@ -654,6 +694,10 @@ suite('ConfigurationChangeEvent', () => {
|
|||
'editor.fontSize': 12,
|
||||
'editor.wordWrap': 'off'
|
||||
},
|
||||
'[css][scss]': {
|
||||
'editor.lineNumbers': 'off',
|
||||
'css.lint.emptyRules': 'error'
|
||||
},
|
||||
'files.autoSave': 'off',
|
||||
}));
|
||||
const data = configuration.toData();
|
||||
|
@ -663,11 +707,15 @@ suite('ConfigurationChangeEvent', () => {
|
|||
'editor.fontSize': 13,
|
||||
'editor.wordWrap': 'off'
|
||||
},
|
||||
'[css][scss]': {
|
||||
'editor.lineNumbers': 'relative',
|
||||
'css.lint.emptyRules': 'error'
|
||||
},
|
||||
'window.zoomLevel': 1,
|
||||
}));
|
||||
let testObject = new ConfigurationChangeEvent(change, { data }, configuration);
|
||||
|
||||
assert.deepStrictEqual(testObject.affectedKeys, ['window.zoomLevel', '[markdown]', 'workbench.editor.enablePreview', 'editor.fontSize']);
|
||||
assert.deepStrictEqual(testObject.affectedKeys, ['window.zoomLevel', '[markdown]', '[css][scss]', 'workbench.editor.enablePreview', 'editor.fontSize', 'editor.lineNumbers']);
|
||||
|
||||
assert.ok(!testObject.affectsConfiguration('files'));
|
||||
|
||||
|
@ -676,10 +724,18 @@ suite('ConfigurationChangeEvent', () => {
|
|||
assert.ok(!testObject.affectsConfiguration('[markdown].editor.fontSize'));
|
||||
assert.ok(!testObject.affectsConfiguration('[markdown].editor.wordWrap'));
|
||||
assert.ok(!testObject.affectsConfiguration('[markdown].workbench'));
|
||||
assert.ok(testObject.affectsConfiguration('[css][scss]'));
|
||||
|
||||
assert.ok(testObject.affectsConfiguration('editor'));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'css' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor', { overrideIdentifier: 'scss' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.fontSize', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.fontSize', { overrideIdentifier: 'css' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.fontSize', { overrideIdentifier: 'scss' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'scss' }));
|
||||
assert.ok(testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'css' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.lineNumbers', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.wordWrap'));
|
||||
assert.ok(!testObject.affectsConfiguration('editor.wordWrap', { overrideIdentifier: 'markdown' }));
|
||||
assert.ok(!testObject.affectsConfiguration('editor', { overrideIdentifier: 'json' }));
|
||||
|
|
|
@ -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 } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN, OVERRIDE_PROPERTY } 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';
|
||||
|
@ -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]: {
|
||||
type: 'object',
|
||||
default: {},
|
||||
$ref: resourceLanguageSettingsSchemaId,
|
||||
|
|
|
@ -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, overrideIdentifierFromKey, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, OVERRIDE_PROPERTY_PATTERN } 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';
|
||||
|
@ -76,7 +76,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
|||
}
|
||||
|
||||
updatePreference(key: string, value: any, source: IIndexedSetting): void {
|
||||
const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
|
||||
const overrideIdentifier = source.overrideOf ? source.overrideOf.key.substring(1, source.overrideOf.key.length - 1) : null;
|
||||
const resource = this.preferencesModel.uri;
|
||||
this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget)
|
||||
.then(() => this.onSettingUpdated(source));
|
||||
|
|
Loading…
Reference in a new issue