mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
#120860 Implement trusted workspace settings
This commit is contained in:
parent
f689971195
commit
7c26f27d90
|
@ -214,42 +214,53 @@ export class DefaultConfigurationModel extends ConfigurationModel {
|
|||
}
|
||||
}
|
||||
|
||||
export interface ConfigurationParseOptions {
|
||||
scopes: ConfigurationScope[] | undefined;
|
||||
excludeUnsafeConfigurations?: boolean;
|
||||
}
|
||||
|
||||
export class ConfigurationModelParser {
|
||||
|
||||
private _raw: any = null;
|
||||
private _configurationModel: ConfigurationModel | null = null;
|
||||
private _excludedUnsafeConfigurations: string[] = [];
|
||||
private _parseErrors: any[] = [];
|
||||
|
||||
constructor(protected readonly _name: string, private _scopes?: ConfigurationScope[]) { }
|
||||
constructor(protected readonly _name: string) { }
|
||||
|
||||
get configurationModel(): ConfigurationModel {
|
||||
return this._configurationModel || new ConfigurationModel();
|
||||
}
|
||||
|
||||
get excludedUnsafeConfigurations(): string[] {
|
||||
return this._excludedUnsafeConfigurations;
|
||||
}
|
||||
|
||||
get errors(): any[] {
|
||||
return this._parseErrors;
|
||||
}
|
||||
|
||||
public parseContent(content: string | null | undefined): void {
|
||||
public parse(content: string | null | undefined, options?: ConfigurationParseOptions): void {
|
||||
if (!types.isUndefinedOrNull(content)) {
|
||||
const raw = this.doParseContent(content);
|
||||
this.parseRaw(raw);
|
||||
this.parseRaw(raw, options);
|
||||
}
|
||||
}
|
||||
|
||||
public parseRaw(raw: any): void {
|
||||
this._raw = raw;
|
||||
const configurationModel = this.doParseRaw(raw);
|
||||
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
|
||||
}
|
||||
|
||||
public parse(): void {
|
||||
public reparse(options: ConfigurationParseOptions): void {
|
||||
if (this._raw) {
|
||||
this.parseRaw(this._raw);
|
||||
this.parseRaw(this._raw, options);
|
||||
}
|
||||
}
|
||||
|
||||
protected doParseContent(content: string): any {
|
||||
public parseRaw(raw: any, options?: ConfigurationParseOptions): void {
|
||||
this._raw = raw;
|
||||
const { contents, keys, overrides, unsafeConfigurations } = this.doParseRaw(raw, options);
|
||||
this._configurationModel = new ConfigurationModel(contents, keys, overrides);
|
||||
this._excludedUnsafeConfigurations = unsafeConfigurations || [];
|
||||
}
|
||||
|
||||
private doParseContent(content: string): any {
|
||||
let raw: any = {};
|
||||
let currentProperty: string | null = null;
|
||||
let currentParent: any = [];
|
||||
|
@ -306,42 +317,49 @@ export class ConfigurationModelParser {
|
|||
return raw;
|
||||
}
|
||||
|
||||
protected doParseRaw(raw: any): IConfigurationModel {
|
||||
if (this._scopes) {
|
||||
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
raw = this.filterByScope(raw, configurationProperties, true, this._scopes);
|
||||
}
|
||||
protected doParseRaw(raw: any, options?: ConfigurationParseOptions): IConfigurationModel & { unsafeConfigurations?: string[] } {
|
||||
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
const filtered = this.filter(raw, configurationProperties, true, options);
|
||||
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}`));
|
||||
return { contents, keys, overrides };
|
||||
return { contents, keys, overrides, unsafeConfigurations: filtered.unsafeConfigurations };
|
||||
}
|
||||
|
||||
private filterByScope(properties: any, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }, filterOverriddenProperties: boolean, scopes: ConfigurationScope[]): {} {
|
||||
const result: any = {};
|
||||
private filter(properties: any, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema | undefined }, filterOverriddenProperties: boolean, options?: ConfigurationParseOptions): { raw: {}, unsafeConfigurations: string[] } {
|
||||
if (!options?.scopes && !options?.excludeUnsafeConfigurations) {
|
||||
return { raw: properties, unsafeConfigurations: [] };
|
||||
}
|
||||
const raw: any = {};
|
||||
const unsafeConfigurations: string[] = [];
|
||||
for (let key in properties) {
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key) && filterOverriddenProperties) {
|
||||
result[key] = this.filterByScope(properties[key], configurationProperties, false, scopes);
|
||||
const result = this.filter(properties[key], configurationProperties, false, options);
|
||||
raw[key] = result.raw;
|
||||
unsafeConfigurations.push(...result.unsafeConfigurations);
|
||||
} else {
|
||||
const scope = this.getScope(key, configurationProperties);
|
||||
const propertySchema = configurationProperties[key];
|
||||
const scope = propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined;
|
||||
// Load unregistered configurations always.
|
||||
if (scope === undefined || scopes.indexOf(scope) !== -1) {
|
||||
result[key] = properties[key];
|
||||
if (scope === undefined || options.scopes === undefined || options.scopes.includes(scope)) {
|
||||
if (options.excludeUnsafeConfigurations && propertySchema?.requiresTrustedWorkspace) {
|
||||
unsafeConfigurations.push(key);
|
||||
} else {
|
||||
raw[key] = properties[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return { raw, unsafeConfigurations };
|
||||
}
|
||||
|
||||
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope | undefined {
|
||||
const propertySchema = configurationProperties[key];
|
||||
return propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class UserSettings extends Disposable {
|
||||
|
||||
private readonly parser: ConfigurationModelParser;
|
||||
private readonly parseOptions: ConfigurationParseOptions;
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
|
@ -352,7 +370,8 @@ export class UserSettings extends Disposable {
|
|||
private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
|
||||
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString());
|
||||
this.parseOptions = { scopes: this.scopes };
|
||||
this._register(this.fileService.watch(extUri.dirname(this.userSettingsResource)));
|
||||
// Also listen to the resource incase the resource is a symlink - https://github.com/microsoft/vscode/issues/118134
|
||||
this._register(this.fileService.watch(this.userSettingsResource));
|
||||
|
@ -362,15 +381,15 @@ export class UserSettings extends Disposable {
|
|||
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||
try {
|
||||
const content = await this.fileService.readFile(this.userSettingsResource);
|
||||
this.parser.parseContent(content.value.toString() || '{}');
|
||||
this.parser.parse(content.value.toString() || '{}', this.parseOptions);
|
||||
return this.parser.configurationModel;
|
||||
} catch (e) {
|
||||
return new ConfigurationModel();
|
||||
}
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
this.parser.parse();
|
||||
reparse(): ConfigurationModel {
|
||||
this.parser.reparse(this.parseOptions);
|
||||
return this.parser.configurationModel;
|
||||
}
|
||||
}
|
||||
|
@ -802,5 +821,4 @@ export class AllKeysConfigurationChangeEvent extends ConfigurationChangeEvent {
|
|||
constructor(configuration: Configuration, workspace: Workspace, public source: ConfigurationTarget, public sourceConfig: any) {
|
||||
super({ keys: configuration.allKeys(), overrides: [] }, undefined, configuration, workspace);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ export const enum ConfigurationScope {
|
|||
|
||||
export interface IConfigurationPropertySchema extends IJSONSchema {
|
||||
scope?: ConfigurationScope;
|
||||
requiresTrustedWorkspace?: boolean;
|
||||
included?: boolean;
|
||||
tags?: string[];
|
||||
/**
|
||||
|
@ -136,6 +137,7 @@ export interface IConfigurationNode {
|
|||
properties?: { [path: string]: IConfigurationPropertySchema; };
|
||||
allOf?: IConfigurationNode[];
|
||||
scope?: ConfigurationScope;
|
||||
requiresTrustedWorkspace?: boolean;
|
||||
extensionInfo?: IConfigurationExtensionInfo;
|
||||
}
|
||||
|
||||
|
@ -297,8 +299,9 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
this.updateOverridePropertyPatternKey();
|
||||
}
|
||||
|
||||
private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW): string[] {
|
||||
private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, scope: ConfigurationScope = ConfigurationScope.WINDOW, requiresTrustedWorkspace?: boolean): string[] {
|
||||
scope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;
|
||||
requiresTrustedWorkspace = types.isUndefinedOrNull(configuration.requiresTrustedWorkspace) ? types.isUndefined(requiresTrustedWorkspace) ? false : requiresTrustedWorkspace : configuration.requiresTrustedWorkspace;
|
||||
let propertyKeys: string[] = [];
|
||||
let properties = configuration.properties;
|
||||
if (properties) {
|
||||
|
@ -318,6 +321,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
property.scope = undefined; // No scope for overridable properties `[${identifier}]`
|
||||
} else {
|
||||
property.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;
|
||||
property.requiresTrustedWorkspace = types.isUndefinedOrNull(property.requiresTrustedWorkspace) ? requiresTrustedWorkspace : property.requiresTrustedWorkspace;
|
||||
}
|
||||
|
||||
// Add to properties maps
|
||||
|
@ -341,7 +345,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
|||
let subNodes = configuration.allOf;
|
||||
if (subNodes) {
|
||||
for (let node of subNodes) {
|
||||
propertyKeys.push(...this.validateAndRegisterProperties(node, validate, scope));
|
||||
propertyKeys.push(...this.validateAndRegisterProperties(node, validate, scope, requiresTrustedWorkspace));
|
||||
}
|
||||
}
|
||||
return propertyKeys;
|
||||
|
|
|
@ -242,10 +242,10 @@ suite('CustomConfigurationModel', () => {
|
|||
|
||||
test('simple merge using models', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
|
||||
let add = new ConfigurationModelParser('add');
|
||||
add.parseContent(JSON.stringify({ 'a': 3, 'c': 4 }));
|
||||
add.parse(JSON.stringify({ 'a': 3, 'c': 4 }));
|
||||
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepStrictEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 });
|
||||
|
@ -253,14 +253,14 @@ suite('CustomConfigurationModel', () => {
|
|||
|
||||
test('simple merge with an undefined contents', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
let add = new ConfigurationModelParser('add');
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepStrictEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||
|
||||
base = new ConfigurationModelParser('base');
|
||||
add = new ConfigurationModelParser('add');
|
||||
add.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
add.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepStrictEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||
|
||||
|
@ -272,25 +272,25 @@ suite('CustomConfigurationModel', () => {
|
|||
|
||||
test('Recursive merge using config models', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
base.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
let add = new ConfigurationModelParser('add');
|
||||
add.parseContent(JSON.stringify({ 'a': { 'b': 2 } }));
|
||||
add.parse(JSON.stringify({ 'a': { 'b': 2 } }));
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepStrictEqual(result.contents, { 'a': { 'b': 2 } });
|
||||
});
|
||||
|
||||
test('Test contents while getting an existing property', () => {
|
||||
let testObject = new ConfigurationModelParser('test');
|
||||
testObject.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
testObject.parse(JSON.stringify({ 'a': 1 }));
|
||||
assert.deepStrictEqual(testObject.configurationModel.getValue('a'), 1);
|
||||
|
||||
testObject.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
testObject.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
assert.deepStrictEqual(testObject.configurationModel.getValue('a'), { 'b': 1 });
|
||||
});
|
||||
|
||||
test('Test contents are undefined for non existing properties', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parseContent(JSON.stringify({
|
||||
testObject.parse(JSON.stringify({
|
||||
awesome: true
|
||||
}));
|
||||
|
||||
|
@ -305,7 +305,7 @@ suite('CustomConfigurationModel', () => {
|
|||
|
||||
test('Test configWithOverrides gives all content merged with overrides', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parseContent(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
||||
testObject.parse(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
||||
|
||||
assert.deepStrictEqual(testObject.configurationModel.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
|
||||
});
|
||||
|
@ -318,17 +318,17 @@ suite('CustomConfigurationModel', () => {
|
|||
|
||||
test('Test update with empty data', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parseContent('');
|
||||
testObject.parse('');
|
||||
|
||||
assert.deepStrictEqual(testObject.configurationModel.contents, Object.create(null));
|
||||
assert.deepStrictEqual(testObject.configurationModel.keys, []);
|
||||
|
||||
testObject.parseContent(null!);
|
||||
testObject.parse(null!);
|
||||
|
||||
assert.deepStrictEqual(testObject.configurationModel.contents, Object.create(null));
|
||||
assert.deepStrictEqual(testObject.configurationModel.keys, []);
|
||||
|
||||
testObject.parseContent(undefined!);
|
||||
testObject.parse(undefined!);
|
||||
|
||||
assert.deepStrictEqual(testObject.configurationModel.contents, Object.create(null));
|
||||
assert.deepStrictEqual(testObject.configurationModel.keys, []);
|
||||
|
@ -380,7 +380,7 @@ suite('Configuration', () => {
|
|||
|
||||
test('Test update value', () => {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||
|
||||
testObject.updateValue('a', 2);
|
||||
|
@ -390,7 +390,7 @@ suite('Configuration', () => {
|
|||
|
||||
test('Test update value after inspect', () => {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||
|
||||
testObject.inspect('a', {}, undefined);
|
||||
|
@ -503,7 +503,7 @@ suite('Configuration', () => {
|
|||
|
||||
function parseConfigurationModel(content: any): ConfigurationModel {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify(content));
|
||||
parser.parse(JSON.stringify(content));
|
||||
return parser.configurationModel;
|
||||
}
|
||||
|
||||
|
@ -951,6 +951,6 @@ suite('AllKeysConfigurationChangeEvent', () => {
|
|||
|
||||
function toConfigurationModel(obj: any): ConfigurationModel {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify(obj));
|
||||
parser.parse(JSON.stringify(obj));
|
||||
return parser.configurationModel;
|
||||
}
|
||||
|
|
|
@ -181,10 +181,10 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
|
|||
for (let extension of added) {
|
||||
const configurations: IConfigurationNode[] = [];
|
||||
const value = <IConfigurationNode | IConfigurationNode[]>extension.value;
|
||||
if (!Array.isArray(value)) {
|
||||
configurations.push(...handleConfiguration(value, extension));
|
||||
} else {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(v => configurations.push(...handleConfiguration(v, extension)));
|
||||
} else {
|
||||
configurations.push(...handleConfiguration(value, extension));
|
||||
}
|
||||
extensionConfigurations.set(ExtensionIdentifier.toKey(extension.description.identifier), configurations);
|
||||
addedConfigurations.push(...configurations);
|
||||
|
|
|
@ -9,7 +9,7 @@ import * as errors from 'vs/base/common/errors';
|
|||
import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { FileChangeType, FileChangesEvent, IFileService, whenProviderRegistered, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { ConfigurationModel, ConfigurationModelParser, UserSettings } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { ConfigurationModel, ConfigurationModelParser, ConfigurationParseOptions, UserSettings } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
import { TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
|
@ -23,6 +23,11 @@ import { hash } from 'vs/base/common/hash';
|
|||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
|
||||
function hasToExcludeUnsafeConfigurations(workspaceTrustState: WorkspaceTrustState): boolean {
|
||||
return workspaceTrustState !== WorkspaceTrustState.Trusted;
|
||||
}
|
||||
|
||||
export class UserConfiguration extends Disposable {
|
||||
|
||||
|
@ -32,17 +37,20 @@ export class UserConfiguration extends Disposable {
|
|||
private readonly userConfiguration: MutableDisposable<UserSettings | FileServiceBasedConfiguration> = this._register(new MutableDisposable<UserSettings | FileServiceBasedConfiguration>());
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
|
||||
private readonly configurationParseOptions: ConfigurationParseOptions;
|
||||
|
||||
get hasTasksLoaded(): boolean { return this.userConfiguration.value instanceof FileServiceBasedConfiguration; }
|
||||
|
||||
constructor(
|
||||
private readonly userSettingsResource: URI,
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
scopes: ConfigurationScope[] | undefined,
|
||||
private readonly fileService: IFileService,
|
||||
private readonly uriIdentityService: IUriIdentityService,
|
||||
private readonly logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
this.userConfiguration.value = new UserSettings(this.userSettingsResource, this.scopes, uriIdentityService.extUri, this.fileService);
|
||||
this.configurationParseOptions = { scopes, excludeUnsafeConfigurations: false };
|
||||
this.userConfiguration.value = new UserSettings(this.userSettingsResource, scopes, uriIdentityService.extUri, this.fileService);
|
||||
this._register(this.userConfiguration.value.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
|
||||
}
|
||||
|
@ -58,7 +66,7 @@ export class UserConfiguration extends Disposable {
|
|||
|
||||
const folder = this.uriIdentityService.extUri.dirname(this.userSettingsResource);
|
||||
const standAloneConfigurationResources: [string, URI][] = [TASKS_CONFIGURATION_KEY].map(name => ([name, this.uriIdentityService.extUri.joinPath(folder, `${name}.json`)]));
|
||||
const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), this.userSettingsResource, standAloneConfigurationResources, this.scopes, this.fileService, this.uriIdentityService, this.logService);
|
||||
const fileServiceBasedConfiguration = new FileServiceBasedConfiguration(folder.toString(), this.userSettingsResource, standAloneConfigurationResources, this.configurationParseOptions, this.fileService, this.uriIdentityService, this.logService);
|
||||
const configurationModel = await fileServiceBasedConfiguration.loadConfiguration();
|
||||
this.userConfiguration.value = fileServiceBasedConfiguration;
|
||||
|
||||
|
@ -70,8 +78,8 @@ export class UserConfiguration extends Disposable {
|
|||
return configurationModel;
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
return this.userConfiguration.value!.reprocess();
|
||||
reparse(): ConfigurationModel {
|
||||
return this.userConfiguration.value!.reparse(this.configurationParseOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +87,7 @@ class FileServiceBasedConfiguration extends Disposable {
|
|||
|
||||
private readonly allResources: URI[];
|
||||
private _folderSettingsModelParser: ConfigurationModelParser;
|
||||
private _folderSettingsParseOptions: ConfigurationParseOptions;
|
||||
private _standAloneConfigurations: ConfigurationModel[];
|
||||
private _cache: ConfigurationModel;
|
||||
|
||||
|
@ -89,7 +98,7 @@ class FileServiceBasedConfiguration extends Disposable {
|
|||
name: string,
|
||||
private readonly settingsResource: URI,
|
||||
private readonly standAloneConfigurationResources: [string, URI][],
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
configurationParseOptions: ConfigurationParseOptions,
|
||||
private readonly fileService: IFileService,
|
||||
private readonly uriIdentityService: IUriIdentityService,
|
||||
private readonly logService: ILogService,
|
||||
|
@ -102,7 +111,8 @@ class FileServiceBasedConfiguration extends Disposable {
|
|||
this.fileService.watch(resource)
|
||||
))));
|
||||
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser(name, this.scopes);
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser(name);
|
||||
this._folderSettingsParseOptions = configurationParseOptions;
|
||||
this._standAloneConfigurations = [];
|
||||
this._cache = new ConfigurationModel();
|
||||
|
||||
|
@ -144,17 +154,17 @@ class FileServiceBasedConfiguration extends Disposable {
|
|||
|
||||
// reset
|
||||
this._standAloneConfigurations = [];
|
||||
this._folderSettingsModelParser.parseContent('');
|
||||
this._folderSettingsModelParser.parse('', this._folderSettingsParseOptions);
|
||||
|
||||
// parse
|
||||
if (settingsContent !== undefined) {
|
||||
this._folderSettingsModelParser.parseContent(settingsContent);
|
||||
this._folderSettingsModelParser.parse(settingsContent, this._folderSettingsParseOptions);
|
||||
}
|
||||
for (let index = 0; index < standAloneConfigurationContents.length; index++) {
|
||||
const contents = standAloneConfigurationContents[index][1];
|
||||
if (contents !== undefined) {
|
||||
const standAloneConfigurationModelParser = new StandaloneConfigurationModelParser(this.standAloneConfigurationResources[index][1].toString(), this.standAloneConfigurationResources[index][0]);
|
||||
standAloneConfigurationModelParser.parseContent(contents);
|
||||
standAloneConfigurationModelParser.parse(contents);
|
||||
this._standAloneConfigurations.push(standAloneConfigurationModelParser.configurationModel);
|
||||
}
|
||||
}
|
||||
|
@ -165,9 +175,14 @@ class FileServiceBasedConfiguration extends Disposable {
|
|||
return this._cache;
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this._folderSettingsModelParser.excludedUnsafeConfigurations;
|
||||
}
|
||||
|
||||
reparse(configurationParseOptions: ConfigurationParseOptions): ConfigurationModel {
|
||||
const oldContents = this._folderSettingsModelParser.configurationModel.contents;
|
||||
this._folderSettingsModelParser.parse();
|
||||
this._folderSettingsParseOptions = configurationParseOptions;
|
||||
this._folderSettingsModelParser.reparse(this._folderSettingsParseOptions);
|
||||
if (!equals(oldContents, this._folderSettingsModelParser.configurationModel.contents)) {
|
||||
this.consolidate();
|
||||
}
|
||||
|
@ -249,8 +264,8 @@ export class RemoteUserConfiguration extends Disposable {
|
|||
return this._userConfiguration.reload();
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
return this._userConfiguration.reprocess();
|
||||
reparse(): ConfigurationModel {
|
||||
return this._userConfiguration.reparse();
|
||||
}
|
||||
|
||||
private onDidUserConfigurationChange(configurationModel: ConfigurationModel): void {
|
||||
|
@ -277,6 +292,7 @@ export class RemoteUserConfiguration extends Disposable {
|
|||
class FileServiceBasedRemoteUserConfiguration extends Disposable {
|
||||
|
||||
private readonly parser: ConfigurationModelParser;
|
||||
private readonly parseOptions: ConfigurationParseOptions;
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
|
||||
|
@ -286,13 +302,14 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable {
|
|||
|
||||
constructor(
|
||||
private readonly configurationResource: URI,
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
scopes: ConfigurationScope[] | undefined,
|
||||
private readonly fileService: IFileService,
|
||||
private readonly uriIdentityService: IUriIdentityService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.parser = new ConfigurationModelParser(this.configurationResource.toString(), this.scopes);
|
||||
this.parser = new ConfigurationModelParser(this.configurationResource.toString());
|
||||
this.parseOptions = { scopes };
|
||||
this._register(fileService.onDidFilesChange(e => this.handleFileEvents(e)));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
|
||||
this._register(toDisposable(() => {
|
||||
|
@ -334,15 +351,15 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable {
|
|||
async reload(): Promise<ConfigurationModel> {
|
||||
try {
|
||||
const content = await this.resolveContent();
|
||||
this.parser.parseContent(content);
|
||||
this.parser.parse(content, this.parseOptions);
|
||||
return this.parser.configurationModel;
|
||||
} catch (e) {
|
||||
return new ConfigurationModel();
|
||||
}
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
this.parser.parse();
|
||||
reparse(): ConfigurationModel {
|
||||
this.parser.reparse(this.parseOptions);
|
||||
return this.parser.configurationModel;
|
||||
}
|
||||
|
||||
|
@ -381,6 +398,7 @@ class CachedRemoteUserConfiguration extends Disposable {
|
|||
|
||||
private readonly key: ConfigurationKey;
|
||||
private readonly parser: ConfigurationModelParser;
|
||||
private readonly parseOptions: ConfigurationParseOptions;
|
||||
private configurationModel: ConfigurationModel;
|
||||
|
||||
constructor(
|
||||
|
@ -390,7 +408,8 @@ class CachedRemoteUserConfiguration extends Disposable {
|
|||
) {
|
||||
super();
|
||||
this.key = { type: 'user', key: remoteAuthority };
|
||||
this.parser = new ConfigurationModelParser('CachedRemoteUserConfiguration', scopes);
|
||||
this.parser = new ConfigurationModelParser('CachedRemoteUserConfiguration');
|
||||
this.parseOptions = { scopes };
|
||||
this.configurationModel = new ConfigurationModel();
|
||||
}
|
||||
|
||||
|
@ -402,8 +421,8 @@ class CachedRemoteUserConfiguration extends Disposable {
|
|||
return this.reload();
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
this.parser.parse();
|
||||
reparse(): ConfigurationModel {
|
||||
this.parser.reparse(this.parseOptions);
|
||||
this.configurationModel = this.parser.configurationModel;
|
||||
return this.configurationModel;
|
||||
}
|
||||
|
@ -413,7 +432,7 @@ class CachedRemoteUserConfiguration extends Disposable {
|
|||
const content = await this.configurationCache.read(this.key);
|
||||
const parsed: { content: string } = JSON.parse(content);
|
||||
if (parsed.content) {
|
||||
this.parser.parseContent(parsed.content);
|
||||
this.parser.parse(parsed.content, this.parseOptions);
|
||||
this.configurationModel = this.parser.configurationModel;
|
||||
}
|
||||
} catch (e) { /* Ignore error */ }
|
||||
|
@ -436,6 +455,7 @@ export class WorkspaceConfiguration extends Disposable {
|
|||
private _workspaceConfiguration: CachedWorkspaceConfiguration | FileServiceBasedWorkspaceConfiguration;
|
||||
private _workspaceConfigurationDisposables = this._register(new DisposableStore());
|
||||
private _workspaceIdentifier: IWorkspaceIdentifier | null = null;
|
||||
private _workspaceTrustState: WorkspaceTrustState | null = null;
|
||||
|
||||
private readonly _onDidUpdateConfiguration: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidUpdateConfiguration: Event<void> = this._onDidUpdateConfiguration.event;
|
||||
|
@ -451,8 +471,9 @@ export class WorkspaceConfiguration extends Disposable {
|
|||
this._workspaceConfiguration = this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache);
|
||||
}
|
||||
|
||||
async initialize(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
async initialize(workspaceIdentifier: IWorkspaceIdentifier, workspaceTrustState: WorkspaceTrustState): Promise<void> {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
this._workspaceTrustState = workspaceTrustState;
|
||||
if (!this._initialized) {
|
||||
if (this.configurationCache.needsCaching(this._workspaceIdentifier.configPath)) {
|
||||
this._workspaceConfiguration = this._cachedConfiguration;
|
||||
|
@ -466,7 +487,7 @@ export class WorkspaceConfiguration extends Disposable {
|
|||
|
||||
async reload(): Promise<void> {
|
||||
if (this._workspaceIdentifier) {
|
||||
await this._workspaceConfiguration.load(this._workspaceIdentifier);
|
||||
await this._workspaceConfiguration.load(this._workspaceIdentifier, { scopes: WORKSPACE_SCOPES, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,16 +507,25 @@ export class WorkspaceConfiguration extends Disposable {
|
|||
return this._workspaceConfiguration.getWorkspaceSettings();
|
||||
}
|
||||
|
||||
reprocessWorkspaceSettings(): ConfigurationModel {
|
||||
this._workspaceConfiguration.reprocessWorkspaceSettings();
|
||||
updateWorkspaceTrustState(workspaceTrustState: WorkspaceTrustState): ConfigurationModel {
|
||||
this._workspaceTrustState = workspaceTrustState;
|
||||
return this.reparseWorkspaceSettings();
|
||||
}
|
||||
|
||||
reparseWorkspaceSettings(): ConfigurationModel {
|
||||
this._workspaceConfiguration.reparseWorkspaceSettings({ scopes: WORKSPACE_SCOPES, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() });
|
||||
return this.getConfiguration();
|
||||
}
|
||||
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this._workspaceConfiguration.getExcludedUnsafeSettings();
|
||||
}
|
||||
|
||||
private async waitAndInitialize(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
await whenProviderRegistered(workspaceIdentifier.configPath, this._fileService);
|
||||
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
|
||||
const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._fileService));
|
||||
await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier);
|
||||
await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier, { scopes: WORKSPACE_SCOPES, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() });
|
||||
this.doInitialize(fileServiceBasedWorkspaceConfiguration);
|
||||
this.onDidWorkspaceConfigurationChange(false);
|
||||
}
|
||||
|
@ -508,6 +538,10 @@ export class WorkspaceConfiguration extends Disposable {
|
|||
this._initialized = true;
|
||||
}
|
||||
|
||||
private hasToExcludeUnsafeConfigurations(): boolean | undefined {
|
||||
return this._workspaceTrustState !== null ? hasToExcludeUnsafeConfigurations(this._workspaceTrustState) : undefined;
|
||||
}
|
||||
|
||||
private async onDidWorkspaceConfigurationChange(reload: boolean): Promise<void> {
|
||||
if (reload) {
|
||||
await this.reload();
|
||||
|
@ -555,7 +589,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable {
|
|||
return content.value.toString();
|
||||
}
|
||||
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier, configurationParseOptions: ConfigurationParseOptions): Promise<void> {
|
||||
if (!this._workspaceIdentifier || this._workspaceIdentifier.id !== workspaceIdentifier.id) {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(this._workspaceIdentifier.id);
|
||||
|
@ -571,7 +605,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable {
|
|||
errors.onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
this.workspaceConfigurationModelParser.parseContent(contents);
|
||||
this.workspaceConfigurationModelParser.parse(contents, configurationParseOptions);
|
||||
this.consolidate();
|
||||
}
|
||||
|
||||
|
@ -587,12 +621,16 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable {
|
|||
return this.workspaceSettings;
|
||||
}
|
||||
|
||||
reprocessWorkspaceSettings(): ConfigurationModel {
|
||||
this.workspaceConfigurationModelParser.reprocessWorkspaceSettings();
|
||||
reparseWorkspaceSettings(configurationParseOptions: ConfigurationParseOptions): ConfigurationModel {
|
||||
this.workspaceConfigurationModelParser.reparseWorkspaceSettings(configurationParseOptions);
|
||||
this.consolidate();
|
||||
return this.getWorkspaceSettings();
|
||||
}
|
||||
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this.workspaceConfigurationModelParser.excludedUnsafeConfigurations;
|
||||
}
|
||||
|
||||
private consolidate(): void {
|
||||
this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel, this.workspaceConfigurationModelParser.tasksModel);
|
||||
}
|
||||
|
@ -624,14 +662,14 @@ class CachedWorkspaceConfiguration {
|
|||
this.workspaceSettings = new ConfigurationModel();
|
||||
}
|
||||
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier, configurationParseOptions: ConfigurationParseOptions): Promise<void> {
|
||||
try {
|
||||
const key = this.getKey(workspaceIdentifier);
|
||||
const contents = await this.configurationCache.read(key);
|
||||
const parsed: { content: string } = JSON.parse(contents);
|
||||
if (parsed.content) {
|
||||
this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(key.key);
|
||||
this.workspaceConfigurationModelParser.parseContent(parsed.content);
|
||||
this.workspaceConfigurationModelParser.parse(parsed.content, configurationParseOptions);
|
||||
this.consolidate();
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -654,12 +692,16 @@ class CachedWorkspaceConfiguration {
|
|||
return this.workspaceSettings;
|
||||
}
|
||||
|
||||
reprocessWorkspaceSettings(): ConfigurationModel {
|
||||
this.workspaceConfigurationModelParser.reprocessWorkspaceSettings();
|
||||
reparseWorkspaceSettings(configurationParseOptions: ConfigurationParseOptions): ConfigurationModel {
|
||||
this.workspaceConfigurationModelParser.reparseWorkspaceSettings(configurationParseOptions);
|
||||
this.consolidate();
|
||||
return this.getWorkspaceSettings();
|
||||
}
|
||||
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this.workspaceConfigurationModelParser.excludedUnsafeConfigurations;
|
||||
}
|
||||
|
||||
private consolidate(): void {
|
||||
this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel, this.workspaceConfigurationModelParser.tasksModel);
|
||||
}
|
||||
|
@ -689,6 +731,7 @@ class CachedFolderConfiguration {
|
|||
readonly onDidChange = Event.None;
|
||||
|
||||
private _folderSettingsModelParser: ConfigurationModelParser;
|
||||
private _folderSettingsParseOptions: ConfigurationParseOptions;
|
||||
private _standAloneConfigurations: ConfigurationModel[];
|
||||
private configurationModel: ConfigurationModel;
|
||||
private readonly key: ConfigurationKey;
|
||||
|
@ -696,11 +739,12 @@ class CachedFolderConfiguration {
|
|||
constructor(
|
||||
folder: URI,
|
||||
configFolderRelativePath: string,
|
||||
configurationParseOptions: ConfigurationParseOptions,
|
||||
private readonly configurationCache: IConfigurationCache,
|
||||
scopes: ConfigurationScope[],
|
||||
) {
|
||||
this.key = { type: 'folder', key: hash(join(folder.path, configFolderRelativePath)).toString(16) };
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser('CachedFolderConfiguration', scopes);
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser('CachedFolderConfiguration');
|
||||
this._folderSettingsParseOptions = configurationParseOptions;
|
||||
this._standAloneConfigurations = [];
|
||||
this.configurationModel = new ConfigurationModel();
|
||||
}
|
||||
|
@ -712,10 +756,10 @@ class CachedFolderConfiguration {
|
|||
if (configurationContents) {
|
||||
for (const key of Object.keys(configurationContents)) {
|
||||
if (key === FOLDER_SETTINGS_NAME) {
|
||||
this._folderSettingsModelParser.parseContent(configurationContents[key]);
|
||||
this._folderSettingsModelParser.parse(configurationContents[key], this._folderSettingsParseOptions);
|
||||
} else {
|
||||
const standAloneConfigurationModelParser = new StandaloneConfigurationModelParser(key, key);
|
||||
standAloneConfigurationModelParser.parseContent(configurationContents[key]);
|
||||
standAloneConfigurationModelParser.parse(configurationContents[key]);
|
||||
this._standAloneConfigurations.push(standAloneConfigurationModelParser.configurationModel);
|
||||
}
|
||||
}
|
||||
|
@ -743,8 +787,13 @@ class CachedFolderConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
this._folderSettingsModelParser.parse();
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this._folderSettingsModelParser.excludedUnsafeConfigurations;
|
||||
}
|
||||
|
||||
reparse(configurationParseOptions: ConfigurationParseOptions): ConfigurationModel {
|
||||
this._folderSettingsParseOptions = configurationParseOptions;
|
||||
this._folderSettingsModelParser.reparse(this._folderSettingsParseOptions);
|
||||
this.consolidate();
|
||||
return this.configurationModel;
|
||||
}
|
||||
|
@ -764,6 +813,7 @@ export class FolderConfiguration extends Disposable {
|
|||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
private folderConfiguration: CachedFolderConfiguration | FileServiceBasedConfiguration;
|
||||
private readonly scopes: ConfigurationScope[];
|
||||
private readonly configurationFolder: URI;
|
||||
private cachedFolderConfiguration: CachedFolderConfiguration;
|
||||
|
||||
|
@ -771,6 +821,7 @@ export class FolderConfiguration extends Disposable {
|
|||
readonly workspaceFolder: IWorkspaceFolder,
|
||||
configFolderRelativePath: string,
|
||||
private readonly workbenchState: WorkbenchState,
|
||||
private workspaceTrustState: WorkspaceTrustState,
|
||||
fileService: IFileService,
|
||||
uriIdentityService: IUriIdentityService,
|
||||
logService: ILogService,
|
||||
|
@ -778,19 +829,19 @@ export class FolderConfiguration extends Disposable {
|
|||
) {
|
||||
super();
|
||||
|
||||
const scopes = WorkbenchState.WORKSPACE === this.workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES;
|
||||
this.scopes = WorkbenchState.WORKSPACE === this.workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES;
|
||||
this.configurationFolder = uriIdentityService.extUri.joinPath(workspaceFolder.uri, configFolderRelativePath);
|
||||
this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache, scopes);
|
||||
this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, { scopes: this.scopes, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() }, configurationCache);
|
||||
if (this.configurationCache.needsCaching(workspaceFolder.uri)) {
|
||||
this.folderConfiguration = this.cachedFolderConfiguration;
|
||||
whenProviderRegistered(workspaceFolder.uri, fileService)
|
||||
.then(() => {
|
||||
this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(scopes, fileService, uriIdentityService, logService));
|
||||
this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService, logService));
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
this.onDidFolderConfigurationChange();
|
||||
});
|
||||
} else {
|
||||
this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(scopes, fileService, uriIdentityService, logService));
|
||||
this.folderConfiguration = this._register(this.createFileServiceBasedConfiguration(fileService, uriIdentityService, logService));
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
}
|
||||
}
|
||||
|
@ -799,21 +850,34 @@ export class FolderConfiguration extends Disposable {
|
|||
return this.folderConfiguration.loadConfiguration();
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
const configurationModel = this.folderConfiguration.reprocess();
|
||||
updateWorkspaceTrustState(workspaceTrustState: WorkspaceTrustState): ConfigurationModel {
|
||||
this.workspaceTrustState = workspaceTrustState;
|
||||
return this.reparse();
|
||||
}
|
||||
|
||||
reparse(): ConfigurationModel {
|
||||
const configurationModel = this.folderConfiguration.reparse({ scopes: this.scopes, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() });
|
||||
this.updateCache();
|
||||
return configurationModel;
|
||||
}
|
||||
|
||||
getExcludedUnsafeSettings(): string[] {
|
||||
return this.folderConfiguration.getExcludedUnsafeSettings();
|
||||
}
|
||||
|
||||
private hasToExcludeUnsafeConfigurations(): boolean {
|
||||
return hasToExcludeUnsafeConfigurations(this.workspaceTrustState);
|
||||
}
|
||||
|
||||
private onDidFolderConfigurationChange(): void {
|
||||
this.updateCache();
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
|
||||
private createFileServiceBasedConfiguration(scopes: ConfigurationScope[], fileService: IFileService, uriIdentityService: IUriIdentityService, logService: ILogService) {
|
||||
private createFileServiceBasedConfiguration(fileService: IFileService, uriIdentityService: IUriIdentityService, logService: ILogService) {
|
||||
const settingsResource = uriIdentityService.extUri.joinPath(this.configurationFolder, `${FOLDER_SETTINGS_NAME}.json`);
|
||||
const standAloneConfigurationResources: [string, URI][] = [TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY].map(name => ([name, uriIdentityService.extUri.joinPath(this.configurationFolder, `${name}.json`)]));
|
||||
return new FileServiceBasedConfiguration(this.configurationFolder.toString(), settingsResource, standAloneConfigurationResources, scopes, fileService, uriIdentityService, logService);
|
||||
return new FileServiceBasedConfiguration(this.configurationFolder.toString(), settingsResource, standAloneConfigurationResources, { scopes: this.scopes, excludeUnsafeConfigurations: this.hasToExcludeUnsafeConfigurations() }, fileService, uriIdentityService, logService);
|
||||
}
|
||||
|
||||
private async updateCache(): Promise<void> {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Queue, Barrier, runWhenIdle, Promises } from 'vs/base/common/async';
|
|||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { IWorkspaceContextService, Workspace as BaseWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder, isWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent, mergeChanges } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationValue, IConfigurationChange, ConfigurationTargetToString, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
@ -32,6 +32,8 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
|
|||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { delta, distinct } from 'vs/base/common/arrays';
|
||||
|
||||
class Workspace extends BaseWorkspace {
|
||||
initialized: boolean = false;
|
||||
|
@ -58,18 +60,25 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
private readonly fileService: IFileService;
|
||||
private readonly uriIdentityService: IUriIdentityService;
|
||||
|
||||
protected readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
|
||||
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
|
||||
public readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
||||
|
||||
protected readonly _onDidChangeWorkspaceFolders: Emitter<IWorkspaceFoldersChangeEvent> = this._register(new Emitter<IWorkspaceFoldersChangeEvent>());
|
||||
private readonly _onDidChangeWorkspaceFolders: Emitter<IWorkspaceFoldersChangeEvent> = this._register(new Emitter<IWorkspaceFoldersChangeEvent>());
|
||||
public readonly onDidChangeWorkspaceFolders: Event<IWorkspaceFoldersChangeEvent> = this._onDidChangeWorkspaceFolders.event;
|
||||
|
||||
protected readonly _onDidChangeWorkspaceName: Emitter<void> = this._register(new Emitter<void>());
|
||||
private readonly _onDidChangeWorkspaceName: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeWorkspaceName: Event<void> = this._onDidChangeWorkspaceName.event;
|
||||
|
||||
protected readonly _onDidChangeWorkbenchState: Emitter<WorkbenchState> = this._register(new Emitter<WorkbenchState>());
|
||||
private readonly _onDidChangeWorkbenchState: Emitter<WorkbenchState> = this._register(new Emitter<WorkbenchState>());
|
||||
public readonly onDidChangeWorkbenchState: Event<WorkbenchState> = this._onDidChangeWorkbenchState.event;
|
||||
|
||||
private readonly _onDidChangeUnsafeWorkspaceSettings = this._register(new Emitter<ReadonlyArray<string>>());
|
||||
public readonly onDidChangeUnsafeWorkspaceSettings = this._onDidChangeUnsafeWorkspaceSettings.event;
|
||||
|
||||
private workspaceTrustState: WorkspaceTrustState = WorkspaceTrustState.Trusted;
|
||||
private _unSafeWorkspaceSettings: string[] = [];
|
||||
get unSafeWorkspaceSettings() { return this._unSafeWorkspaceSettings; }
|
||||
|
||||
private readonly configurationRegistry: IConfigurationRegistry;
|
||||
|
||||
// TODO@sandeep debt with cyclic dependencies
|
||||
|
@ -390,6 +399,34 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
mark('code/didInitWorkspaceService');
|
||||
}
|
||||
|
||||
updateWorkspaceTrustState(workspaceTrustState: WorkspaceTrustState): void {
|
||||
if (this.workspaceTrustState !== workspaceTrustState) {
|
||||
this.workspaceTrustState = workspaceTrustState;
|
||||
const data = this._configuration.toData();
|
||||
const folderConfigurationModels: (ConfigurationModel | undefined)[] = [];
|
||||
for (const folder of this.workspace.folders) {
|
||||
const folderConfiguration = this.cachedFolderConfigs.get(folder.uri);
|
||||
let configurationModel: ConfigurationModel | undefined;
|
||||
if (folderConfiguration) {
|
||||
configurationModel = folderConfiguration.updateWorkspaceTrustState(this.workspaceTrustState);
|
||||
this._configuration.updateFolderConfiguration(folder.uri, configurationModel);
|
||||
}
|
||||
folderConfigurationModels.push(configurationModel);
|
||||
}
|
||||
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
if (folderConfigurationModels[0]) {
|
||||
this._configuration.updateWorkspaceConfiguration(folderConfigurationModels[0]);
|
||||
}
|
||||
} else {
|
||||
this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.updateWorkspaceTrustState(this.workspaceTrustState));
|
||||
}
|
||||
const keys = this.updateUnsafeWorkpsaceSettings();
|
||||
if (keys.length) {
|
||||
this.triggerConfigurationChange({ keys, overrides: [] }, { data, workspace: this.workspace }, ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acquireInstantiationService(instantiationService: IInstantiationService): void {
|
||||
this.configurationEditingService = instantiationService.createInstance(ConfigurationEditingService);
|
||||
this.jsonEditingService = instantiationService.createInstance(JSONEditingService);
|
||||
|
@ -401,7 +438,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
}
|
||||
}
|
||||
|
||||
private createWorkspace(arg: IWorkspaceInitializationPayload): Promise<Workspace> {
|
||||
private async createWorkspace(arg: IWorkspaceInitializationPayload): Promise<Workspace> {
|
||||
if (isWorkspaceIdentifier(arg)) {
|
||||
return this.createMultiFolderWorkspace(arg);
|
||||
}
|
||||
|
@ -413,22 +450,20 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
return this.createEmptyWorkspace(arg);
|
||||
}
|
||||
|
||||
private createMultiFolderWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise<Workspace> {
|
||||
return this.workspaceConfiguration.initialize({ id: workspaceIdentifier.id, configPath: workspaceIdentifier.configPath })
|
||||
.then(() => {
|
||||
const workspaceConfigPath = workspaceIdentifier.configPath;
|
||||
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), workspaceConfigPath, this.uriIdentityService.extUri);
|
||||
const workspaceId = workspaceIdentifier.id;
|
||||
const workspace = new Workspace(workspaceId, workspaceFolders, workspaceConfigPath, uri => this.uriIdentityService.extUri.ignorePathCasing(uri));
|
||||
workspace.initialized = this.workspaceConfiguration.initialized;
|
||||
return workspace;
|
||||
});
|
||||
private async createMultiFolderWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise<Workspace> {
|
||||
await this.workspaceConfiguration.initialize({ id: workspaceIdentifier.id, configPath: workspaceIdentifier.configPath }, this.workspaceTrustState);
|
||||
const workspaceConfigPath = workspaceIdentifier.configPath;
|
||||
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), workspaceConfigPath, this.uriIdentityService.extUri);
|
||||
const workspaceId = workspaceIdentifier.id;
|
||||
const workspace = new Workspace(workspaceId, workspaceFolders, workspaceConfigPath, uri => this.uriIdentityService.extUri.ignorePathCasing(uri));
|
||||
workspace.initialized = this.workspaceConfiguration.initialized;
|
||||
return workspace;
|
||||
}
|
||||
|
||||
private createSingleFolderWorkspace(singleFolderWorkspaceIdentifier: ISingleFolderWorkspaceIdentifier): Promise<Workspace> {
|
||||
private createSingleFolderWorkspace(singleFolderWorkspaceIdentifier: ISingleFolderWorkspaceIdentifier): Workspace {
|
||||
const workspace = new Workspace(singleFolderWorkspaceIdentifier.id, [toWorkspaceFolder(singleFolderWorkspaceIdentifier.uri)], null, uri => this.uriIdentityService.extUri.ignorePathCasing(uri));
|
||||
workspace.initialized = true;
|
||||
return Promise.resolve(workspace);
|
||||
return workspace;
|
||||
}
|
||||
|
||||
private createEmptyWorkspace(emptyWorkspaceIdentifier: IEmptyWorkspaceIdentifier): Promise<Workspace> {
|
||||
|
@ -505,9 +540,9 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
return result;
|
||||
}
|
||||
|
||||
private initializeConfiguration(): Promise<void> {
|
||||
return this.initializeUserConfiguration()
|
||||
.then(({ local, remote }) => this.loadConfiguration(local, remote));
|
||||
private async initializeConfiguration(): Promise<void> {
|
||||
const { local, remote } = await this.initializeUserConfiguration();
|
||||
await this.loadConfiguration(local, remote);
|
||||
}
|
||||
|
||||
private initializeUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
|
||||
|
@ -553,29 +588,29 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
return this.onWorkspaceFolderConfigurationChanged(folder);
|
||||
}
|
||||
|
||||
private loadConfiguration(userConfigurationModel: ConfigurationModel, remoteUserConfigurationModel: ConfigurationModel): Promise<void> {
|
||||
private async loadConfiguration(userConfigurationModel: ConfigurationModel, remoteUserConfigurationModel: ConfigurationModel): Promise<void> {
|
||||
// reset caches
|
||||
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
|
||||
|
||||
const folders = this.workspace.folders;
|
||||
return this.loadFolderConfigurations(folders)
|
||||
.then((folderConfigurations) => {
|
||||
const folderConfigurations = await this.loadFolderConfigurations(folders);
|
||||
|
||||
let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations);
|
||||
const folderConfigurationModels = new ResourceMap<ConfigurationModel>();
|
||||
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
|
||||
let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations);
|
||||
const folderConfigurationModels = new ResourceMap<ConfigurationModel>();
|
||||
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
|
||||
|
||||
const currentConfiguration = this._configuration;
|
||||
this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
||||
const currentConfiguration = this._configuration;
|
||||
this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
|
||||
|
||||
if (this.initialized) {
|
||||
const change = this._configuration.compare(currentConfiguration);
|
||||
this.triggerConfigurationChange(change, { data: currentConfiguration.toData(), workspace: this.workspace }, ConfigurationTarget.WORKSPACE);
|
||||
} else {
|
||||
this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration, this.workspace, ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE)));
|
||||
this.initialized = true;
|
||||
}
|
||||
});
|
||||
if (this.initialized) {
|
||||
const change = this._configuration.compare(currentConfiguration);
|
||||
this.triggerConfigurationChange(change, { data: currentConfiguration.toData(), workspace: this.workspace }, ConfigurationTarget.WORKSPACE);
|
||||
} else {
|
||||
this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration, this.workspace, ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE)));
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
this.updateUnsafeWorkpsaceSettings();
|
||||
}
|
||||
|
||||
private getWorkspaceConfigurationModel(folderConfigurations: ConfigurationModel[]): ConfigurationModel {
|
||||
|
@ -595,25 +630,26 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
const previousData = this._configuration.toData();
|
||||
const change = this._configuration.compareAndUpdateDefaultConfiguration(this.defaultConfiguration, keys);
|
||||
if (this.remoteUserConfiguration) {
|
||||
this._configuration.updateLocalUserConfiguration(this.localUserConfiguration.reprocess());
|
||||
this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reprocess());
|
||||
this._configuration.updateLocalUserConfiguration(this.localUserConfiguration.reparse());
|
||||
this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reparse());
|
||||
}
|
||||
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
const folderConfiguration = this.cachedFolderConfigs.get(this.workspace.folders[0].uri);
|
||||
if (folderConfiguration) {
|
||||
this._configuration.updateWorkspaceConfiguration(folderConfiguration.reprocess());
|
||||
this._configuration.updateFolderConfiguration(this.workspace.folders[0].uri, folderConfiguration.reprocess());
|
||||
this._configuration.updateWorkspaceConfiguration(folderConfiguration.reparse());
|
||||
this._configuration.updateFolderConfiguration(this.workspace.folders[0].uri, folderConfiguration.reparse());
|
||||
}
|
||||
} else {
|
||||
this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.reprocessWorkspaceSettings());
|
||||
this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.reparseWorkspaceSettings());
|
||||
for (const folder of this.workspace.folders) {
|
||||
const folderConfiguration = this.cachedFolderConfigs.get(folder.uri);
|
||||
if (folderConfiguration) {
|
||||
this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration.reprocess());
|
||||
this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration.reparse());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.triggerConfigurationChange(change, { data: previousData, workspace: this.workspace }, ConfigurationTarget.DEFAULT);
|
||||
this.updateUnsafeWorkpsaceSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -651,6 +687,24 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
}
|
||||
}
|
||||
|
||||
private updateUnsafeWorkpsaceSettings(): string[] {
|
||||
let unsafeWorkspaceSettings = [];
|
||||
if (this.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
unsafeWorkspaceSettings.push(...this.workspaceConfiguration.getExcludedUnsafeSettings());
|
||||
}
|
||||
for (const folderConfig of this.cachedFolderConfigs.values()) {
|
||||
unsafeWorkspaceSettings.push(...folderConfig.getExcludedUnsafeSettings());
|
||||
}
|
||||
unsafeWorkspaceSettings = distinct(unsafeWorkspaceSettings).sort((a, b) => a.localeCompare(b));
|
||||
const { removed, added } = delta(unsafeWorkspaceSettings, this._unSafeWorkspaceSettings, (a, b) => a.localeCompare(b));
|
||||
const changed = [...removed, ...added];
|
||||
if (changed.length) {
|
||||
this._unSafeWorkspaceSettings = unsafeWorkspaceSettings;
|
||||
this._onDidChangeUnsafeWorkspaceSettings.fire(this.unSafeWorkspaceSettings);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private async updateWorkspaceConfiguration(workspaceFolders: WorkspaceFolder[], configuration: ConfigurationModel): Promise<void> {
|
||||
const previous = { data: this._configuration.toData(), workspace: this.workspace };
|
||||
const change = this._configuration.compareAndUpdateWorkspaceConfiguration(configuration);
|
||||
|
@ -663,20 +717,20 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
} else {
|
||||
this.triggerConfigurationChange(change, previous, ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
this.updateUnsafeWorkpsaceSettings();
|
||||
}
|
||||
|
||||
private onWorkspaceFolderConfigurationChanged(folder: IWorkspaceFolder): Promise<void> {
|
||||
return this.loadFolderConfigurations([folder])
|
||||
.then(([folderConfiguration]) => {
|
||||
const previous = { data: this._configuration.toData(), workspace: this.workspace };
|
||||
const folderConfiguraitonChange = this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration);
|
||||
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
const workspaceConfigurationChange = this._configuration.compareAndUpdateWorkspaceConfiguration(folderConfiguration);
|
||||
this.triggerConfigurationChange(mergeChanges(folderConfiguraitonChange, workspaceConfigurationChange), previous, ConfigurationTarget.WORKSPACE);
|
||||
} else {
|
||||
this.triggerConfigurationChange(folderConfiguraitonChange, previous, ConfigurationTarget.WORKSPACE_FOLDER);
|
||||
}
|
||||
});
|
||||
private async onWorkspaceFolderConfigurationChanged(folder: IWorkspaceFolder): Promise<void> {
|
||||
const [folderConfiguration] = await this.loadFolderConfigurations([folder]);
|
||||
const previous = { data: this._configuration.toData(), workspace: this.workspace };
|
||||
const folderConfiguraitonChange = this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration);
|
||||
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
const workspaceConfigurationChange = this._configuration.compareAndUpdateWorkspaceConfiguration(folderConfiguration);
|
||||
this.triggerConfigurationChange(mergeChanges(folderConfiguraitonChange, workspaceConfigurationChange), previous, ConfigurationTarget.WORKSPACE);
|
||||
} else {
|
||||
this.triggerConfigurationChange(folderConfiguraitonChange, previous, ConfigurationTarget.WORKSPACE_FOLDER);
|
||||
}
|
||||
this.updateUnsafeWorkpsaceSettings();
|
||||
}
|
||||
|
||||
private async onFoldersChanged(): Promise<IConfigurationChange> {
|
||||
|
@ -706,7 +760,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
return Promise.all([...folders.map(folder => {
|
||||
let folderConfiguration = this.cachedFolderConfigs.get(folder.uri);
|
||||
if (!folderConfiguration) {
|
||||
folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.uriIdentityService, this.logService, this.configurationCache);
|
||||
folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.workspaceTrustState, this.fileService, this.uriIdentityService, this.logService, this.configurationCache);
|
||||
this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder)));
|
||||
this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration));
|
||||
}
|
||||
|
@ -860,6 +914,17 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
}
|
||||
}
|
||||
|
||||
class ConfigurationWorkspaceTrustContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IWorkspaceTrustService workspaceTrustService: IWorkspaceTrustService,
|
||||
@IConfigurationService configurationService: WorkspaceService
|
||||
) {
|
||||
super();
|
||||
configurationService.updateWorkspaceTrustState(workspaceTrustService.getWorkspaceTrustState());
|
||||
this._register(workspaceTrustService.onDidChangeTrustState(e => configurationService.updateWorkspaceTrustState(workspaceTrustService.getWorkspaceTrustState())));
|
||||
}
|
||||
}
|
||||
|
||||
class RegisterConfigurationSchemasContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
|
@ -900,4 +965,6 @@ class RegisterConfigurationSchemasContribution extends Disposable implements IWo
|
|||
}
|
||||
}
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored);
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(ConfigurationWorkspaceTrustContribution, LifecyclePhase.Restored);
|
||||
|
|
|
@ -7,6 +7,7 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurati
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export const FOLDER_CONFIG_FOLDER_NAME = '.vscode';
|
||||
export const FOLDER_SETTINGS_NAME = 'settings';
|
||||
|
@ -47,6 +48,16 @@ export interface IConfigurationCache {
|
|||
|
||||
export const IWorkbenchConfigurationService = refineServiceDecorator<IConfigurationService, IWorkbenchConfigurationService>(IConfigurationService);
|
||||
export interface IWorkbenchConfigurationService extends IConfigurationService {
|
||||
/**
|
||||
* List of unsafe workspace settings found in current workspace
|
||||
*/
|
||||
readonly unSafeWorkspaceSettings: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* Event that triggers when the list of unsafe workspace settings changes
|
||||
*/
|
||||
readonly onDidChangeUnsafeWorkspaceSettings: Event<ReadonlyArray<string>>;
|
||||
|
||||
/**
|
||||
* A promise that resolves when the remote configuration is loaded in a remote window.
|
||||
* The promise is resolved immediately if the window is not remote.
|
||||
|
|
|
@ -5,12 +5,11 @@
|
|||
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
import { toValuesTree, IConfigurationModel, IConfigurationOverrides, IConfigurationValue, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
||||
import { Configuration as BaseConfiguration, ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { Configuration as BaseConfiguration, ConfigurationModelParser, ConfigurationModel, ConfigurationParseOptions } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { OVERRIDE_PROPERTY_PATTERN, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
||||
export class WorkspaceConfigurationModelParser extends ConfigurationModelParser {
|
||||
|
@ -22,7 +21,7 @@ export class WorkspaceConfigurationModelParser extends ConfigurationModelParser
|
|||
|
||||
constructor(name: string) {
|
||||
super(name);
|
||||
this._settingsModelParser = new ConfigurationModelParser(name, WORKSPACE_SCOPES);
|
||||
this._settingsModelParser = new ConfigurationModelParser(name);
|
||||
this._launchModel = new ConfigurationModel();
|
||||
this._tasksModel = new ConfigurationModel();
|
||||
}
|
||||
|
@ -43,16 +42,16 @@ export class WorkspaceConfigurationModelParser extends ConfigurationModelParser
|
|||
return this._tasksModel;
|
||||
}
|
||||
|
||||
reprocessWorkspaceSettings(): void {
|
||||
this._settingsModelParser.parse();
|
||||
reparseWorkspaceSettings(configurationParseOptions: ConfigurationParseOptions): void {
|
||||
this._settingsModelParser.reparse(configurationParseOptions);
|
||||
}
|
||||
|
||||
protected override doParseRaw(raw: any): IConfigurationModel {
|
||||
protected override doParseRaw(raw: any, configurationParseOptions?: ConfigurationParseOptions): IConfigurationModel {
|
||||
this._folders = (raw['folders'] || []) as IStoredWorkspaceFolder[];
|
||||
this._settingsModelParser.parseRaw(raw['settings']);
|
||||
this._settingsModelParser.parseRaw(raw['settings'], configurationParseOptions);
|
||||
this._launchModel = this.createConfigurationModelFrom(raw, 'launch');
|
||||
this._tasksModel = this.createConfigurationModelFrom(raw, 'tasks');
|
||||
return super.doParseRaw(raw);
|
||||
return super.doParseRaw(raw, configurationParseOptions);
|
||||
}
|
||||
|
||||
private createConfigurationModelFrom(raw: any, key: string): ConfigurationModel {
|
||||
|
@ -74,7 +73,7 @@ export class StandaloneConfigurationModelParser extends ConfigurationModelParser
|
|||
super(name);
|
||||
}
|
||||
|
||||
protected override doParseRaw(raw: any): IConfigurationModel {
|
||||
protected override doParseRaw(raw: any, configurationParseOptions?: ConfigurationParseOptions): IConfigurationModel {
|
||||
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
const scopedContents = Object.create(null);
|
||||
scopedContents[this.scope] = contents;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import * as assert from 'assert';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { StandaloneConfigurationModelParser, Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
import { ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { ConfigurationModelParser, ConfigurationModel, ConfigurationParseOptions } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -49,9 +49,9 @@ suite('FolderSettingsModelParser', () => {
|
|||
});
|
||||
|
||||
test('parse all folder settings', () => {
|
||||
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]);
|
||||
const testObject = new ConfigurationModelParser('settings');
|
||||
|
||||
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }));
|
||||
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }), { scopes: [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW] });
|
||||
|
||||
const expected = Object.create(null);
|
||||
expected['FolderSettingsModelParser'] = Object.create(null);
|
||||
|
@ -61,9 +61,9 @@ suite('FolderSettingsModelParser', () => {
|
|||
});
|
||||
|
||||
test('parse resource folder settings', () => {
|
||||
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE]);
|
||||
const testObject = new ConfigurationModelParser('settings');
|
||||
|
||||
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }));
|
||||
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }), { scopes: [ConfigurationScope.RESOURCE] });
|
||||
|
||||
const expected = Object.create(null);
|
||||
expected['FolderSettingsModelParser'] = Object.create(null);
|
||||
|
@ -72,9 +72,9 @@ suite('FolderSettingsModelParser', () => {
|
|||
});
|
||||
|
||||
test('parse resource and resource language settings', () => {
|
||||
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE]);
|
||||
const testObject = new ConfigurationModelParser('settings');
|
||||
|
||||
testObject.parseContent(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.resourceLanguage': 'resourceLanguage', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' } }));
|
||||
testObject.parse(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.resourceLanguage': 'resourceLanguage', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' } }), { scopes: [ConfigurationScope.RESOURCE, ConfigurationScope.LANGUAGE_OVERRIDABLE] });
|
||||
|
||||
const expected = Object.create(null);
|
||||
expected['FolderSettingsModelParser'] = Object.create(null);
|
||||
|
@ -83,10 +83,11 @@ suite('FolderSettingsModelParser', () => {
|
|||
assert.deepStrictEqual(testObject.configurationModel.overrides, [{ 'contents': expected, 'identifiers': ['json'], 'keys': ['FolderSettingsModelParser.resource', 'FolderSettingsModelParser.resourceLanguage'] }]);
|
||||
});
|
||||
|
||||
test('reprocess folder settings excludes application and machine setting', () => {
|
||||
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]);
|
||||
test('reparse folder settings excludes application and machine setting', () => {
|
||||
const parseOptions: ConfigurationParseOptions = { scopes: [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW] };
|
||||
const testObject = new ConfigurationModelParser('settings');
|
||||
|
||||
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.anotherApplicationSetting': 'executable' }));
|
||||
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.anotherApplicationSetting': 'executable' }), parseOptions);
|
||||
|
||||
let expected = Object.create(null);
|
||||
expected['FolderSettingsModelParser'] = Object.create(null);
|
||||
|
@ -112,7 +113,7 @@ suite('FolderSettingsModelParser', () => {
|
|||
}
|
||||
});
|
||||
|
||||
testObject.parse();
|
||||
testObject.reparse(parseOptions);
|
||||
|
||||
expected = Object.create(null);
|
||||
expected['FolderSettingsModelParser'] = Object.create(null);
|
||||
|
@ -127,7 +128,7 @@ suite('StandaloneConfigurationModelParser', () => {
|
|||
test('parse tasks stand alone configuration model', () => {
|
||||
const testObject = new StandaloneConfigurationModelParser('tasks', 'tasks');
|
||||
|
||||
testObject.parseContent(JSON.stringify({ 'version': '1.1.1', 'tasks': [] }));
|
||||
testObject.parse(JSON.stringify({ 'version': '1.1.1', 'tasks': [] }));
|
||||
|
||||
const expected = Object.create(null);
|
||||
expected['tasks'] = Object.create(null);
|
||||
|
@ -204,6 +205,6 @@ suite('Workspace Configuration', () => {
|
|||
|
||||
function toConfigurationModel(obj: any): ConfigurationModel {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify(obj));
|
||||
parser.parse(JSON.stringify(obj));
|
||||
return parser.configurationModel;
|
||||
}
|
||||
|
|
|
@ -732,7 +732,7 @@ suite('ExtHostConfiguration', function () {
|
|||
|
||||
function toConfigurationModel(obj: any): ConfigurationModel {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parseContent(JSON.stringify(obj));
|
||||
parser.parse(JSON.stringify(obj));
|
||||
return parser.configurationModel;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue