Skip to content

Commit

Permalink
A VS Code extension configurationDefault does not work #12713 (#12758)
Browse files Browse the repository at this point in the history
* A VS Code extension configurationDefault does not work #12713

* plugin contribution handler will now also register
configurationDefault for non language related configuration changes
* extend preference-contribution#doSetSchema to allow modifying default
values for existing schemas when contributed via a special schema id
* also update select options in preference-select-input, since the
default value may change now, which requires the SelectOptions to
recreate

* Address Review Comments #12713
  • Loading branch information
jfaltermeier authored Aug 8, 2023
1 parent 2747ee5 commit 1e16b08
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 30 deletions.
73 changes: 49 additions & 24 deletions packages/core/src/browser/preferences/preference-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { JSONValue } from '@phosphor/coreutils';

export const PreferenceContribution = Symbol('PreferenceContribution');

export const DefaultOverridesPreferenceSchemaId = 'defaultOverrides';

/**
* A {@link PreferenceContribution} allows adding additional custom preferences.
* For this, the {@link PreferenceContribution} has to provide a valid JSON Schema specifying which preferences
Expand Down Expand Up @@ -202,34 +204,44 @@ export class PreferenceSchemaProvider extends PreferenceProvider {
const defaultScope = PreferenceSchema.getDefaultScope(schema);
const overridable = schema.overridable || false;
for (const [preferenceName, rawSchemaProps] of Object.entries(schema.properties)) {
if (this.combinedSchema.properties[preferenceName]) {
if (this.combinedSchema.properties[preferenceName] && DefaultOverridesPreferenceSchemaId !== schema.id) {
console.error('Preference name collision detected in the schema for property: ' + preferenceName);
} else if (!rawSchemaProps.hasOwnProperty('included') || rawSchemaProps.included) {
const schemaProps = PreferenceDataProperty.fromPreferenceSchemaProperty(rawSchemaProps, defaultScope);
if (typeof schemaProps.overridable !== 'boolean' && overridable) {
schemaProps.overridable = true;
}
if (schemaProps.overridable) {
this.overridePatternProperties.properties[preferenceName] = schemaProps;
} else {
let schemaProps;
if (this.combinedSchema.properties[preferenceName] && DefaultOverridesPreferenceSchemaId === schema.id) {
// update existing default value in schema
schemaProps = PreferenceDataProperty.fromPreferenceSchemaProperty(rawSchemaProps, defaultScope);
this.updateSchemaPropsDefault(preferenceName, schemaProps);
} else if (!rawSchemaProps.hasOwnProperty('included') || rawSchemaProps.included) {
// add overrides for languages
schemaProps = PreferenceDataProperty.fromPreferenceSchemaProperty(rawSchemaProps, defaultScope);
if (typeof schemaProps.overridable !== 'boolean' && overridable) {
schemaProps.overridable = true;
}
if (schemaProps.overridable) {
this.overridePatternProperties.properties[preferenceName] = schemaProps;
}
this.updateSchemaProps(preferenceName, schemaProps);
}
this.updateSchemaProps(preferenceName, schemaProps);

const schemaDefault = this.getDefaultValue(schemaProps);
const configuredDefault = this.getConfiguredDefault(preferenceName);
if (this.preferenceOverrideService.testOverrideValue(preferenceName, schemaDefault)) {
schemaProps.defaultValue = PreferenceSchemaProperties.is(configuredDefault)
? PreferenceProvider.merge(schemaDefault, configuredDefault)
: schemaDefault;
if (schemaProps.defaultValue && PreferenceSchemaProperties.is(schemaProps.defaultValue)) {
for (const overriddenPreferenceName in schemaProps.defaultValue) {
const overrideValue = schemaDefault[overriddenPreferenceName];
const overridePreferenceName = `${preferenceName}.${overriddenPreferenceName}`;
changes.push(this.doSetPreferenceValue(overridePreferenceName, overrideValue, { scope, domain }));

if (schemaProps !== undefined) {
const schemaDefault = this.getDefaultValue(schemaProps);
const configuredDefault = this.getConfiguredDefault(preferenceName);
if (this.preferenceOverrideService.testOverrideValue(preferenceName, schemaDefault)) {
schemaProps.defaultValue = PreferenceSchemaProperties.is(configuredDefault)
? PreferenceProvider.merge(schemaDefault, configuredDefault)
: schemaDefault;
if (schemaProps.defaultValue && PreferenceSchemaProperties.is(schemaProps.defaultValue)) {
for (const overriddenPreferenceName in schemaProps.defaultValue) {
const overrideValue = schemaDefault[overriddenPreferenceName];
const overridePreferenceName = `${preferenceName}.${overriddenPreferenceName}`;
changes.push(this.doSetPreferenceValue(overridePreferenceName, overrideValue, { scope, domain }));
}
}
} else {
schemaProps.defaultValue = configuredDefault === undefined ? schemaDefault : configuredDefault;
changes.push(this.doSetPreferenceValue(preferenceName, schemaProps.defaultValue, { scope, domain }));
}
} else {
schemaProps.defaultValue = configuredDefault === undefined ? schemaDefault : configuredDefault;
changes.push(this.doSetPreferenceValue(preferenceName, schemaProps.defaultValue, { scope, domain }));
}
}
}
Expand Down Expand Up @@ -383,6 +395,19 @@ export class PreferenceSchemaProvider extends PreferenceProvider {
}
}

protected updateSchemaPropsDefault(key: string, property: PreferenceDataProperty): void {
this.combinedSchema.properties[key].default = property.default;
this.combinedSchema.properties[key].defaultValue = property.defaultValue;
if (this.workspaceSchema.properties[key]) {
this.workspaceSchema.properties[key].default = property.default;
this.workspaceSchema.properties[key].defaultValue = property.defaultValue;
}
if (this.folderSchema.properties[key]) {
this.folderSchema.properties[key].default = property.default;
this.folderSchema.properties[key].defaultValue = property.defaultValue;
}
}

protected removePropFromSchemas(key: string): void {
// If we remove a key from combined, it should also be removed from all narrower scopes.
delete this.combinedSchema.properties[key];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
LabelProviderContribution,
PreferenceSchemaProvider
} from '@theia/core/lib/browser';
import { PreferenceLanguageOverrideService, PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/browser/preferences';
import { DefaultOverridesPreferenceSchemaId, PreferenceLanguageOverrideService, PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/browser/preferences';
import { KeybindingsContributionPointHandler } from './keybindings/keybindings-contribution-handler';
import { MonacoSnippetSuggestProvider } from '@theia/monaco/lib/browser/monaco-snippet-suggest-provider';
import { PluginSharedStyle } from './plugin-shared-style';
Expand Down Expand Up @@ -487,19 +487,26 @@ export class PluginContributionHandler {

protected updateDefaultOverridesSchema(configurationDefaults: PreferenceSchemaProperties): Disposable {
const defaultOverrides: PreferenceSchema = {
id: 'defaultOverrides',
id: DefaultOverridesPreferenceSchemaId,
title: 'Default Configuration Overrides',
properties: {}
};
// eslint-disable-next-line guard-for-in
for (const key in configurationDefaults) {
const defaultValue = configurationDefaults[key];
if (this.preferenceOverrideService.testOverrideValue(key, defaultValue)) {
// language specific override
defaultOverrides.properties[key] = {
type: 'object',
default: defaultValue,
description: `Configure editor settings to be overridden for ${key} language.`
};
} else {
// regular configuration override
defaultOverrides.properties[key] = {
default: defaultValue,
description: `Configure default setting for ${key}.`
};
}
}
if (Object.keys(defaultOverrides.properties).length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ export class PreferenceSelectInputRenderer extends PreferenceLeafNodeRenderer<JS

protected readonly selectComponent = React.createRef<SelectComponent>();

protected selectOptions: SelectOption[] = [];

protected get enumValues(): JSONValue[] {
return this.preferenceNode.preference.data.enum!;
}

protected get selectOptions(): SelectOption[] {
const items: SelectOption[] = [];
protected updateSelectOptions(): void {
const updatedSelectOptions: SelectOption[] = [];
const values = this.enumValues;
const preferenceData = this.preferenceNode.preference.data;
const defaultValue = preferenceData.default;
Expand All @@ -51,18 +53,19 @@ export class PreferenceSelectInputRenderer extends PreferenceLeafNodeRenderer<JS
enumDescription = this.markdownRenderer.renderInline(markdownEnumDescription);
markdown = true;
}
items.push({
updatedSelectOptions.push({
label,
value: stringValue,
detail,
description: enumDescription,
markdown
});
}
return items;
this.selectOptions = updatedSelectOptions;
}

protected createInteractable(parent: HTMLElement): void {
this.updateSelectOptions();
const interactable = document.createElement('div');
const selectComponent = React.createElement(SelectComponent, {
options: this.selectOptions,
Expand All @@ -86,6 +89,7 @@ export class PreferenceSelectInputRenderer extends PreferenceLeafNodeRenderer<JS

protected doHandleValueChange(): void {
this.updateInspection();
this.updateSelectOptions();
const newValue = this.getDataValue();
this.updateModificationStatus(this.getValue());
if (document.activeElement !== this.interactable && this.selectComponent.current) {
Expand Down

0 comments on commit 1e16b08

Please sign in to comment.