Skip to content

Commit

Permalink
#19733 Implement default language specific editor settings
Browse files Browse the repository at this point in the history
- Extend configuration extension to override default settings for a language
- Update configuration registry with overrides
- Adopt Defaults config model to read default overrides
- Tests
  • Loading branch information
sandy081 committed Feb 7, 2017
1 parent 9d73ec9 commit 9328bd6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 35 deletions.
88 changes: 56 additions & 32 deletions src/vs/platform/configuration/common/configurationRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export interface IConfigurationNode {
overridable?: boolean;
}

export interface IConfigurationExtension extends IConfigurationNode {
defaults?: any;
}

const schemaId = 'vscode://schemas/settings';
const editorConfigurationSchemaId = 'vscode://schemas/settings/editor';
const contributionRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
Expand All @@ -90,7 +94,6 @@ class ConfigurationRegistry implements IConfigurationRegistry {

contributionRegistry.registerSchema(schemaId, this.configurationSchema);
contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema);
this.registerOverrideSettingsConfiguration();
}

public get onDidRegisterConfiguration() {
Expand All @@ -103,6 +106,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {

public registerConfigurations(configurations: IConfigurationNode[]): void {
configurations.forEach(configuration => {
this.registerDefaultOverrides(configuration); /// fills in default overrides
this.registerProperties(configuration); // fills in defaults
this.configurationContributors.push(configuration);
this.registerJSONConfiguration(configuration);
Expand All @@ -117,6 +121,26 @@ class ConfigurationRegistry implements IConfigurationRegistry {
this.updateOverridePropertyPatternKey();
}

private registerDefaultOverrides(configurationNode: IConfigurationExtension): void {
if (!configurationNode.defaults) {
return;
}

for (const key in configurationNode.defaults) {
if (OVERRIDE_PROPERTY_PATTERN.test(key)) {
if (!configurationNode.properties) {
configurationNode.properties = {};
}
configurationNode.properties[key] = {
type: 'object',
default: configurationNode.defaults[key],
description: nls.localize('overrideSettings.description', "Configure editor settings to be overridden for {0} language.", key),
$ref: editorConfigurationSchemaId
};
}
}
}

private registerProperties(configuration: IConfigurationNode, overridable: boolean = false) {
overridable = configuration.overridable || overridable;
let properties = configuration.properties;
Expand Down Expand Up @@ -166,11 +190,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
subNodes.forEach(register);
}
};
if (configuration.id === SETTINGS_OVERRRIDE_NODE_ID) {
configurationSchema.patternProperties[this.overridePropertyPattern] = objects.clone(configuration.properties['[]']);
} else {
register(configuration);
}
register(configuration);
contributionRegistry.registerSchema(schemaId, configurationSchema);
}

Expand All @@ -182,13 +202,19 @@ class ConfigurationRegistry implements IConfigurationRegistry {
}

private updateOverridePropertyPatternKey(): void {
let patternProperties = this.configurationSchema.patternProperties[this.overridePropertyPattern];
if (patternProperties) {
delete this.configurationSchema.patternProperties[this.overridePropertyPattern];
this.computeOverridePropertyPattern();
this.configurationSchema.patternProperties[this.overridePropertyPattern] = patternProperties;
contributionRegistry.registerSchema(schemaId, this.configurationSchema);
let patternProperties: IJSONSchema = this.configurationSchema.patternProperties[this.overridePropertyPattern];
if (!patternProperties) {
patternProperties = {
type: 'object',
description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
errorMessage: 'Unknown Identifier. Use language identifiers',
$ref: editorConfigurationSchemaId
};
}
delete this.configurationSchema.patternProperties[this.overridePropertyPattern];
this.computeOverridePropertyPattern();
this.configurationSchema.patternProperties[this.overridePropertyPattern] = patternProperties;
contributionRegistry.registerSchema(schemaId, this.configurationSchema);
}

private update(configuration: IConfigurationNode, overridePropertiesSchema: IJSONSchema): void {
Expand All @@ -209,24 +235,6 @@ class ConfigurationRegistry implements IConfigurationRegistry {
private computeOverridePropertyPattern(): void {
this.overridePropertyPattern = this.overrideIdentifiers.length ? OVERRIDE_PATTERN_WITH_SUBSTITUTION.replace('${0}', this.overrideIdentifiers.join('|')) : OVERRIDE_PROPERTY;
}

private registerOverrideSettingsConfiguration(): void {
const properties = {
'[]': <IConfigurationPropertySchema>{
type: 'object',
description: nls.localize('overrideSettings.description', "Configure editor settings to be overridden for a language."),
additionalProperties: false,
errorMessage: 'Unknown Identifier. Use language identifiers',
$ref: editorConfigurationSchemaId
}
};
this.registerConfiguration({
id: SETTINGS_OVERRRIDE_NODE_ID,
type: 'object',
title: nls.localize('overrideSettings.title', "Override Settings"),
properties
});
}
}

const SETTINGS_OVERRRIDE_NODE_ID = 'override';
Expand Down Expand Up @@ -283,14 +291,25 @@ const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigu
]
}
},
defaults: {
description: nls.localize('vscode.extension.contributes.configuration.defaults', 'Override default editor settings for a language'),
type: 'object',
patternProperties: {
'\\[.*\\]$': {
type: 'object',
default: {},
$ref: editorConfigurationSchemaId,
}
}
}
}
});

configurationExtPoint.setHandler(extensions => {
const configurations: IConfigurationNode[] = [];
const configurations: IConfigurationExtension[] = [];

for (let i = 0; i < extensions.length; i++) {
const configuration = <IConfigurationNode>extensions[i].value;
const configuration = <IConfigurationExtension>extensions[i].value;
const collector = extensions[i].collector;

if (configuration.type && configuration.type !== 'object') {
Expand All @@ -308,6 +327,11 @@ configurationExtPoint.setHandler(extensions => {
return;
}

if (configuration.defaults && typeof configuration.defaults !== 'object') {
collector.error(nls.localize('invalid.defaults', "'configuration.defaults' must be an object"));
return;
}

const clonedConfiguration = objects.clone(configuration);
clonedConfiguration.id = extensions[i].description.id;
configurations.push(clonedConfiguration);
Expand Down
8 changes: 8 additions & 0 deletions src/vs/platform/configuration/common/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ export class DefaultConfigModel<T> extends ConfigModel<T> {
public update(): void {
this._contents = getDefaultValues(); // defaults coming from contributions to registries
this._keys = getConfigurationKeys();
this._overrides = Object.keys(this._contents)
.filter(key => OVERRIDE_PROPERTY_PATTERN.test(key))
.map(key => {
return <IOverrides<any>>{
identifiers: [overrideIdentifierFromKey(key).trim()],
contents: toValuesTree(this._contents[key], message => console.error(`Conflict in default settings file: ${message}`))
};
});
}
}

Expand Down
21 changes: 18 additions & 3 deletions src/vs/platform/configuration/test/common/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@

import * as assert from 'assert';
import * as model from 'vs/platform/configuration/common/model';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { Extensions, IConfigurationRegistry, IConfigurationExtension } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/platform';

suite('ConfigurationService - Model', () => {

suiteSetup(() => {
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
'id': 'problems',
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration(<IConfigurationExtension>{
'id': 'a',
'order': 1,
'title': 'a',
'type': 'object',
'defaults': {
'[b]': {
'a': false
}
},
'properties': {
'a': {
'description': 'a',
Expand Down Expand Up @@ -126,4 +131,14 @@ suite('ConfigurationService - Model', () => {
assert.deepEqual(testObject.keys, []);
});

test('Test default settings', () => {
const testObject = new model.DefaultConfigModel();

assert.deepEqual(testObject.contents, { 'a': true, '[b]': { 'a': false } });
assert.deepEqual(testObject.keys, ['a', '[b]']);
assert.deepEqual(testObject.overrides, [{
identifiers: ['b'],
contents: { 'a': false }
}]);
});
});

0 comments on commit 9328bd6

Please sign in to comment.