feat: 添加vscode编辑器
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
export const IConfigurationService = createDecorator('configurationService');
|
||||
export function toValuesTree(properties, conflictReporter) {
|
||||
const root = Object.create(null);
|
||||
for (const key in properties) {
|
||||
addToValueTree(root, key, properties[key], conflictReporter);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
export function addToValueTree(settingsTreeRoot, key, value, conflictReporter) {
|
||||
const segments = key.split('.');
|
||||
const last = segments.pop();
|
||||
let curr = settingsTreeRoot;
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const s = segments[i];
|
||||
let obj = curr[s];
|
||||
switch (typeof obj) {
|
||||
case 'undefined':
|
||||
obj = curr[s] = Object.create(null);
|
||||
break;
|
||||
case 'object':
|
||||
break;
|
||||
default:
|
||||
conflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`);
|
||||
return;
|
||||
}
|
||||
curr = obj;
|
||||
}
|
||||
if (typeof curr === 'object' && curr !== null) {
|
||||
try {
|
||||
curr[last] = value; // workaround https://github.com/microsoft/vscode/issues/13606
|
||||
}
|
||||
catch (e) {
|
||||
conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);
|
||||
}
|
||||
}
|
||||
export function removeFromValueTree(valueTree, key) {
|
||||
const segments = key.split('.');
|
||||
doRemoveFromValueTree(valueTree, segments);
|
||||
}
|
||||
function doRemoveFromValueTree(valueTree, segments) {
|
||||
const first = segments.shift();
|
||||
if (segments.length === 0) {
|
||||
// Reached last segment
|
||||
delete valueTree[first];
|
||||
return;
|
||||
}
|
||||
if (Object.keys(valueTree).indexOf(first) !== -1) {
|
||||
const value = valueTree[first];
|
||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||
doRemoveFromValueTree(value, segments);
|
||||
if (Object.keys(value).length === 0) {
|
||||
delete valueTree[first];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A helper function to get the configuration value with a specific settings path (e.g. config.some.setting)
|
||||
*/
|
||||
export function getConfigurationValue(config, settingPath, defaultValue) {
|
||||
function accessSetting(config, path) {
|
||||
let current = config;
|
||||
for (const component of path) {
|
||||
if (typeof current !== 'object' || current === null) {
|
||||
return undefined;
|
||||
}
|
||||
current = current[component];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
const path = settingPath.split('.');
|
||||
const result = accessSetting(config, path);
|
||||
return typeof result === 'undefined' ? defaultValue : result;
|
||||
}
|
||||
export function getLanguageTagSettingPlainKey(settingKey) {
|
||||
return settingKey.replace(/[\[\]]/g, '');
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as arrays from '../../../base/common/arrays.js';
|
||||
import { ResourceMap } from '../../../base/common/map.js';
|
||||
import * as objects from '../../../base/common/objects.js';
|
||||
import * as types from '../../../base/common/types.js';
|
||||
import { URI } from '../../../base/common/uri.js';
|
||||
import { addToValueTree, getConfigurationValue, removeFromValueTree, toValuesTree } from './configuration.js';
|
||||
export class ConfigurationModel {
|
||||
constructor(_contents = {}, _keys = [], _overrides = []) {
|
||||
this._contents = _contents;
|
||||
this._keys = _keys;
|
||||
this._overrides = _overrides;
|
||||
this.frozen = false;
|
||||
this.overrideConfigurations = new Map();
|
||||
}
|
||||
get contents() {
|
||||
return this.checkAndFreeze(this._contents);
|
||||
}
|
||||
get overrides() {
|
||||
return this.checkAndFreeze(this._overrides);
|
||||
}
|
||||
get keys() {
|
||||
return this.checkAndFreeze(this._keys);
|
||||
}
|
||||
isEmpty() {
|
||||
return this._keys.length === 0 && Object.keys(this._contents).length === 0 && this._overrides.length === 0;
|
||||
}
|
||||
getValue(section) {
|
||||
return section ? getConfigurationValue(this.contents, section) : this.contents;
|
||||
}
|
||||
getOverrideValue(section, overrideIdentifier) {
|
||||
const overrideContents = this.getContentsForOverrideIdentifer(overrideIdentifier);
|
||||
return overrideContents
|
||||
? section ? getConfigurationValue(overrideContents, section) : overrideContents
|
||||
: undefined;
|
||||
}
|
||||
override(identifier) {
|
||||
let overrideConfigurationModel = this.overrideConfigurations.get(identifier);
|
||||
if (!overrideConfigurationModel) {
|
||||
overrideConfigurationModel = this.createOverrideConfigurationModel(identifier);
|
||||
this.overrideConfigurations.set(identifier, overrideConfigurationModel);
|
||||
}
|
||||
return overrideConfigurationModel;
|
||||
}
|
||||
merge(...others) {
|
||||
const contents = objects.deepClone(this.contents);
|
||||
const overrides = objects.deepClone(this.overrides);
|
||||
const keys = [...this.keys];
|
||||
for (const other of others) {
|
||||
if (other.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
this.mergeContents(contents, other.contents);
|
||||
for (const otherOverride of other.overrides) {
|
||||
const [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));
|
||||
if (override) {
|
||||
this.mergeContents(override.contents, otherOverride.contents);
|
||||
override.keys.push(...otherOverride.keys);
|
||||
override.keys = arrays.distinct(override.keys);
|
||||
}
|
||||
else {
|
||||
overrides.push(objects.deepClone(otherOverride));
|
||||
}
|
||||
}
|
||||
for (const key of other.keys) {
|
||||
if (keys.indexOf(key) === -1) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ConfigurationModel(contents, keys, overrides);
|
||||
}
|
||||
freeze() {
|
||||
this.frozen = true;
|
||||
return this;
|
||||
}
|
||||
createOverrideConfigurationModel(identifier) {
|
||||
const overrideContents = this.getContentsForOverrideIdentifer(identifier);
|
||||
if (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) {
|
||||
// If there are no valid overrides, return self
|
||||
return this;
|
||||
}
|
||||
const contents = {};
|
||||
for (const key of arrays.distinct([...Object.keys(this.contents), ...Object.keys(overrideContents)])) {
|
||||
let contentsForKey = this.contents[key];
|
||||
const overrideContentsForKey = overrideContents[key];
|
||||
// If there are override contents for the key, clone and merge otherwise use base contents
|
||||
if (overrideContentsForKey) {
|
||||
// Clone and merge only if base contents and override contents are of type object otherwise just override
|
||||
if (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') {
|
||||
contentsForKey = objects.deepClone(contentsForKey);
|
||||
this.mergeContents(contentsForKey, overrideContentsForKey);
|
||||
}
|
||||
else {
|
||||
contentsForKey = overrideContentsForKey;
|
||||
}
|
||||
}
|
||||
contents[key] = contentsForKey;
|
||||
}
|
||||
return new ConfigurationModel(contents, this.keys, this.overrides);
|
||||
}
|
||||
mergeContents(source, target) {
|
||||
for (const key of Object.keys(target)) {
|
||||
if (key in source) {
|
||||
if (types.isObject(source[key]) && types.isObject(target[key])) {
|
||||
this.mergeContents(source[key], target[key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
source[key] = objects.deepClone(target[key]);
|
||||
}
|
||||
}
|
||||
checkAndFreeze(data) {
|
||||
if (this.frozen && !Object.isFrozen(data)) {
|
||||
return objects.deepFreeze(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
getContentsForOverrideIdentifer(identifier) {
|
||||
let contentsForIdentifierOnly = null;
|
||||
let contents = null;
|
||||
const mergeContents = (contentsToMerge) => {
|
||||
if (contentsToMerge) {
|
||||
if (contents) {
|
||||
this.mergeContents(contents, contentsToMerge);
|
||||
}
|
||||
else {
|
||||
contents = objects.deepClone(contentsToMerge);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const override of this.overrides) {
|
||||
if (arrays.equals(override.identifiers, [identifier])) {
|
||||
contentsForIdentifierOnly = override.contents;
|
||||
}
|
||||
else if (override.identifiers.includes(identifier)) {
|
||||
mergeContents(override.contents);
|
||||
}
|
||||
}
|
||||
// Merge contents of the identifier only at the end to take precedence.
|
||||
mergeContents(contentsForIdentifierOnly);
|
||||
return contents;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
contents: this.contents,
|
||||
overrides: this.overrides,
|
||||
keys: this.keys
|
||||
};
|
||||
}
|
||||
// Update methods
|
||||
setValue(key, value) {
|
||||
this.addKey(key);
|
||||
addToValueTree(this.contents, key, value, e => { throw new Error(e); });
|
||||
}
|
||||
removeValue(key) {
|
||||
if (this.removeKey(key)) {
|
||||
removeFromValueTree(this.contents, key);
|
||||
}
|
||||
}
|
||||
addKey(key) {
|
||||
let index = this.keys.length;
|
||||
for (let i = 0; i < index; i++) {
|
||||
if (key.indexOf(this.keys[i]) === 0) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
this.keys.splice(index, 1, key);
|
||||
}
|
||||
removeKey(key) {
|
||||
const index = this.keys.indexOf(key);
|
||||
if (index !== -1) {
|
||||
this.keys.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export class Configuration {
|
||||
constructor(_defaultConfiguration, _policyConfiguration, _applicationConfiguration, _localUserConfiguration, _remoteUserConfiguration = new ConfigurationModel(), _workspaceConfiguration = new ConfigurationModel(), _folderConfigurations = new ResourceMap(), _memoryConfiguration = new ConfigurationModel(), _memoryConfigurationByResource = new ResourceMap(), _freeze = true) {
|
||||
this._defaultConfiguration = _defaultConfiguration;
|
||||
this._policyConfiguration = _policyConfiguration;
|
||||
this._applicationConfiguration = _applicationConfiguration;
|
||||
this._localUserConfiguration = _localUserConfiguration;
|
||||
this._remoteUserConfiguration = _remoteUserConfiguration;
|
||||
this._workspaceConfiguration = _workspaceConfiguration;
|
||||
this._folderConfigurations = _folderConfigurations;
|
||||
this._memoryConfiguration = _memoryConfiguration;
|
||||
this._memoryConfigurationByResource = _memoryConfigurationByResource;
|
||||
this._freeze = _freeze;
|
||||
this._workspaceConsolidatedConfiguration = null;
|
||||
this._foldersConsolidatedConfigurations = new ResourceMap();
|
||||
this._userConfiguration = null;
|
||||
}
|
||||
getValue(section, overrides, workspace) {
|
||||
const consolidateConfigurationModel = this.getConsolidatedConfigurationModel(section, overrides, workspace);
|
||||
return consolidateConfigurationModel.getValue(section);
|
||||
}
|
||||
updateValue(key, value, overrides = {}) {
|
||||
let memoryConfiguration;
|
||||
if (overrides.resource) {
|
||||
memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource);
|
||||
if (!memoryConfiguration) {
|
||||
memoryConfiguration = new ConfigurationModel();
|
||||
this._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
memoryConfiguration = this._memoryConfiguration;
|
||||
}
|
||||
if (value === undefined) {
|
||||
memoryConfiguration.removeValue(key);
|
||||
}
|
||||
else {
|
||||
memoryConfiguration.setValue(key, value);
|
||||
}
|
||||
if (!overrides.resource) {
|
||||
this._workspaceConsolidatedConfiguration = null;
|
||||
}
|
||||
}
|
||||
inspect(key, overrides, workspace) {
|
||||
const consolidateConfigurationModel = this.getConsolidatedConfigurationModel(key, overrides, workspace);
|
||||
const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace);
|
||||
const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;
|
||||
const defaultValue = overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._defaultConfiguration.freeze().getValue(key);
|
||||
const policyValue = this._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration.freeze().getValue(key);
|
||||
const applicationValue = this.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration.freeze().getValue(key);
|
||||
const userValue = overrides.overrideIdentifier ? this.userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.userConfiguration.freeze().getValue(key);
|
||||
const userLocalValue = overrides.overrideIdentifier ? this.localUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.localUserConfiguration.freeze().getValue(key);
|
||||
const userRemoteValue = overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.remoteUserConfiguration.freeze().getValue(key);
|
||||
const workspaceValue = workspace ? overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._workspaceConfiguration.freeze().getValue(key) : undefined; //Check on workspace exists or not because _workspaceConfiguration is never null
|
||||
const workspaceFolderValue = folderConfigurationModel ? overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : folderConfigurationModel.freeze().getValue(key) : undefined;
|
||||
const memoryValue = overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).getValue(key) : memoryConfigurationModel.getValue(key);
|
||||
const value = consolidateConfigurationModel.getValue(key);
|
||||
const overrideIdentifiers = arrays.distinct(consolidateConfigurationModel.overrides.map(override => override.identifiers).flat()).filter(overrideIdentifier => consolidateConfigurationModel.getOverrideValue(key, overrideIdentifier) !== undefined);
|
||||
return {
|
||||
defaultValue,
|
||||
policyValue,
|
||||
applicationValue,
|
||||
userValue,
|
||||
userLocalValue,
|
||||
userRemoteValue,
|
||||
workspaceValue,
|
||||
workspaceFolderValue,
|
||||
memoryValue,
|
||||
value,
|
||||
default: defaultValue !== undefined ? { value: this._defaultConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
policy: policyValue !== undefined ? { value: policyValue } : undefined,
|
||||
application: applicationValue !== undefined ? { value: applicationValue, override: overrides.overrideIdentifier ? this.applicationConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
user: userValue !== undefined ? { value: this.userConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.userConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
userLocal: userLocalValue !== undefined ? { value: this.localUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.localUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
userRemote: userRemoteValue !== undefined ? { value: this.remoteUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
workspace: workspaceValue !== undefined ? { value: this._workspaceConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
workspaceFolder: workspaceFolderValue !== undefined ? { value: folderConfigurationModel === null || folderConfigurationModel === void 0 ? void 0 : folderConfigurationModel.freeze().getValue(key), override: overrides.overrideIdentifier ? folderConfigurationModel === null || folderConfigurationModel === void 0 ? void 0 : folderConfigurationModel.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
memory: memoryValue !== undefined ? { value: memoryConfigurationModel.getValue(key), override: overrides.overrideIdentifier ? memoryConfigurationModel.getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
|
||||
overrideIdentifiers: overrideIdentifiers.length ? overrideIdentifiers : undefined
|
||||
};
|
||||
}
|
||||
get applicationConfiguration() {
|
||||
return this._applicationConfiguration;
|
||||
}
|
||||
get userConfiguration() {
|
||||
if (!this._userConfiguration) {
|
||||
this._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration);
|
||||
if (this._freeze) {
|
||||
this._userConfiguration.freeze();
|
||||
}
|
||||
}
|
||||
return this._userConfiguration;
|
||||
}
|
||||
get localUserConfiguration() {
|
||||
return this._localUserConfiguration;
|
||||
}
|
||||
get remoteUserConfiguration() {
|
||||
return this._remoteUserConfiguration;
|
||||
}
|
||||
getConsolidatedConfigurationModel(section, overrides, workspace) {
|
||||
let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);
|
||||
if (overrides.overrideIdentifier) {
|
||||
configurationModel = configurationModel.override(overrides.overrideIdentifier);
|
||||
}
|
||||
if (!this._policyConfiguration.isEmpty() && this._policyConfiguration.getValue(section) !== undefined) {
|
||||
configurationModel = configurationModel.merge(this._policyConfiguration);
|
||||
}
|
||||
return configurationModel;
|
||||
}
|
||||
getConsolidatedConfigurationModelForResource({ resource }, workspace) {
|
||||
let consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
|
||||
if (workspace && resource) {
|
||||
const root = workspace.getFolder(resource);
|
||||
if (root) {
|
||||
consolidateConfiguration = this.getFolderConsolidatedConfiguration(root.uri) || consolidateConfiguration;
|
||||
}
|
||||
const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);
|
||||
if (memoryConfigurationForResource) {
|
||||
consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);
|
||||
}
|
||||
}
|
||||
return consolidateConfiguration;
|
||||
}
|
||||
getWorkspaceConsolidatedConfiguration() {
|
||||
if (!this._workspaceConsolidatedConfiguration) {
|
||||
this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.applicationConfiguration, this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
|
||||
if (this._freeze) {
|
||||
this._workspaceConfiguration = this._workspaceConfiguration.freeze();
|
||||
}
|
||||
}
|
||||
return this._workspaceConsolidatedConfiguration;
|
||||
}
|
||||
getFolderConsolidatedConfiguration(folder) {
|
||||
let folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);
|
||||
if (!folderConsolidatedConfiguration) {
|
||||
const workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
|
||||
const folderConfiguration = this._folderConfigurations.get(folder);
|
||||
if (folderConfiguration) {
|
||||
folderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration);
|
||||
if (this._freeze) {
|
||||
folderConsolidatedConfiguration = folderConsolidatedConfiguration.freeze();
|
||||
}
|
||||
this._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);
|
||||
}
|
||||
else {
|
||||
folderConsolidatedConfiguration = workspaceConsolidateConfiguration;
|
||||
}
|
||||
}
|
||||
return folderConsolidatedConfiguration;
|
||||
}
|
||||
getFolderConfigurationModelForResource(resource, workspace) {
|
||||
if (workspace && resource) {
|
||||
const root = workspace.getFolder(resource);
|
||||
if (root) {
|
||||
return this._folderConfigurations.get(root.uri);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
toData() {
|
||||
return {
|
||||
defaults: {
|
||||
contents: this._defaultConfiguration.contents,
|
||||
overrides: this._defaultConfiguration.overrides,
|
||||
keys: this._defaultConfiguration.keys
|
||||
},
|
||||
policy: {
|
||||
contents: this._policyConfiguration.contents,
|
||||
overrides: this._policyConfiguration.overrides,
|
||||
keys: this._policyConfiguration.keys
|
||||
},
|
||||
application: {
|
||||
contents: this.applicationConfiguration.contents,
|
||||
overrides: this.applicationConfiguration.overrides,
|
||||
keys: this.applicationConfiguration.keys
|
||||
},
|
||||
user: {
|
||||
contents: this.userConfiguration.contents,
|
||||
overrides: this.userConfiguration.overrides,
|
||||
keys: this.userConfiguration.keys
|
||||
},
|
||||
workspace: {
|
||||
contents: this._workspaceConfiguration.contents,
|
||||
overrides: this._workspaceConfiguration.overrides,
|
||||
keys: this._workspaceConfiguration.keys
|
||||
},
|
||||
folders: [...this._folderConfigurations.keys()].reduce((result, folder) => {
|
||||
const { contents, overrides, keys } = this._folderConfigurations.get(folder);
|
||||
result.push([folder, { contents, overrides, keys }]);
|
||||
return result;
|
||||
}, [])
|
||||
};
|
||||
}
|
||||
static parse(data) {
|
||||
const defaultConfiguration = this.parseConfigurationModel(data.defaults);
|
||||
const policyConfiguration = this.parseConfigurationModel(data.policy);
|
||||
const applicationConfiguration = this.parseConfigurationModel(data.application);
|
||||
const userConfiguration = this.parseConfigurationModel(data.user);
|
||||
const workspaceConfiguration = this.parseConfigurationModel(data.workspace);
|
||||
const folders = data.folders.reduce((result, value) => {
|
||||
result.set(URI.revive(value[0]), this.parseConfigurationModel(value[1]));
|
||||
return result;
|
||||
}, new ResourceMap());
|
||||
return new Configuration(defaultConfiguration, policyConfiguration, applicationConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap(), false);
|
||||
}
|
||||
static parseConfigurationModel(model) {
|
||||
return new ConfigurationModel(model.contents, model.keys, model.overrides).freeze();
|
||||
}
|
||||
}
|
||||
export class ConfigurationChangeEvent {
|
||||
constructor(change, previous, currentConfiguraiton, currentWorkspace) {
|
||||
this.change = change;
|
||||
this.previous = previous;
|
||||
this.currentConfiguraiton = currentConfiguraiton;
|
||||
this.currentWorkspace = currentWorkspace;
|
||||
this._previousConfiguration = undefined;
|
||||
const keysSet = new Set();
|
||||
change.keys.forEach(key => keysSet.add(key));
|
||||
change.overrides.forEach(([, keys]) => keys.forEach(key => keysSet.add(key)));
|
||||
this.affectedKeys = [...keysSet.values()];
|
||||
const configurationModel = new ConfigurationModel();
|
||||
this.affectedKeys.forEach(key => configurationModel.setValue(key, {}));
|
||||
this.affectedKeysTree = configurationModel.contents;
|
||||
}
|
||||
get previousConfiguration() {
|
||||
if (!this._previousConfiguration && this.previous) {
|
||||
this._previousConfiguration = Configuration.parse(this.previous.data);
|
||||
}
|
||||
return this._previousConfiguration;
|
||||
}
|
||||
affectsConfiguration(section, overrides) {
|
||||
var _a;
|
||||
if (this.doesAffectedKeysTreeContains(this.affectedKeysTree, section)) {
|
||||
if (overrides) {
|
||||
const value1 = this.previousConfiguration ? this.previousConfiguration.getValue(section, overrides, (_a = this.previous) === null || _a === void 0 ? void 0 : _a.workspace) : undefined;
|
||||
const value2 = this.currentConfiguraiton.getValue(section, overrides, this.currentWorkspace);
|
||||
return !objects.equals(value1, value2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
doesAffectedKeysTreeContains(affectedKeysTree, section) {
|
||||
let requestedTree = toValuesTree({ [section]: true }, () => { });
|
||||
let key;
|
||||
while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property
|
||||
affectedKeysTree = affectedKeysTree[key];
|
||||
if (!affectedKeysTree) {
|
||||
return false; // Requested tree is not found
|
||||
}
|
||||
requestedTree = requestedTree[key];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { distinct } from '../../../base/common/arrays.js';
|
||||
import { Emitter } from '../../../base/common/event.js';
|
||||
import * as types from '../../../base/common/types.js';
|
||||
import * as nls from '../../../nls.js';
|
||||
import { getLanguageTagSettingPlainKey } from './configuration.js';
|
||||
import { Extensions as JSONExtensions } from '../../jsonschemas/common/jsonContributionRegistry.js';
|
||||
import { Registry } from '../../registry/common/platform.js';
|
||||
export const Extensions = {
|
||||
Configuration: 'base.contributions.configuration'
|
||||
};
|
||||
export const allSettings = { properties: {}, patternProperties: {} };
|
||||
export const applicationSettings = { properties: {}, patternProperties: {} };
|
||||
export const machineSettings = { properties: {}, patternProperties: {} };
|
||||
export const machineOverridableSettings = { properties: {}, patternProperties: {} };
|
||||
export const windowSettings = { properties: {}, patternProperties: {} };
|
||||
export const resourceSettings = { properties: {}, patternProperties: {} };
|
||||
export const resourceLanguageSettingsSchemaId = 'vscode://schemas/settings/resourceLanguage';
|
||||
const contributionRegistry = Registry.as(JSONExtensions.JSONContribution);
|
||||
class ConfigurationRegistry {
|
||||
constructor() {
|
||||
this.overrideIdentifiers = new Set();
|
||||
this._onDidSchemaChange = new Emitter();
|
||||
this._onDidUpdateConfiguration = new Emitter();
|
||||
this.configurationDefaultsOverrides = new Map();
|
||||
this.defaultLanguageConfigurationOverridesNode = {
|
||||
id: 'defaultOverrides',
|
||||
title: nls.localize('defaultLanguageConfigurationOverrides.title', "Default Language Configuration Overrides"),
|
||||
properties: {}
|
||||
};
|
||||
this.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];
|
||||
this.resourceLanguageSettingsSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting', allowTrailingCommas: true, allowComments: true };
|
||||
this.configurationProperties = {};
|
||||
this.policyConfigurations = new Map();
|
||||
this.excludedConfigurationProperties = {};
|
||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||
this.registerOverridePropertyPatternKey();
|
||||
}
|
||||
registerConfiguration(configuration, validate = true) {
|
||||
this.registerConfigurations([configuration], validate);
|
||||
}
|
||||
registerConfigurations(configurations, validate = true) {
|
||||
const properties = this.doRegisterConfigurations(configurations, validate);
|
||||
contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
|
||||
this._onDidSchemaChange.fire();
|
||||
this._onDidUpdateConfiguration.fire({ properties });
|
||||
}
|
||||
registerDefaultConfigurations(configurationDefaults) {
|
||||
var _a;
|
||||
const properties = [];
|
||||
const overrideIdentifiers = [];
|
||||
for (const { overrides, source } of configurationDefaults) {
|
||||
for (const key in overrides) {
|
||||
properties.push(key);
|
||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||
const configurationDefaultOverride = this.configurationDefaultsOverrides.get(key);
|
||||
const valuesSources = (_a = configurationDefaultOverride === null || configurationDefaultOverride === void 0 ? void 0 : configurationDefaultOverride.valuesSources) !== null && _a !== void 0 ? _a : new Map();
|
||||
if (source) {
|
||||
for (const configuration of Object.keys(overrides[key])) {
|
||||
valuesSources.set(configuration, source);
|
||||
}
|
||||
}
|
||||
const defaultValue = Object.assign(Object.assign({}, ((configurationDefaultOverride === null || configurationDefaultOverride === void 0 ? void 0 : configurationDefaultOverride.value) || {})), overrides[key]);
|
||||
this.configurationDefaultsOverrides.set(key, { source, value: defaultValue, valuesSources });
|
||||
const plainKey = getLanguageTagSettingPlainKey(key);
|
||||
const property = {
|
||||
type: 'object',
|
||||
default: defaultValue,
|
||||
description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for the {0} language.", plainKey),
|
||||
$ref: resourceLanguageSettingsSchemaId,
|
||||
defaultDefaultValue: defaultValue,
|
||||
source: types.isString(source) ? undefined : source,
|
||||
defaultValueSource: source
|
||||
};
|
||||
overrideIdentifiers.push(...overrideIdentifiersFromKey(key));
|
||||
this.configurationProperties[key] = property;
|
||||
this.defaultLanguageConfigurationOverridesNode.properties[key] = property;
|
||||
}
|
||||
else {
|
||||
this.configurationDefaultsOverrides.set(key, { value: overrides[key], source });
|
||||
const property = this.configurationProperties[key];
|
||||
if (property) {
|
||||
this.updatePropertyDefaultValue(key, property);
|
||||
this.updateSchema(key, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.registerOverrideIdentifiers(overrideIdentifiers);
|
||||
this._onDidSchemaChange.fire();
|
||||
this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
|
||||
}
|
||||
registerOverrideIdentifiers(overrideIdentifiers) {
|
||||
for (const overrideIdentifier of overrideIdentifiers) {
|
||||
this.overrideIdentifiers.add(overrideIdentifier);
|
||||
}
|
||||
this.updateOverridePropertyPatternKey();
|
||||
}
|
||||
doRegisterConfigurations(configurations, validate) {
|
||||
const properties = [];
|
||||
configurations.forEach(configuration => {
|
||||
properties.push(...this.validateAndRegisterProperties(configuration, validate, configuration.extensionInfo, configuration.restrictedProperties)); // fills in defaults
|
||||
this.configurationContributors.push(configuration);
|
||||
this.registerJSONConfiguration(configuration);
|
||||
});
|
||||
return properties;
|
||||
}
|
||||
validateAndRegisterProperties(configuration, validate = true, extensionInfo, restrictedProperties, scope = 3 /* ConfigurationScope.WINDOW */) {
|
||||
var _a;
|
||||
scope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;
|
||||
const propertyKeys = [];
|
||||
const properties = configuration.properties;
|
||||
if (properties) {
|
||||
for (const key in properties) {
|
||||
const property = properties[key];
|
||||
if (validate && validateProperty(key, property)) {
|
||||
delete properties[key];
|
||||
continue;
|
||||
}
|
||||
property.source = extensionInfo;
|
||||
// update default value
|
||||
property.defaultDefaultValue = properties[key].default;
|
||||
this.updatePropertyDefaultValue(key, property);
|
||||
// update scope
|
||||
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;
|
||||
property.restricted = types.isUndefinedOrNull(property.restricted) ? !!(restrictedProperties === null || restrictedProperties === void 0 ? void 0 : restrictedProperties.includes(key)) : property.restricted;
|
||||
}
|
||||
// Add to properties maps
|
||||
// Property is included by default if 'included' is unspecified
|
||||
if (properties[key].hasOwnProperty('included') && !properties[key].included) {
|
||||
this.excludedConfigurationProperties[key] = properties[key];
|
||||
delete properties[key];
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
this.configurationProperties[key] = properties[key];
|
||||
if ((_a = properties[key].policy) === null || _a === void 0 ? void 0 : _a.name) {
|
||||
this.policyConfigurations.set(properties[key].policy.name, key);
|
||||
}
|
||||
}
|
||||
if (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {
|
||||
// If not set, default deprecationMessage to the markdown source
|
||||
properties[key].deprecationMessage = properties[key].markdownDeprecationMessage;
|
||||
}
|
||||
propertyKeys.push(key);
|
||||
}
|
||||
}
|
||||
const subNodes = configuration.allOf;
|
||||
if (subNodes) {
|
||||
for (const node of subNodes) {
|
||||
propertyKeys.push(...this.validateAndRegisterProperties(node, validate, extensionInfo, restrictedProperties, scope));
|
||||
}
|
||||
}
|
||||
return propertyKeys;
|
||||
}
|
||||
getConfigurationProperties() {
|
||||
return this.configurationProperties;
|
||||
}
|
||||
getPolicyConfigurations() {
|
||||
return this.policyConfigurations;
|
||||
}
|
||||
registerJSONConfiguration(configuration) {
|
||||
const register = (configuration) => {
|
||||
const properties = configuration.properties;
|
||||
if (properties) {
|
||||
for (const key in properties) {
|
||||
this.updateSchema(key, properties[key]);
|
||||
}
|
||||
}
|
||||
const subNodes = configuration.allOf;
|
||||
subNodes === null || subNodes === void 0 ? void 0 : subNodes.forEach(register);
|
||||
};
|
||||
register(configuration);
|
||||
}
|
||||
updateSchema(key, property) {
|
||||
allSettings.properties[key] = property;
|
||||
switch (property.scope) {
|
||||
case 1 /* ConfigurationScope.APPLICATION */:
|
||||
applicationSettings.properties[key] = property;
|
||||
break;
|
||||
case 2 /* ConfigurationScope.MACHINE */:
|
||||
machineSettings.properties[key] = property;
|
||||
break;
|
||||
case 6 /* ConfigurationScope.MACHINE_OVERRIDABLE */:
|
||||
machineOverridableSettings.properties[key] = property;
|
||||
break;
|
||||
case 3 /* ConfigurationScope.WINDOW */:
|
||||
windowSettings.properties[key] = property;
|
||||
break;
|
||||
case 4 /* ConfigurationScope.RESOURCE */:
|
||||
resourceSettings.properties[key] = property;
|
||||
break;
|
||||
case 5 /* ConfigurationScope.LANGUAGE_OVERRIDABLE */:
|
||||
resourceSettings.properties[key] = property;
|
||||
this.resourceLanguageSettingsSchema.properties[key] = property;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateOverridePropertyPatternKey() {
|
||||
for (const overrideIdentifier of this.overrideIdentifiers.values()) {
|
||||
const overrideIdentifierProperty = `[${overrideIdentifier}]`;
|
||||
const resourceLanguagePropertiesSchema = {
|
||||
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,
|
||||
};
|
||||
this.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);
|
||||
allSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
applicationSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
machineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
machineOverridableSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
windowSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
resourceSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
|
||||
}
|
||||
this._onDidSchemaChange.fire();
|
||||
}
|
||||
registerOverridePropertyPatternKey() {
|
||||
const resourceLanguagePropertiesSchema = {
|
||||
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_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();
|
||||
}
|
||||
updatePropertyDefaultValue(key, property) {
|
||||
const configurationdefaultOverride = this.configurationDefaultsOverrides.get(key);
|
||||
let defaultValue = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.value;
|
||||
let defaultSource = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.source;
|
||||
if (types.isUndefined(defaultValue)) {
|
||||
defaultValue = property.defaultDefaultValue;
|
||||
defaultSource = undefined;
|
||||
}
|
||||
if (types.isUndefined(defaultValue)) {
|
||||
defaultValue = getDefaultValue(property.type);
|
||||
}
|
||||
property.default = defaultValue;
|
||||
property.defaultValueSource = defaultSource;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
const identifiers = [];
|
||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||
let matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
|
||||
while (matches === null || matches === void 0 ? void 0 : matches.length) {
|
||||
const identifier = matches[1].trim();
|
||||
if (identifier) {
|
||||
identifiers.push(identifier);
|
||||
}
|
||||
matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
|
||||
}
|
||||
}
|
||||
return distinct(identifiers);
|
||||
}
|
||||
export function getDefaultValue(type) {
|
||||
const t = Array.isArray(type) ? type[0] : type;
|
||||
switch (t) {
|
||||
case 'boolean':
|
||||
return false;
|
||||
case 'integer':
|
||||
case 'number':
|
||||
return 0;
|
||||
case 'string':
|
||||
return '';
|
||||
case 'array':
|
||||
return [];
|
||||
case 'object':
|
||||
return {};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const configurationRegistry = new ConfigurationRegistry();
|
||||
Registry.add(Extensions.Configuration, configurationRegistry);
|
||||
export function validateProperty(property, schema) {
|
||||
var _a, _b, _c, _d;
|
||||
if (!property.trim()) {
|
||||
return nls.localize('config.property.empty', "Cannot register an empty 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) {
|
||||
return nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", property);
|
||||
}
|
||||
if (((_a = schema.policy) === null || _a === void 0 ? void 0 : _a.name) && configurationRegistry.getPolicyConfigurations().get((_b = schema.policy) === null || _b === void 0 ? void 0 : _b.name) !== undefined) {
|
||||
return nls.localize('config.policy.duplicate', "Cannot register '{0}'. The associated policy {1} is already registered with {2}.", property, (_c = schema.policy) === null || _c === void 0 ? void 0 : _c.name, configurationRegistry.getPolicyConfigurations().get((_d = schema.policy) === null || _d === void 0 ? void 0 : _d.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { addToValueTree, toValuesTree } from './configuration.js';
|
||||
import { ConfigurationModel } from './configurationModels.js';
|
||||
import { Extensions, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from './configurationRegistry.js';
|
||||
import { Registry } from '../../registry/common/platform.js';
|
||||
export class DefaultConfigurationModel extends ConfigurationModel {
|
||||
constructor(configurationDefaultsOverrides = {}) {
|
||||
const properties = Registry.as(Extensions.Configuration).getConfigurationProperties();
|
||||
const keys = Object.keys(properties);
|
||||
const contents = Object.create(null);
|
||||
const overrides = [];
|
||||
for (const key in properties) {
|
||||
const defaultOverrideValue = configurationDefaultsOverrides[key];
|
||||
const value = defaultOverrideValue !== undefined ? defaultOverrideValue : properties[key].default;
|
||||
addToValueTree(contents, key, value, message => console.error(`Conflict in default settings: ${message}`));
|
||||
}
|
||||
for (const key of Object.keys(contents)) {
|
||||
if (OVERRIDE_PROPERTY_REGEX.test(key)) {
|
||||
overrides.push({
|
||||
identifiers: overrideIdentifiersFromKey(key),
|
||||
keys: Object.keys(contents[key]),
|
||||
contents: toValuesTree(contents[key], message => console.error(`Conflict in default settings file: ${message}`)),
|
||||
});
|
||||
}
|
||||
}
|
||||
super(contents, keys, overrides);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user