Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -6,11 +6,10 @@
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const CONFIG_DEFAULT_NAME = 'settings';
// {{SQL CARBON EDIT}}
export const WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME = '.sqlops';
export const WORKSPACE_CONFIG_DEFAULT_PATH = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/${CONFIG_DEFAULT_NAME}.json`;
export const FOLDER_CONFIG_FOLDER_NAME = '.sqlops';
export const FOLDER_SETTINGS_NAME = 'settings';
export const FOLDER_SETTINGS_PATH = `${FOLDER_CONFIG_FOLDER_NAME}/${FOLDER_SETTINGS_NAME}.json`;
export const IWorkspaceConfigurationService = createDecorator<IWorkspaceConfigurationService>('configurationService');
@@ -29,6 +28,6 @@ export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
export const TASKS_CONFIGURATION_KEY = 'tasks';
export const LAUNCH_CONFIGURATION_KEY = 'launch';
export const WORKSPACE_STANDALONE_CONFIGURATIONS = {};
WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`;
WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json`;
export const WORKSPACE_STANDALONE_CONFIGURATIONS = Object.create(null);
WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/tasks.json`;
WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/launch.json`;

View File

@@ -52,46 +52,7 @@ const configurationEntrySchema: IJSONSchema = {
}
};
// BEGIN VSCode extension point `configuration`
const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigurationNode>('configuration', [], {
description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'),
oneOf: [
configurationEntrySchema,
{
type: 'array',
items: configurationEntrySchema
}
]
});
configurationExtPoint.setHandler(extensions => {
const configurations: IConfigurationNode[] = [];
function handleConfiguration(node: IConfigurationNode, id: string, extension: IExtensionPointUser<any>) {
let configuration = objects.clone(node);
if (configuration.title && (typeof configuration.title !== 'string')) {
extension.collector.error(nls.localize('invalid.title', "'configuration.title' must be a string"));
}
validateProperties(configuration, extension);
configuration.id = id;
configurations.push(configuration);
};
for (let extension of extensions) {
const value = <IConfigurationNode | IConfigurationNode[]>extension.value;
const id = extension.description.id;
if (!Array.isArray(value)) {
handleConfiguration(value, id, extension);
} else {
value.forEach(v => handleConfiguration(v, id, extension));
}
}
configurationRegistry.registerConfigurations(configurations, false);
});
// END VSCode extension point `configuration`
let registeredDefaultConfigurations: IDefaultConfigurationExtension[] = [];
// BEGIN VSCode extension point `configurationDefaults`
const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigurationNode>('configurationDefaults', [], {
@@ -107,18 +68,58 @@ const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<I
}
});
defaultConfigurationExtPoint.setHandler(extensions => {
const defaultConfigurations: IDefaultConfigurationExtension[] = extensions.map(extension => {
registeredDefaultConfigurations = extensions.map(extension => {
const id = extension.description.id;
const name = extension.description.name;
const defaults = objects.clone(extension.value);
const defaults = objects.deepClone(extension.value);
return <IDefaultConfigurationExtension>{
id, name, defaults
};
});
configurationRegistry.registerDefaultConfigurations(defaultConfigurations);
});
// END VSCode extension point `configurationDefaults`
// BEGIN VSCode extension point `configuration`
const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IConfigurationNode>('configuration', [defaultConfigurationExtPoint], {
description: nls.localize('vscode.extension.contributes.configuration', 'Contributes configuration settings.'),
oneOf: [
configurationEntrySchema,
{
type: 'array',
items: configurationEntrySchema
}
]
});
configurationExtPoint.setHandler(extensions => {
const configurations: IConfigurationNode[] = [];
function handleConfiguration(node: IConfigurationNode, id: string, extension: IExtensionPointUser<any>) {
let configuration = objects.deepClone(node);
if (configuration.title && (typeof configuration.title !== 'string')) {
extension.collector.error(nls.localize('invalid.title', "'configuration.title' must be a string"));
}
validateProperties(configuration, extension);
configuration.id = id;
configurations.push(configuration);
}
for (let extension of extensions) {
const value = <IConfigurationNode | IConfigurationNode[]>extension.value;
const id = extension.description.id;
if (!Array.isArray(value)) {
handleConfiguration(value, id, extension);
} else {
value.forEach(v => handleConfiguration(v, id, extension));
}
}
configurationRegistry.registerConfigurations(configurations, registeredDefaultConfigurations, false);
});
// END VSCode extension point `configuration`
function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser<any>): void {
let properties = configuration.properties;
if (properties) {
@@ -148,6 +149,7 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
allowComments: true,
default: {
folders: [
{
@@ -208,4 +210,4 @@ jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
},
additionalProperties: false,
errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property")
});
});

View File

@@ -4,190 +4,130 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { clone, equals } from 'vs/base/common/objects';
import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { ConfigurationModel, Configuration as BaseConfiguration, CustomConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { equals } from 'vs/base/common/objects';
import { compare, toValuesTree, IConfigurationChangeEvent, ConfigurationTarget, IConfigurationModel, IConfigurationOverrides, IOverrides } from 'vs/platform/configuration/common/configuration';
import { Configuration as BaseConfiguration, ConfigurationModelParser, ConfigurationChangeEvent, ConfigurationModel, AbstractConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, IConfigurationPropertySchema, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration';
import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { StrictResourceMap } from 'vs/base/common/map';
import URI from 'vs/base/common/uri';
import { distinct } from 'vs/base/common/arrays';
export class WorkspaceConfigurationModel extends CustomConfigurationModel {
export class WorkspaceSettingsModel extends ConfigurationModel {
private _raw: any;
private _folders: IStoredWorkspaceFolder[];
private _worksapaceSettings: WorkspaceSettingsModel;
private _unsupportedKeys: string[];
public update(content: string): void {
super.update(content);
this._folders = (this._raw['folders'] || []) as IStoredWorkspaceFolder[];
this._worksapaceSettings = new WorkspaceSettingsModel(this._raw['settings'] || {});
constructor(contents: any, keys: string[], overrides: IOverrides[], unsupportedKeys: string[]) {
super(contents, keys, overrides);
this._unsupportedKeys = unsupportedKeys;
}
public get unsupportedKeys(): string[] {
return this._unsupportedKeys;
}
}
export class WorkspaceConfigurationModelParser extends ConfigurationModelParser {
private _folders: IStoredWorkspaceFolder[] = [];
private _workspaceSettingsModelParser: FolderSettingsModelParser;
constructor(name: string) {
super(name);
this._workspaceSettingsModelParser = new FolderSettingsModelParser(name);
}
get folders(): IStoredWorkspaceFolder[] {
return this._folders;
}
get workspaceConfiguration(): ConfigurationModel {
return this._worksapaceSettings || new WorkspaceSettingsModel({});
}
get workspaceSettingsModel(): WorkspaceSettingsModel {
return this._worksapaceSettings || new WorkspaceSettingsModel({});
return this._workspaceSettingsModelParser.folderSettingsModel;
}
protected processRaw(raw: any): void {
this._raw = raw;
super.processRaw(raw);
reprocessWorkspaceSettings(): void {
this._workspaceSettingsModelParser.reprocess();
}
protected parseRaw(raw: any): IConfigurationModel {
this._folders = (raw['folders'] || []) as IStoredWorkspaceFolder[];
this._workspaceSettingsModelParser.parse(raw['settings']);
return super.parseRaw(raw);
}
}
export class StandaloneConfigurationModelParser extends ConfigurationModelParser {
constructor(name: string, private readonly scope: string) {
super(name);
}
protected parseRaw(raw: any): IConfigurationModel {
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
const scopedContents = Object.create(null);
scopedContents[this.scope] = contents;
const keys = Object.keys(raw).map(key => `${this.scope}.${key}`);
return { contents: scopedContents, keys, overrides: [] };
}
}
export class WorkspaceSettingsModel extends ConfigurationModel {
export class FolderSettingsModelParser extends ConfigurationModelParser {
private _raw: any;
private _unsupportedKeys: string[];
private _workspaceSettingsModel: WorkspaceSettingsModel;
constructor(raw: any) {
super();
this._raw = raw;
this.update();
constructor(name: string, private configurationScope?: ConfigurationScope) {
super(name);
}
public get unsupportedKeys(): string[] {
return this._unsupportedKeys || [];
parse(content: string | any): void {
this._raw = typeof content === 'string' ? this.parseContent(content) : content;
this.parseWorkspaceSettings(this._raw);
}
update(): void {
const { unsupportedKeys, contents } = processWorkspaceSettings(this._raw);
this._unsupportedKeys = unsupportedKeys;
this._contents = toValuesTree(contents, message => console.error(`Conflict in workspace settings file: ${message}`));
this._keys = Object.keys(contents);
}
}
export class ScopedConfigurationModel extends CustomConfigurationModel {
constructor(content: string, name: string, public readonly scope: string) {
super(null, name);
this.update(content);
get configurationModel(): ConfigurationModel {
return this._workspaceSettingsModel || new WorkspaceSettingsModel({}, [], [], []);
}
public update(content: string): void {
super.update(content);
const contents = Object.create(null);
contents[this.scope] = this.contents;
this._contents = contents;
get folderSettingsModel(): WorkspaceSettingsModel {
return <WorkspaceSettingsModel>this.configurationModel;
}
}
function processWorkspaceSettings(content: any): { unsupportedKeys: string[], contents: any } {
const isNotExecutable = (key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): boolean => {
const propertySchema = configurationProperties[key];
if (!propertySchema) {
return true; // Unknown propertis are ignored from checks
}
return !propertySchema.isExecutable;
};
const unsupportedKeys = [];
const contents = {};
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
for (let key in content) {
if (isNotExecutable(key, configurationProperties)) {
contents[key] = content[key];
} else {
unsupportedKeys.push(key);
}
}
return { contents, unsupportedKeys };
}
export class FolderSettingsModel extends CustomConfigurationModel {
private _raw: any;
private _unsupportedKeys: string[];
protected processRaw(raw: any): void {
this._raw = raw;
const { unsupportedKeys, contents } = processWorkspaceSettings(raw);
this._unsupportedKeys = unsupportedKeys;
return super.processRaw(contents);
reprocess(): void {
this.parse(this._raw);
}
public reprocess(): void {
this.processRaw(this._raw);
}
public get unsupportedKeys(): string[] {
return this._unsupportedKeys || [];
}
public createWorkspaceConfigurationModel(): ConfigurationModel {
return this.createScopedConfigurationModel(ConfigurationScope.WINDOW);
}
public createFolderScopedConfigurationModel(): ConfigurationModel {
return this.createScopedConfigurationModel(ConfigurationScope.RESOURCE);
}
private createScopedConfigurationModel(scope: ConfigurationScope): ConfigurationModel {
const workspaceRaw = {};
private parseWorkspaceSettings(rawSettings: any): void {
const unsupportedKeys = [];
const rawWorkspaceSettings = {};
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
for (let key in this._raw) {
if (this.getScope(key, configurationProperties) === scope) {
workspaceRaw[key] = this._raw[key];
for (let key in rawSettings) {
if (this.isNotExecutable(key, configurationProperties)) {
if (this.configurationScope === void 0 || this.getScope(key, configurationProperties) === this.configurationScope) {
rawWorkspaceSettings[key] = rawSettings[key];
}
} else {
unsupportedKeys.push(key);
}
}
const workspaceContents = toValuesTree(workspaceRaw, message => console.error(`Conflict in workspace settings file: ${message}`));
const workspaceKeys = Object.keys(workspaceRaw);
return new ConfigurationModel(workspaceContents, workspaceKeys, clone(this._overrides));
const configurationModel = this.parseRaw(rawWorkspaceSettings);
this._workspaceSettingsModel = new WorkspaceSettingsModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides, unsupportedKeys);
}
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope {
const propertySchema = configurationProperties[key];
return propertySchema ? propertySchema.scope : ConfigurationScope.WINDOW;
}
}
export class FolderConfigurationModel extends CustomConfigurationModel {
constructor(public readonly workspaceSettingsConfig: FolderSettingsModel, private scopedConfigs: ScopedConfigurationModel[], private scope: ConfigurationScope) {
super();
this.consolidate();
}
private consolidate(): void {
this._contents = {};
this._overrides = [];
this.doMerge(this, ConfigurationScope.WINDOW === this.scope ? this.workspaceSettingsConfig : this.workspaceSettingsConfig.createFolderScopedConfigurationModel());
for (const configModel of this.scopedConfigs) {
this.doMerge(this, configModel);
private isNotExecutable(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): boolean {
const propertySchema = configurationProperties[key];
if (!propertySchema) {
return true; // Unknown propertis are ignored from checks
}
}
public get keys(): string[] {
const keys: string[] = [...this.workspaceSettingsConfig.keys];
this.scopedConfigs.forEach(scopedConfigModel => {
Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS).forEach(scope => {
if (scopedConfigModel.scope === scope) {
keys.push(...scopedConfigModel.keys.map(key => `${scope}.${key}`));
}
});
});
return keys;
}
public update(): void {
this.workspaceSettingsConfig.reprocess();
this.consolidate();
return !propertySchema.isExecutable;
}
}
@@ -197,22 +137,18 @@ export class Configuration extends BaseConfiguration {
defaults: ConfigurationModel,
user: ConfigurationModel,
workspaceConfiguration: ConfigurationModel,
protected folders: StrictResourceMap<FolderConfigurationModel>,
folders: StrictResourceMap<ConfigurationModel>,
memoryConfiguration: ConfigurationModel,
memoryConfigurationByResource: StrictResourceMap<ConfigurationModel>,
private readonly _workspace: Workspace) {
super(defaults, user, workspaceConfiguration, folders, memoryConfiguration, memoryConfigurationByResource);
}
getSection<C>(section: string = '', overrides: IConfigurationOverrides = {}): C {
return super.getSection(section, overrides, this._workspace);
}
getValue(key: string, overrides: IConfigurationOverrides = {}): any {
return super.getValue(key, overrides, this._workspace);
}
lookup<C>(key: string, overrides: IConfigurationOverrides = {}): {
inspect<C>(key: string, overrides: IConfigurationOverrides = {}): {
default: C,
user: C,
workspace: C,
@@ -220,7 +156,7 @@ export class Configuration extends BaseConfiguration {
memory?: C
value: C,
} {
return super.lookup(key, overrides, this._workspace);
return super.inspect(key, overrides, this._workspace);
}
keys(): {
@@ -232,103 +168,95 @@ export class Configuration extends BaseConfiguration {
return super.keys(this._workspace);
}
updateDefaultConfiguration(defaults: ConfigurationModel): void {
this._defaults = defaults;
this.merge();
}
updateUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this._user, user);
compareAndUpdateUserConfiguration(user: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.user, user);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace);
this._user = user;
this.merge();
changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key)));
const oldValues = changedKeys.map(key => this.getValue(key));
super.updateUserConfiguration(user);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key)));
}
return new ConfigurationChangeEvent().change(changedKeys);
}
updateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this._workspaceConfiguration, workspaceConfiguration);
compareAndUpdateWorkspaceConfiguration(workspaceConfiguration: ConfigurationModel): ConfigurationChangeEvent {
const { added, updated, removed } = compare(this.workspace, workspaceConfiguration);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace);
this._workspaceConfiguration = workspaceConfiguration;
this.merge();
changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key), this.getValue(key)));
const oldValues = changedKeys.map(key => this.getValue(key));
super.updateWorkspaceConfiguration(workspaceConfiguration);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key)));
}
return new ConfigurationChangeEvent().change(changedKeys);
}
updateFolderConfiguration(resource: URI, configuration: FolderConfigurationModel): ConfigurationChangeEvent {
compareAndUpdateFolderConfiguration(resource: URI, folderConfiguration: ConfigurationModel): ConfigurationChangeEvent {
const currentFolderConfiguration = this.folders.get(resource);
if (currentFolderConfiguration) {
const { added, updated, removed } = compare(currentFolderConfiguration, configuration);
const { added, updated, removed } = compare(currentFolderConfiguration, folderConfiguration);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldConfiguartion = new Configuration(this._defaults, this._user, this._workspaceConfiguration, this.folders, this._memoryConfiguration, this._memoryConfigurationByResource, this._workspace);
this.folders.set(resource, configuration);
this.mergeFolder(resource);
changedKeys = changedKeys.filter(key => !equals(oldConfiguartion.getValue(key, { resource }), this.getValue(key, { resource })));
const oldValues = changedKeys.map(key => this.getValue(key, { resource }));
super.updateFolderConfiguration(resource, folderConfiguration);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key, { resource })));
}
return new ConfigurationChangeEvent().change(changedKeys, resource);
} else {
super.updateFolderConfiguration(resource, folderConfiguration);
return new ConfigurationChangeEvent().change(folderConfiguration.keys, resource);
}
this.folders.set(resource, configuration);
this.mergeFolder(resource);
return new ConfigurationChangeEvent().change(configuration.keys, resource);
}
deleteFolderConfiguration(folder: URI): ConfigurationChangeEvent {
compareAndDeleteFolderConfiguration(folder: URI): ConfigurationChangeEvent {
if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) {
// Do not remove workspace configuration
return new ConfigurationChangeEvent();
}
const keys = this.folders.get(folder).keys;
this.folders.delete(folder);
this._foldersConsolidatedConfigurations.delete(folder);
super.deleteFolderConfiguration(folder);
return new ConfigurationChangeEvent().change(keys, folder);
}
getFolderConfigurationModel(folder: URI): FolderConfigurationModel {
return <FolderConfigurationModel>this.folders.get(folder);
}
compare(other: Configuration): string[] {
let from = other.allKeys();
let to = this.allKeys();
const added = to.filter(key => from.indexOf(key) === -1);
const removed = from.filter(key => to.indexOf(key) === -1);
const updated = [];
for (const key of from) {
const value1 = this.getValue(key);
const value2 = other.getValue(key);
if (!equals(value1, value2)) {
updated.push(key);
const result = [];
for (const key of this.allKeys()) {
if (!equals(this.getValue(key), other.getValue(key))
|| (this._workspace && this._workspace.folders.some(folder => !equals(this.getValue(key, { resource: folder.uri }), other.getValue(key, { resource: folder.uri }))))) {
result.push(key);
}
}
return [...added, ...removed, ...updated];
return result;
}
allKeys(): string[] {
let keys = this.keys();
let all = [...keys.default, ...keys.user, ...keys.workspace];
for (const resource of this.folders.keys()) {
all.push(...this.folders.get(resource).keys);
return super.allKeys(this._workspace);
}
}
export class AllKeysConfigurationChangeEvent extends AbstractConfigurationChangeEvent implements IConfigurationChangeEvent {
private _changedConfiguration: ConfigurationModel = null;
constructor(private _configuration: Configuration, readonly source: ConfigurationTarget, readonly sourceConfig: any) { super(); }
get changedConfiguration(): ConfigurationModel {
if (!this._changedConfiguration) {
this._changedConfiguration = new ConfigurationModel();
this.updateKeys(this._changedConfiguration, this.affectedKeys);
}
return distinct(all);
return this._changedConfiguration;
}
get changedConfigurationByResource(): StrictResourceMap<IConfigurationModel> {
return new StrictResourceMap();
}
get affectedKeys(): string[] {
return this._configuration.allKeys();
}
affectsConfiguration(config: string, resource?: URI): boolean {
return this.doesConfigurationContains(this.changedConfiguration, config);
}
}

View File

@@ -15,13 +15,16 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
import { isLinux } from 'vs/base/common/platform';
import { ConfigWatcher } from 'vs/base/node/config';
import { CustomConfigurationModel, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModel, ScopedConfigurationModel, FolderConfigurationModel, FolderSettingsModel, WorkspaceSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels';
import { WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser, WorkspaceSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels';
import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { IStoredWorkspace, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import * as extfs from 'vs/base/node/extfs';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
import { WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { relative } from 'path';
import { equals } from 'vs/base/common/objects';
// node.hs helper functions
@@ -73,7 +76,7 @@ function resolveStat(resource: URI): TPromise<IStat> {
export class WorkspaceConfiguration extends Disposable {
private _workspaceConfigPath: URI;
private _workspaceConfigurationWatcher: ConfigWatcher<WorkspaceConfigurationModel>;
private _workspaceConfigurationWatcher: ConfigWatcher<WorkspaceConfigurationModelParser>;
private _workspaceConfigurationWatcherDisposables: IDisposable[] = [];
private _onDidUpdateConfiguration: Emitter<void> = this._register(new Emitter<void>());
@@ -88,12 +91,15 @@ export class WorkspaceConfiguration extends Disposable {
this.stopListeningToWatcher();
return new TPromise<void>((c, e) => {
const defaultConfig = new WorkspaceConfigurationModelParser(this._workspaceConfigPath.fsPath);
defaultConfig.parse(JSON.stringify({ folders: [] } as IStoredWorkspace, null, '\t'));
this._workspaceConfigurationWatcher = new ConfigWatcher(this._workspaceConfigPath.fsPath, {
changeBufferDelay: 300,
onError: error => errors.onUnexpectedError(error),
defaultConfig: new WorkspaceConfigurationModel(JSON.stringify({ folders: [] } as IStoredWorkspace, null, '\t'), this._workspaceConfigPath.fsPath),
defaultConfig,
parse: (content: string, parseErrors: any[]) => {
const workspaceConfigurationModel = new WorkspaceConfigurationModel(content, this._workspaceConfigPath.fsPath);
const workspaceConfigurationModel = new WorkspaceConfigurationModelParser(this._workspaceConfigPath.fsPath);
workspaceConfigurationModel.parse(content);
parseErrors = [...workspaceConfigurationModel.errors];
return workspaceConfigurationModel;
}, initCallback: () => c(null)
@@ -102,8 +108,8 @@ export class WorkspaceConfiguration extends Disposable {
});
}
private get workspaceConfigurationModel(): WorkspaceConfigurationModel {
return this._workspaceConfigurationWatcher ? this._workspaceConfigurationWatcher.getConfig() : new WorkspaceConfigurationModel();
private get workspaceConfigurationModelParser(): WorkspaceConfigurationModelParser {
return this._workspaceConfigurationWatcher ? this._workspaceConfigurationWatcher.getConfig() : new WorkspaceConfigurationModelParser(this._workspaceConfigPath ? this._workspaceConfigPath.fsPath : '');
}
reload(): TPromise<void> {
@@ -115,7 +121,7 @@ export class WorkspaceConfiguration extends Disposable {
}
getFolders(): IStoredWorkspaceFolder[] {
return this.workspaceConfigurationModel.folders;
return this.workspaceConfigurationModelParser.folders;
}
setFolders(folders: IStoredWorkspaceFolder[], jsonEditingService: JSONEditingService): TPromise<void> {
@@ -124,11 +130,16 @@ export class WorkspaceConfiguration extends Disposable {
}
getConfiguration(): ConfigurationModel {
return this.workspaceConfigurationModel.workspaceConfiguration;
return this.workspaceConfigurationModelParser.workspaceSettingsModel;
}
getWorkspaceSettings(): WorkspaceSettingsModel {
return this.workspaceConfigurationModel.workspaceSettingsModel;
return this.workspaceConfigurationModelParser.workspaceSettingsModel;
}
reprocessWorkspaceSettings(): ConfigurationModel {
this.workspaceConfigurationModelParser.reprocessWorkspaceSettings();
return this.getConfiguration();
}
private listenToWatcher() {
@@ -148,32 +159,54 @@ export class WorkspaceConfiguration extends Disposable {
export class FolderConfiguration extends Disposable {
private static RELOAD_CONFIGURATION_DELAY = 50;
private static readonly RELOAD_CONFIGURATION_DELAY = 50;
private bulkFetchFromWorkspacePromise: TPromise;
private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise<ConfigurationModel> };
private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise<ConfigurationModelParser> };
private _folderSettingsModelParser: FolderSettingsModelParser;
private _standAloneConfigurations: ConfigurationModel[] = [];
private _cache: ConfigurationModel = new ConfigurationModel();
private reloadConfigurationScheduler: RunOnceScheduler;
private reloadConfigurationEventEmitter: Emitter<FolderConfigurationModel> = new Emitter<FolderConfigurationModel>();
private reloadConfigurationEventEmitter: Emitter<ConfigurationModel> = new Emitter<ConfigurationModel>();
constructor(private folder: URI, private configFolderRelativePath: string, private scope: ConfigurationScope) {
constructor(private folder: URI, private configFolderRelativePath: string, workbenchState: WorkbenchState) {
super();
this._folderSettingsModelParser = new FolderSettingsModelParser(FOLDER_SETTINGS_PATH, WorkbenchState.WORKSPACE === workbenchState ? ConfigurationScope.RESOURCE : void 0);
this.workspaceFilePathToConfiguration = Object.create(null);
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configuration => this.reloadConfigurationEventEmitter.fire(configuration), errors.onUnexpectedError), FolderConfiguration.RELOAD_CONFIGURATION_DELAY));
}
loadConfiguration(): TPromise<FolderConfigurationModel> {
loadConfiguration(): TPromise<ConfigurationModel> {
// Load workspace locals
return this.loadWorkspaceConfigFiles().then(workspaceConfigFiles => {
this._standAloneConfigurations = Object.keys(workspaceConfigFiles).filter(key => key !== FOLDER_SETTINGS_PATH).map(key => <ConfigurationModel>workspaceConfigFiles[key].configurationModel);
// Consolidate (support *.json files in the workspace settings folder)
const workspaceSettingsConfig = <FolderSettingsModel>workspaceConfigFiles[WORKSPACE_CONFIG_DEFAULT_PATH] || new FolderSettingsModel(null);
const otherConfigModels = Object.keys(workspaceConfigFiles).filter(key => key !== WORKSPACE_CONFIG_DEFAULT_PATH).map(key => <ScopedConfigurationModel>workspaceConfigFiles[key]);
return new FolderConfigurationModel(workspaceSettingsConfig, otherConfigModels, this.scope);
this.consolidate();
return this._cache;
});
}
private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModel }> {
reprocess(): ConfigurationModel {
const oldContents = this._folderSettingsModelParser.folderSettingsModel.contents;
this._folderSettingsModelParser.reprocess();
if (!equals(oldContents, this._folderSettingsModelParser.folderSettingsModel.contents)) {
this.consolidate();
}
return this._cache;
}
getUnsupportedKeys(): string[] {
return this._folderSettingsModelParser.folderSettingsModel.unsupportedKeys;
}
private consolidate(): void {
this._cache = this._folderSettingsModelParser.folderSettingsModel.merge(...this._standAloneConfigurations);
}
private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModelParser }> {
// once: when invoked for the first time we fetch json files that contribute settings
if (!this.bulkFetchFromWorkspacePromise) {
this.bulkFetchFromWorkspacePromise = resolveStat(this.toResource(this.configFolderRelativePath)).then(stat => {
@@ -191,7 +224,7 @@ export class FolderConfiguration extends Disposable {
}).map(stat => stat.resource));
}, err => [] /* never fail this call */)
.then((contents: IContent[]) => {
contents.forEach(content => this.workspaceFilePathToConfiguration[this.toFolderRelativePath(content.resource)] = TPromise.as(this.createConfigModel(content)));
contents.forEach(content => this.workspaceFilePathToConfiguration[this.toFolderRelativePath(content.resource)] = TPromise.as(this.createConfigurationModelParser(content)));
}, errors.onUnexpectedError);
}
@@ -200,7 +233,7 @@ export class FolderConfiguration extends Disposable {
return this.bulkFetchFromWorkspacePromise.then(() => TPromise.join(this.workspaceFilePathToConfiguration));
}
public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise<FolderConfigurationModel> {
public handleWorkspaceFileEvents(event: FileChangesEvent): TPromise<ConfigurationModel> {
const events = event.changes;
let affectedByChanges = false;
@@ -237,7 +270,7 @@ export class FolderConfiguration extends Disposable {
break;
case FileChangeType.UPDATED:
case FileChangeType.ADDED:
this.workspaceFilePathToConfiguration[workspacePath] = resolveContent(resource).then(content => this.createConfigModel(content), errors.onUnexpectedError);
this.workspaceFilePathToConfiguration[workspacePath] = resolveContent(resource).then(content => this.createConfigurationModelParser(content), errors.onUnexpectedError);
affectedByChanges = true;
}
}
@@ -258,22 +291,24 @@ export class FolderConfiguration extends Disposable {
});
}
private createConfigModel(content: IContent): ConfigurationModel {
private createConfigurationModelParser(content: IContent): ConfigurationModelParser {
const path = this.toFolderRelativePath(content.resource);
if (path === WORKSPACE_CONFIG_DEFAULT_PATH) {
return new FolderSettingsModel(content.value, content.resource.toString());
if (path === FOLDER_SETTINGS_PATH) {
this._folderSettingsModelParser.parse(content.value);
return this._folderSettingsModelParser;
} else {
const matches = /\/([^\.]*)*\.json/.exec(path);
if (matches && matches[1]) {
return new ScopedConfigurationModel(content.value, content.resource.toString(), matches[1]);
const standAloneConfigurationModelParser = new StandaloneConfigurationModelParser(content.resource.toString(), matches[1]);
standAloneConfigurationModelParser.parse(content.value);
return standAloneConfigurationModelParser;
}
}
return new CustomConfigurationModel(null);
return new ConfigurationModelParser(null);
}
private isWorkspaceConfigurationFile(folderRelativePath: string): boolean {
return [WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY], WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY]].some(p => p === folderRelativePath);
return [FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY], WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY]].some(p => p === folderRelativePath);
}
private toResource(folderRelativePath: string): URI {
@@ -286,7 +321,7 @@ export class FolderConfiguration extends Disposable {
private toFolderRelativePath(resource: URI, toOSPath?: boolean): string {
if (this.contains(resource)) {
return paths.normalize(paths.relative(this.folder.fsPath, resource.fsPath), toOSPath);
return paths.normalize(relative(this.folder.fsPath, resource.fsPath), toOSPath);
}
return null;

View File

@@ -24,7 +24,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
@@ -109,11 +109,6 @@ interface IConfigurationEditOperation extends IConfigurationValue {
}
interface IValidationResult {
error?: ConfigurationEditingErrorCode;
exists?: boolean;
}
interface ConfigurationEditingOptions extends IConfigurationEditingOptions {
force?: boolean;
}
@@ -161,7 +156,7 @@ export class ConfigurationEditingService {
private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise<any> {
const edit = this.getEdits(model, operation)[0];
if (this.applyEditsToBuffer(edit, model) && save) {
if (edit && this.applyEditsToBuffer(edit, model) && save) {
return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ });
}
return TPromise.as(null);
@@ -308,7 +303,7 @@ export class ConfigurationEditingService {
return nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open **Folder Settings** file under **{0}** folder to correct errors/warnings in it and try again.", workspaceFolderName);
}
return '';
};
}
case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return nls.localize('errorTasksConfigurationFileDirty', "Unable to write into tasks file because the file is dirty. Please save the **Tasks Configuration** file and try again.");
@@ -326,7 +321,7 @@ export class ConfigurationEditingService {
return nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the **Folder Settings** file under **{0}** folder and try again.", workspaceFolderName);
}
return '';
};
}
}
}
@@ -352,7 +347,7 @@ export class ConfigurationEditingService {
const content = JSON.stringify(value, null, insertSpaces ? strings.repeat(' ', tabSize) : '\t');
return [{
content,
length: content.length,
length: model.getValue().length,
offset: 0
}];
}
@@ -467,7 +462,7 @@ export class ConfigurationEditingService {
return { key, jsonPath, value: config.value, resource: URI.file(this.environmentService.appSettingsPath), target };
}
const resource = this.getConfigurationFileResource(target, WORKSPACE_CONFIG_DEFAULT_PATH, overrides.resource);
const resource = this.getConfigurationFileResource(target, FOLDER_SETTINGS_PATH, overrides.resource);
if (workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath) {
jsonPath = ['settings', ...jsonPath];
}

View File

@@ -20,15 +20,14 @@ import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder,
import { FileChangesEvent } from 'vs/platform/files/common/files';
import { isLinux } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ConfigurationModel, ConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration';
import { FolderConfigurationModel, Configuration, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/configuration/node/configurationService';
import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { IWorkspaceConfigurationService, FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationNode, IConfigurationRegistry, Extensions, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationNode, IConfigurationRegistry, Extensions, settingsSchema, resourceSettingsSchema, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
import { createHash } from 'crypto';
import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { getWorkspaceLabel, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -40,6 +39,8 @@ import { JSONEditingService } from 'vs/workbench/services/configuration/node/jso
import { Schemas } from 'vs/base/common/network';
import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces';
import { distinct } from 'vs/base/common/arrays';
import { UserConfiguration } from 'vs/platform/configuration/node/configuration';
import { getBaseLabel } from 'vs/base/common/labels';
export class WorkspaceService extends Disposable implements IWorkspaceConfigurationService, IWorkspaceContextService {
@@ -47,7 +48,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
private workspace: Workspace;
private _configuration: Configuration;
private baseConfigurationService: GlobalConfigurationService;
private defaultConfiguration: DefaultConfigurationModel;
private userConfiguration: UserConfiguration;
private workspaceConfiguration: WorkspaceConfiguration;
private cachedFolderConfigs: StrictResourceMap<FolderConfiguration>;
@@ -68,15 +70,17 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
private configurationEditingService: ConfigurationEditingService;
private jsonEditingService: JSONEditingService;
constructor(private environmentService: IEnvironmentService, private workspacesService: IWorkspacesService, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) {
constructor(private environmentService: IEnvironmentService, private workspaceSettingsRootFolder: string = FOLDER_CONFIG_FOLDER_NAME) {
super();
this.defaultConfiguration = new DefaultConfigurationModel();
this.userConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
this.workspaceConfiguration = this._register(new WorkspaceConfiguration());
this._register(this.userConfiguration.onDidChangeConfiguration(() => this.onUserConfigurationChanged()));
this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged()));
this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService));
this._register(this.baseConfigurationService.onDidChangeConfiguration(e => this.onBaseConfigurationChanged(e)));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidRegisterConfiguration(e => this.registerConfigurationSchemas()));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidRegisterConfiguration(configurationProperties => this.onDefaultConfigurationChanged(configurationProperties)));
this.workspaceEditingQueue = new Queue<void>();
}
@@ -222,25 +226,21 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return this._configuration.toData();
}
getConfiguration<T>(): T
getConfiguration<T>(section: string): T
getConfiguration<T>(overrides: IConfigurationOverrides): T
getConfiguration<T>(section: string, overrides: IConfigurationOverrides): T
getConfiguration(arg1?: any, arg2?: any): any {
getValue<T>(): T;
getValue<T>(section: string): T;
getValue<T>(overrides: IConfigurationOverrides): T;
getValue<T>(section: string, overrides: IConfigurationOverrides): T;
getValue(arg1?: any, arg2?: any): any {
const section = typeof arg1 === 'string' ? arg1 : void 0;
const overrides = isConfigurationOverrides(arg1) ? arg1 : isConfigurationOverrides(arg2) ? arg2 : void 0;
return this._configuration.getSection(section, overrides);
return this._configuration.getValue(section, overrides);
}
getValue<T>(key: string, overrides?: IConfigurationOverrides): T {
return this._configuration.getValue(key, overrides);
}
updateValue(key: string, value: any): TPromise<void>
updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise<void>
updateValue(key: string, value: any, target: ConfigurationTarget): TPromise<void>
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise<void>
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError: boolean): TPromise<void>
updateValue(key: string, value: any): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides): TPromise<void>;
updateValue(key: string, value: any, target: ConfigurationTarget): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget): TPromise<void>;
updateValue(key: string, value: any, overrides: IConfigurationOverrides, target: ConfigurationTarget, donotNotifyError: boolean): TPromise<void>;
updateValue(key: string, value: any, arg3?: any, arg4?: any, donotNotifyError?: any): TPromise<void> {
assert.ok(this.configurationEditingService, 'Workbench is not initialized yet');
const overrides = isConfigurationOverrides(arg3) ? arg3 : void 0;
@@ -266,7 +266,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
memory?: T,
value: T
} {
return this._configuration.lookup<T>(key);
return this._configuration.inspect<T>(key, overrides);
}
keys(): {
@@ -281,7 +281,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
getUnsupportedWorkspaceKeys(): string[] {
const unsupportedWorkspaceKeys = [...this.workspaceConfiguration.getWorkspaceSettings().unsupportedKeys];
for (const folder of this.workspace.folders) {
unsupportedWorkspaceKeys.push(...this._configuration.getFolderConfigurationModel(folder.uri).workspaceSettingsConfig.unsupportedKeys);
unsupportedWorkspaceKeys.push(...this.cachedFolderConfigs.get(folder.uri).getUnsupportedKeys());
}
return distinct(unsupportedWorkspaceKeys);
}
@@ -336,7 +336,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
const ctime = isLinux ? workspaceStat.ino : workspaceStat.birthtime.getTime(); // On Linux, birthtime is ctime, so we cannot use it! We use the ino instead!
const id = createHash('md5').update(folderPath.fsPath).update(ctime ? String(ctime) : '').digest('hex');
const folder = URI.file(folderPath.fsPath);
return new Workspace(id, paths.basename(folderPath.fsPath), toWorkspaceFolders([{ path: folder.fsPath }]), null, ctime);
return new Workspace(id, getBaseLabel(folder), toWorkspaceFolders([{ path: folder.fsPath }]), null, ctime);
});
}
@@ -346,34 +346,37 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
private updateWorkspaceAndInitializeConfiguration(workspace: Workspace): TPromise<void> {
let folderChanges: IWorkspaceFoldersChangeEvent;
if (this.workspace) {
const currentState = this.getWorkbenchState();
const currentWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
const currentFolders = this.workspace.folders;
const hasWorkspaceBefore = !!this.workspace;
let previousState;
let previousWorkspacePath;
let previousFolders;
if (hasWorkspaceBefore) {
previousState = this.getWorkbenchState();
previousWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
previousFolders = this.workspace.folders;
this.workspace.update(workspace);
const newState = this.getWorkbenchState();
if (newState !== currentState) {
this._onDidChangeWorkbenchState.fire(newState);
}
const newWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
if (newWorkspacePath !== currentWorkspacePath || newState !== currentState) {
this._onDidChangeWorkspaceName.fire();
}
folderChanges = this.compareFolders(currentFolders, this.workspace.folders);
} else {
this.workspace = workspace;
}
return this.initializeConfiguration().then(() => {
// Trigger folders change after configuration initialization so that configuration is up to date.
if (folderChanges && (folderChanges.added.length || folderChanges.removed.length || folderChanges.changed.length)) {
this._onDidChangeWorkspaceFolders.fire(folderChanges);
// Trigger changes after configuration initialization so that configuration is up to date.
if (hasWorkspaceBefore) {
const newState = this.getWorkbenchState();
if (previousState && newState !== previousState) {
this._onDidChangeWorkbenchState.fire(newState);
}
const newWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
if (previousWorkspacePath && newWorkspacePath !== previousWorkspacePath || newState !== previousState) {
this._onDidChangeWorkspaceName.fire();
}
const folderChanges = this.compareFolders(previousFolders, this.workspace.folders);
if (folderChanges && (folderChanges.added.length || folderChanges.removed.length || folderChanges.changed.length)) {
this._onDidChangeWorkspaceFolders.fire(folderChanges);
}
}
});
}
@@ -402,7 +405,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
private reloadUserConfiguration(key?: string): TPromise<void> {
return this.baseConfigurationService.reloadConfiguration();
return this.userConfiguration.reload();
}
private reloadWorkspaceConfiguration(key?: string): TPromise<void> {
@@ -429,22 +432,22 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
.then((folderConfigurations) => {
let workspaceConfiguration = this.getWorkspaceConfigurationModel(folderConfigurations);
const folderConfigurationModels = new StrictResourceMap<FolderConfigurationModel>();
const folderConfigurationModels = new StrictResourceMap<ConfigurationModel>();
folderConfigurations.forEach((folderConfiguration, index) => folderConfigurationModels.set(folders[index].uri, folderConfiguration));
const currentConfiguration = this._configuration;
this._configuration = new Configuration(this.baseConfigurationService.configuration.defaults, this.baseConfigurationService.configuration.user, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap<ConfigurationModel>(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: Sandy Avoid passing null
this._configuration = new Configuration(this.defaultConfiguration, this.userConfiguration.configurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new StrictResourceMap<ConfigurationModel>(), this.getWorkbenchState() !== WorkbenchState.EMPTY ? this.workspace : null); //TODO: Sandy Avoid passing null
if (currentConfiguration) {
const changedKeys = this._configuration.compare(currentConfiguration);
this.triggerConfigurationChange(new ConfigurationChangeEvent().change(changedKeys), ConfigurationTarget.WORKSPACE);
} else {
this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration.allKeys(), ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE)));
this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration, ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE)));
}
});
}
private getWorkspaceConfigurationModel(folderConfigurations: FolderConfigurationModel[]): ConfigurationModel {
private getWorkspaceConfigurationModel(folderConfigurations: ConfigurationModel[]): ConfigurationModel {
switch (this.getWorkbenchState()) {
case WorkbenchState.FOLDER:
return folderConfigurations[0];
@@ -455,6 +458,21 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
}
private onDefaultConfigurationChanged(keys: string[]): void {
this.defaultConfiguration = new DefaultConfigurationModel();
this.registerConfigurationSchemas();
if (this.workspace && this._configuration) {
this._configuration.updateDefaultConfiguration(this.defaultConfiguration);
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
this._configuration.updateWorkspaceConfiguration(this.cachedFolderConfigs.get(this.workspace.folders[0].uri).reprocess());
} else {
this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.reprocessWorkspaceSettings());
this.workspace.folders.forEach(folder => this._configuration.updateFolderConfiguration(folder.uri, this.cachedFolderConfigs.get(folder.uri).reprocess()));
}
this.triggerConfigurationChange(new ConfigurationChangeEvent().change(keys), ConfigurationTarget.DEFAULT);
}
}
private registerConfigurationSchemas(): void {
if (this.workspace) {
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
@@ -471,23 +489,14 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
}
private onBaseConfigurationChanged(e: IConfigurationChangeEvent): void {
if (this.workspace && this._configuration) {
if (e.source === ConfigurationTarget.DEFAULT) {
this.workspaceConfiguration.getWorkspaceSettings().update();
this.workspace.folders.forEach(folder => this._configuration.getFolderConfigurationModel(folder.uri).update());
this._configuration.updateDefaultConfiguration(this.baseConfigurationService.configuration.defaults);
this.triggerConfigurationChange(new ConfigurationChangeEvent().change(e.affectedKeys), e.source);
} else {
let keys = this._configuration.updateUserConfiguration(this.baseConfigurationService.configuration.user);
this.triggerConfigurationChange(keys, e.source);
}
}
private onUserConfigurationChanged(): void {
let keys = this._configuration.compareAndUpdateUserConfiguration(this.userConfiguration.configurationModel);
this.triggerConfigurationChange(keys, ConfigurationTarget.USER);
}
private onWorkspaceConfigurationChanged(): TPromise<void> {
if (this.workspace && this.workspace.configuration && this._configuration) {
const workspaceConfigurationChangeEvent = this._configuration.updateWorkspaceConfiguration(this.workspaceConfiguration.getConfiguration());
const workspaceConfigurationChangeEvent = this._configuration.compareAndUpdateWorkspaceConfiguration(this.workspaceConfiguration.getConfiguration());
let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(paths.dirname(this.workspace.configuration.fsPath)));
const changes = this.compareFolders(this.workspace.folders, configuredFolders);
if (changes.added.length || changes.removed.length || changes.changed.length) {
@@ -509,7 +518,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
// handle file event for each folder
this.cachedFolderConfigs.get(folder.uri).handleWorkspaceFileEvents(event)
// Update folder configuration if handled
.then(folderConfiguration => folderConfiguration ? this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration) : new ConfigurationChangeEvent()))
.then(folderConfiguration => folderConfiguration ? this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration) : new ConfigurationChangeEvent()))
).then(changeEvents => {
const consolidateChangeEvent = changeEvents.reduce((consolidated, e) => consolidated.change(e), new ConfigurationChangeEvent());
this.triggerConfigurationChange(consolidateChangeEvent, ConfigurationTarget.WORKSPACE_FOLDER);
@@ -522,8 +531,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
.then(folderConfiguration => {
if (folderConfiguration) {
// File change handled
this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration);
const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration);
this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration);
const workspaceChangedKeys = this._configuration.compareAndUpdateWorkspaceConfiguration(folderConfiguration);
this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE);
}
});
@@ -533,9 +542,9 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
this.disposeFolderConfiguration(folder);
return this.loadFolderConfigurations([folder])
.then(([folderConfiguration]) => {
const folderChangedKeys = this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration);
const folderChangedKeys = this._configuration.compareAndUpdateFolderConfiguration(folder.uri, folderConfiguration);
if (this.getWorkbenchState() === WorkbenchState.FOLDER) {
const workspaceChangedKeys = this._configuration.updateWorkspaceConfiguration(folderConfiguration);
const workspaceChangedKeys = this._configuration.compareAndUpdateWorkspaceConfiguration(folderConfiguration);
this.triggerConfigurationChange(workspaceChangedKeys, ConfigurationTarget.WORKSPACE);
} else {
this.triggerConfigurationChange(folderChangedKeys, ConfigurationTarget.WORKSPACE_FOLDER);
@@ -550,7 +559,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
for (const key of this.cachedFolderConfigs.keys()) {
if (!this.workspace.folders.filter(folder => folder.uri.toString() === key.toString())[0]) {
this.cachedFolderConfigs.delete(key);
changeEvent = changeEvent.change(this._configuration.deleteFolderConfiguration(key));
changeEvent = changeEvent.change(this._configuration.compareAndDeleteFolderConfiguration(key));
}
}
@@ -559,7 +568,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return this.loadFolderConfigurations(toInitialize)
.then(folderConfigurations => {
folderConfigurations.forEach((folderConfiguration, index) => {
changeEvent = changeEvent.change(this._configuration.updateFolderConfiguration(toInitialize[index].uri, folderConfiguration));
changeEvent = changeEvent.change(this._configuration.compareAndUpdateFolderConfiguration(toInitialize[index].uri, folderConfiguration));
});
return changeEvent;
});
@@ -567,9 +576,9 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return TPromise.as(changeEvent);
}
private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise<FolderConfigurationModel[]> {
private loadFolderConfigurations(folders: IWorkspaceFolder[]): TPromise<ConfigurationModel[]> {
return TPromise.join([...folders.map(folder => {
const folderConfiguration = new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW);
const folderConfiguration = new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState());
this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration));
return folderConfiguration.loadConfiguration();
})]);
@@ -694,7 +703,7 @@ export class DefaultConfigurationExportHelper {
}
private writeConfigModelAndQuit(targetPath: string): TPromise<void> {
return this.extensionService.onReady()
return this.extensionService.whenInstalledExtensionsRegistered()
.then(() => this.writeConfigModel(targetPath))
.then(() => this.commandService.executeCommand('workbench.action.quit'))
.then(() => { });
@@ -708,28 +717,33 @@ export class DefaultConfigurationExportHelper {
}
private getConfigModel(): IConfigurationExport {
const configurations = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurations().slice();
const configRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
const configurations = configRegistry.getConfigurations().slice();
const settings: IExportedConfigurationNode[] = [];
const processProperty = (name: string, prop: IConfigurationPropertySchema) => {
const propDetails: IExportedConfigurationNode = {
name,
description: prop.description,
default: prop.default,
type: prop.type
};
if (prop.enum) {
propDetails.enum = prop.enum;
}
if (prop.enumDescriptions) {
propDetails.enumDescriptions = prop.enumDescriptions;
}
settings.push(propDetails);
};
const processConfig = (config: IConfigurationNode) => {
if (config.properties) {
for (let name in config.properties) {
const prop = config.properties[name];
const propDetails: IExportedConfigurationNode = {
name,
description: prop.description,
default: prop.default,
type: prop.type
};
if (prop.enum) {
propDetails.enum = prop.enum;
}
if (prop.enumDescriptions) {
propDetails.enumDescriptions = prop.enumDescriptions;
}
settings.push(propDetails);
processProperty(name, config.properties[name]);
}
}
@@ -740,6 +754,11 @@ export class DefaultConfigurationExportHelper {
configurations.forEach(processConfig);
const excludedProps = configRegistry.getExcludedConfigurationProperties();
for (let name in excludedProps) {
processProperty(name, excludedProps[name]);
}
const result: IConfigurationExport = {
settings: settings.sort((a, b) => a.name.localeCompare(b.name)),
buildTime: Date.now(),

View File

@@ -126,10 +126,10 @@ export class JSONEditingService implements IJSONEditingService {
// User issues
case JSONEditingErrorCode.ERROR_INVALID_FILE: {
return nls.localize('errorInvalidFile', "Unable to write into the file. Please open the file to correct errors/warnings in the file and try again.");
};
}
case JSONEditingErrorCode.ERROR_FILE_DIRTY: {
return nls.localize('errorFileDirty', "Unable to write into the file because the file is dirty. Please save the file and try again.");
};
}
}
}
}

View File

@@ -6,99 +6,93 @@
import * as assert from 'assert';
import { join } from 'vs/base/common/paths';
import { FolderConfigurationModel, ScopedConfigurationModel, FolderSettingsModel, WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { FolderSettingsModelParser, WorkspaceConfigurationChangeEvent, StandaloneConfigurationModelParser, AllKeysConfigurationChangeEvent, Configuration } from 'vs/workbench/services/configuration/common/configurationModels';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
import { ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { StrictResourceMap } from 'vs/base/common/map';
suite('ConfigurationService - Model', () => {
suite('FolderSettingsModelParser', () => {
test('Test scoped configs are undefined', () => {
const settingsConfig = new FolderSettingsModel(JSON.stringify({
awesome: true
}));
const testObject = new FolderConfigurationModel(settingsConfig, [], ConfigurationScope.WINDOW);
assert.equal(testObject.getSectionContents('task'), undefined);
suiteSetup(() => {
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'FolderSettingsModelParser_1',
'type': 'object',
'properties': {
'FolderSettingsModelParser.window': {
'type': 'string',
'default': 'isSet'
},
'FolderSettingsModelParser.resource': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.RESOURCE
},
'FolderSettingsModelParser.executable': {
'type': 'string',
'default': 'isSet',
isExecutable: true
}
}
});
});
test('Test consolidate (settings and tasks)', () => {
const settingsConfig = new FolderSettingsModel(JSON.stringify({
awesome: true
}));
test('parse all folder settings', () => {
const testObject = new FolderSettingsModelParser('settings');
const tasksConfig = new ScopedConfigurationModel(JSON.stringify({
awesome: false
}), '', 'tasks');
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.executable': 'executable' }));
const expected = {
awesome: true,
tasks: {
awesome: false
}
};
assert.deepEqual(new FolderConfigurationModel(settingsConfig, [tasksConfig], ConfigurationScope.WINDOW).contents, expected);
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'window': 'window', 'resource': 'resource' } });
});
test('Test consolidate (settings and launch)', () => {
const settingsConfig = new FolderSettingsModel(JSON.stringify({
awesome: true
}));
test('parse resource folder settings', () => {
const testObject = new FolderSettingsModelParser('settings', ConfigurationScope.RESOURCE);
const launchConfig = new ScopedConfigurationModel(JSON.stringify({
awesome: false
}), '', 'launch');
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.executable': 'executable' }));
const expected = {
awesome: true,
launch: {
awesome: false
}
};
assert.deepEqual(new FolderConfigurationModel(settingsConfig, [launchConfig], ConfigurationScope.WINDOW).contents, expected);
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'resource': 'resource' } });
});
test('Test consolidate (settings and launch and tasks) - launch/tasks wins over settings file', () => {
const settingsConfig = new FolderSettingsModel(JSON.stringify({
awesome: true,
launch: {
launchConfig: 'defined',
otherLaunchConfig: 'alsoDefined'
},
tasks: {
taskConfig: 'defined',
otherTaskConfig: 'alsoDefined'
test('reprocess folder settings excludes executable', () => {
const testObject = new FolderSettingsModelParser('settings');
testObject.parse(JSON.stringify({ 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.anotherExecutable': 'executable' }));
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'resource': 'resource', 'anotherExecutable': 'executable' } });
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': 'FolderSettingsModelParser_2',
'type': 'object',
'properties': {
'FolderSettingsModelParser.anotherExecutable': {
'type': 'string',
'default': 'isSet',
isExecutable: true
}
}
}));
});
const tasksConfig = new ScopedConfigurationModel(JSON.stringify({
taskConfig: 'overwritten',
}), '', 'tasks');
const launchConfig = new ScopedConfigurationModel(JSON.stringify({
launchConfig: 'overwritten',
}), '', 'launch');
const expected = {
awesome: true,
launch: {
launchConfig: 'overwritten',
otherLaunchConfig: 'alsoDefined'
},
tasks: {
taskConfig: 'overwritten',
otherTaskConfig: 'alsoDefined'
}
};
assert.deepEqual(new FolderConfigurationModel(settingsConfig, [launchConfig, tasksConfig], ConfigurationScope.WINDOW).contents, expected);
assert.deepEqual(new FolderConfigurationModel(settingsConfig, [tasksConfig, launchConfig], ConfigurationScope.WINDOW).contents, expected);
testObject.reprocess();
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'resource': 'resource' } });
});
});
suite('StandaloneConfigurationModelParser', () => {
test('parse tasks stand alone configuration model', () => {
const testObject = new StandaloneConfigurationModelParser('tasks', 'tasks');
testObject.parse(JSON.stringify({ 'version': '1.1.1', 'tasks': [] }));
assert.deepEqual(testObject.configurationModel.contents, { 'tasks': { 'version': '1.1.1', 'tasks': [] } });
});
});
suite('WorkspaceConfigurationChangeEvent', () => {
@@ -194,4 +188,50 @@ suite('WorkspaceConfigurationChangeEvent', () => {
assert.ok(!testObject.affectsConfiguration('files', URI.file(join('folder3', 'file3'))));
});
});
suite('AllKeysConfigurationChangeEvent', () => {
test('changeEvent affects keys for any resource', () => {
const configuraiton = new Configuration(new ConfigurationModel({}, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']),
new ConfigurationModel(), new ConfigurationModel(), new StrictResourceMap(), new ConfigurationModel(), new StrictResourceMap(), null);
let testObject = new AllKeysConfigurationChangeEvent(configuraiton, ConfigurationTarget.USER, null);
assert.deepEqual(testObject.affectedKeys, ['window.title', 'window.zoomLevel', 'window.restoreFullscreen', 'workbench.editor.enablePreview', 'window.restoreWindows']);
assert.ok(testObject.affectsConfiguration('window.zoomLevel'));
assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.zoomLevel', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen'));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.restoreFullscreen', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreWindows'));
assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window.restoreWindows', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.title'));
assert.ok(testObject.affectsConfiguration('window.title', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window.title', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('window'));
assert.ok(testObject.affectsConfiguration('window', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('window', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview'));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor.enablePreview', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('workbench.editor'));
assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench.editor', URI.file('file1')));
assert.ok(testObject.affectsConfiguration('workbench'));
assert.ok(testObject.affectsConfiguration('workbench', URI.file('file2')));
assert.ok(testObject.affectsConfiguration('workbench', URI.file('file1')));
assert.ok(!testObject.affectsConfiguration('files'));
assert.ok(!testObject.affectsConfiguration('files', URI.file('file1')));
});
});

View File

@@ -18,7 +18,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import extfs = require('vs/base/node/extfs');
import { TestTextFileService, TestTextResourceConfigurationService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { TestTextFileService, TestTextResourceConfigurationService, workbenchInstantiationService, TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
import uuid = require('vs/base/common/uuid');
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService';
@@ -33,12 +33,12 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
import { IChoiceService } from 'vs/platform/message/common/message';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { mkdirp } from 'vs/base/node/pfs';
class SettingsTestEnvironmentService extends EnvironmentService {
constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome) {
constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) {
super(args, _execPath);
}
@@ -49,9 +49,9 @@ suite('ConfigurationEditingService', () => {
let instantiationService: TestInstantiationService;
let testObject: ConfigurationEditingService;
let parentDir;
let workspaceDir;
let globalSettingsFile;
let parentDir: string;
let workspaceDir: string;
let globalSettingsFile: string;
let workspaceSettingsDir;
suiteSetup(() => {
@@ -81,22 +81,15 @@ suite('ConfigurationEditingService', () => {
.then(() => setUpServices());
});
function setUpWorkspace(): TPromise<void> {
return new TPromise<void>((c, e) => {
const id = uuid.generateUuid();
parentDir = path.join(os.tmpdir(), 'vsctests', id);
workspaceDir = path.join(parentDir, 'workspaceconfig', id);
globalSettingsFile = path.join(workspaceDir, 'config.json');
// {{SQL CARBON EDIT}}
workspaceSettingsDir = path.join(workspaceDir, '.sqlops');
extfs.mkdirp(workspaceSettingsDir, 493, (error) => {
if (error) {
e(error);
} else {
c(null);
}
});
});
function setUpWorkspace(): TPromise<boolean> {
const id = uuid.generateUuid();
parentDir = path.join(os.tmpdir(), 'vsctests', id);
workspaceDir = path.join(parentDir, 'workspaceconfig', id);
globalSettingsFile = path.join(workspaceDir, 'config.json');
// {{SQL CARBON EDIT}}
workspaceSettingsDir = path.join(workspaceDir, '.sqlops');
return mkdirp(workspaceSettingsDir, 493);
}
function setUpServices(noWorkspace: boolean = false): TPromise<void> {
@@ -106,12 +99,11 @@ suite('ConfigurationEditingService', () => {
instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
instantiationService.stub(IEnvironmentService, environmentService);
const workspacesService = instantiationService.stub(IWorkspacesService, {});
const workspaceService = new WorkspaceService(environmentService, workspacesService);
const workspaceService = new WorkspaceService(environmentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
return workspaceService.initialize(noWorkspace ? <IWindowConfiguration>{} : workspaceDir).then(() => {
return workspaceService.initialize(noWorkspace ? {} as IWindowConfiguration : workspaceDir).then(() => {
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }));
instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
testObject = instantiationService.createInstance(ConfigurationEditingService);
@@ -214,6 +206,28 @@ suite('ConfigurationEditingService', () => {
});
});
test('remove an existing setting - existing file', () => {
fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value", "configurationEditing.service.testSetting": "value" }');
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: undefined })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
assert.deepEqual(Object.keys(parsed), ['my.super.setting']);
assert.equal(parsed['my.super.setting'], 'my.super.value');
});
});
test('remove non existing setting - existing file', () => {
fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value" }');
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: undefined })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
assert.deepEqual(Object.keys(parsed), ['my.super.setting']);
assert.equal(parsed['my.super.setting'], 'my.super.value');
});
});
test('write workspace standalone setting - empty file', () => {
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' })
.then(() => {
@@ -249,11 +263,10 @@ suite('ConfigurationEditingService', () => {
});
test('write workspace standalone setting - existing file - full JSON', () => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']);
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }');
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
.then(() => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
const contents = fs.readFileSync(target).toString('utf8');
const parsed = json.parse(contents);
@@ -263,11 +276,10 @@ suite('ConfigurationEditingService', () => {
});
test('write workspace standalone setting - existing file with JSON errors - full JSON', () => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']);
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
fs.writeFileSync(target, '{ "my.super.setting": '); // invalid JSON
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
.then(() => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
const contents = fs.readFileSync(target).toString('utf8');
const parsed = json.parse(contents);
@@ -275,4 +287,25 @@ suite('ConfigurationEditingService', () => {
assert.equal(parsed['tasks'][0]['taskName'], 'myTask');
});
});
test('write workspace standalone setting should replace complete file', () => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
fs.writeFileSync(target, `{
"version": "1.0.0",
"tasks": [
{
"taskName": "myTask1"
},
{
"taskName": "myTask2"
}
]
}`);
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } })
.then(() => {
const actual = fs.readFileSync(target).toString('utf8');
const expected = JSON.stringify({ 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] }, null, '\t');
assert.equal(actual, expected);
});
});
});

View File

@@ -23,8 +23,8 @@ import { WorkspaceService } from 'vs/workbench/services/configuration/node/confi
import { ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService';
import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { workbenchInstantiationService, TestTextResourceConfigurationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices';
import { ConfigurationTarget, IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { workbenchInstantiationService, TestTextResourceConfigurationService, TestTextFileService, TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
import { FileService } from 'vs/workbench/services/files/node/fileService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
@@ -32,6 +32,9 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { mkdirp } from 'vs/base/node/pfs';
class SettingsTestEnvironmentService extends EnvironmentService {
@@ -53,13 +56,7 @@ function setUpFolder(folderName: string, parentDir: string): TPromise<string> {
// {{SQL CARBON EDIT}}
const workspaceSettingsDir = path.join(folderDir, '.sqlops');
return new TPromise((c, e) => {
extfs.mkdirp(workspaceSettingsDir, 493, (error) => {
if (error) {
e(error);
return null;
}
c(folderDir);
});
extfs.mkdirp(workspaceSettingsDir, 493);
});
}
@@ -68,7 +65,7 @@ function setUpWorkspace(folders: string[]): TPromise<{ parentDir: string, config
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
return createDir(parentDir)
return mkdirp(parentDir, 493)
.then(() => {
const configPath = path.join(parentDir, 'vsctests.code-workspace');
const workspace = { folders: folders.map(path => ({ path })) };
@@ -80,617 +77,10 @@ function setUpWorkspace(folders: string[]): TPromise<{ parentDir: string, config
}
function createDir(dir: string): TPromise<void> {
return new TPromise((c, e) => {
extfs.mkdirp(dir, 493, (error) => {
if (error) {
e(error);
return null;
}
c(null);
});
});
}
suite('WorkspaceContextService - Folder', () => {
let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceResource: string, workspaceContextService: IWorkspaceContextService;
setup(() => {
return setUpFolderWorkspace(workspaceName)
.then(({ parentDir, folderDir }) => {
parentResource = parentDir;
workspaceResource = folderDir;
const globalSettingsFile = path.join(parentDir, 'settings.json');
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
workspaceContextService = new WorkspaceService(environmentService, null);
return (<WorkspaceService>workspaceContextService).initialize(folderDir);
});
});
teardown(done => {
if (workspaceContextService) {
(<WorkspaceService>workspaceContextService).dispose();
}
if (parentResource) {
extfs.del(parentResource, os.tmpdir(), () => { }, done);
}
});
test('getWorkspace()', () => {
const actual = workspaceContextService.getWorkspace();
assert.equal(actual.folders.length, 1);
assert.equal(actual.folders[0].uri.fsPath, URI.file(workspaceResource).fsPath);
assert.equal(actual.folders[0].name, workspaceName);
assert.equal(actual.folders[0].index, 0);
assert.ok(!actual.configuration);
});
test('getWorkbenchState()', () => {
const actual = workspaceContextService.getWorkbenchState();
assert.equal(actual, WorkbenchState.FOLDER);
});
test('getWorkspaceFolder()', () => {
const actual = workspaceContextService.getWorkspaceFolder(URI.file(path.join(workspaceResource, 'a')));
assert.equal(actual, workspaceContextService.getWorkspace().folders[0]);
});
test('isCurrentWorkspace() => true', () => {
assert.ok(workspaceContextService.isCurrentWorkspace(workspaceResource));
});
test('isCurrentWorkspace() => false', () => {
assert.ok(!workspaceContextService.isCurrentWorkspace(workspaceResource + 'abc'));
});
});
suite('WorkspaceContextService - Workspace', () => {
let parentResource: string, testObject: WorkspaceService;
setup(() => {
return setUpWorkspace(['a', 'b'])
.then(({ parentDir, configPath }) => {
parentResource = parentDir;
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json'));
const workspaceService = new WorkspaceService(environmentService, null);
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize({ id: configPath, configPath }).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.setInstantiationService(instantiationService);
testObject = workspaceService;
});
});
});
teardown(done => {
if (testObject) {
(<WorkspaceService>testObject).dispose();
}
if (parentResource) {
extfs.del(parentResource, os.tmpdir(), () => { }, done);
}
});
test('workspace folders', () => {
const actual = testObject.getWorkspace().folders;
assert.equal(actual.length, 2);
assert.equal(path.basename(actual[0].uri.fsPath), 'a');
assert.equal(path.basename(actual[1].uri.fsPath), 'b');
});
test('add folders', () => {
const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath);
return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')) }, { uri: URI.file(path.join(workspaceDir, 'c')) }])
.then(() => {
const actual = testObject.getWorkspace().folders;
assert.equal(actual.length, 4);
assert.equal(path.basename(actual[0].uri.fsPath), 'a');
assert.equal(path.basename(actual[1].uri.fsPath), 'b');
assert.equal(path.basename(actual[2].uri.fsPath), 'd');
assert.equal(path.basename(actual[3].uri.fsPath), 'c');
});
});
test('add folders (with name)', () => {
const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath);
return testObject.addFolders([{ uri: URI.file(path.join(workspaceDir, 'd')), name: 'DDD' }, { uri: URI.file(path.join(workspaceDir, 'c')), name: 'CCC' }])
.then(() => {
const actual = testObject.getWorkspace().folders;
assert.equal(actual.length, 4);
assert.equal(path.basename(actual[0].uri.fsPath), 'a');
assert.equal(path.basename(actual[1].uri.fsPath), 'b');
assert.equal(path.basename(actual[2].uri.fsPath), 'd');
assert.equal(path.basename(actual[3].uri.fsPath), 'c');
assert.equal(actual[2].name, 'DDD');
assert.equal(actual[3].name, 'CCC');
});
});
test('add folders triggers change event', () => {
const target = sinon.spy();
testObject.onDidChangeWorkspaceFolders(target);
const workspaceDir = path.dirname(testObject.getWorkspace().folders[0].uri.fsPath);
const addedFolders = [{ uri: URI.file(path.join(workspaceDir, 'd')) }, { uri: URI.file(path.join(workspaceDir, 'c')) }];
return testObject.addFolders(addedFolders)
.then(() => {
assert.ok(target.calledOnce);
const actual = <IWorkspaceFoldersChangeEvent>target.args[0][0];
assert.deepEqual(actual.added.map(r => r.uri.toString()), addedFolders.map(a => a.uri.toString()));
assert.deepEqual(actual.removed, []);
assert.deepEqual(actual.changed, []);
});
});
test('remove folders', () => {
return testObject.removeFolders([testObject.getWorkspace().folders[0].uri])
.then(() => {
const actual = testObject.getWorkspace().folders;
assert.equal(actual.length, 1);
assert.equal(path.basename(actual[0].uri.fsPath), 'b');
});
});
test('remove folders triggers change event', () => {
const target = sinon.spy();
testObject.onDidChangeWorkspaceFolders(target);
const removedFolder = testObject.getWorkspace().folders[0];
return testObject.removeFolders([removedFolder.uri])
.then(() => {
assert.ok(target.calledOnce);
const actual = <IWorkspaceFoldersChangeEvent>target.args[0][0];
assert.deepEqual(actual.added, []);
assert.deepEqual(actual.removed.map(r => r.uri.toString()), [removedFolder.uri.toString()]);
assert.deepEqual(actual.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]);
});
});
test('reorder folders trigger change event', () => {
const target = sinon.spy();
testObject.onDidChangeWorkspaceFolders(target);
const workspace = { folders: [{ path: testObject.getWorkspace().folders[1].uri.fsPath }, { path: testObject.getWorkspace().folders[0].uri.fsPath }] };
fs.writeFileSync(testObject.getWorkspace().configuration.fsPath, JSON.stringify(workspace, null, '\t'));
return testObject.reloadConfiguration()
.then(() => {
assert.ok(target.calledOnce);
const actual = <IWorkspaceFoldersChangeEvent>target.args[0][0];
assert.deepEqual(actual.added, []);
assert.deepEqual(actual.removed, []);
assert.deepEqual(actual.changed.map(c => c.uri.toString()), testObject.getWorkspace().folders.map(f => f.uri.toString()).reverse());
});
});
test('rename folders trigger change event', () => {
const target = sinon.spy();
testObject.onDidChangeWorkspaceFolders(target);
const workspace = { folders: [{ path: testObject.getWorkspace().folders[0].uri.fsPath, name: '1' }, { path: testObject.getWorkspace().folders[1].uri.fsPath }] };
fs.writeFileSync(testObject.getWorkspace().configuration.fsPath, JSON.stringify(workspace, null, '\t'));
return testObject.reloadConfiguration()
.then(() => {
assert.ok(target.calledOnce);
const actual = <IWorkspaceFoldersChangeEvent>target.args[0][0];
assert.deepEqual(actual.added, []);
assert.deepEqual(actual.removed, []);
assert.deepEqual(actual.changed.map(c => c.uri.toString()), [testObject.getWorkspace().folders[0].uri.toString()]);
});
});
});
suite('WorkspaceConfigurationService - Folder', () => {
let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: IConfigurationService, globalSettingsFile: string;
suiteSetup(() => {
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'configurationService.folder.testSetting': {
'type': 'string',
'default': 'isSet'
},
}
});
});
setup(() => {
return setUpFolderWorkspace(workspaceName)
.then(({ parentDir, folderDir }) => {
parentResource = parentDir;
workspaceDir = folderDir;
globalSettingsFile = path.join(parentDir, 'settings.json');
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
const workspaceService = new WorkspaceService(environmentService, null);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize(folderDir).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.setInstantiationService(instantiationService);
testObject = workspaceService;
});
});
});
teardown(done => {
if (testObject) {
(<WorkspaceService>testObject).dispose();
}
if (parentResource) {
extfs.del(parentResource, os.tmpdir(), () => { }, done);
}
});
test('defaults', () => {
assert.deepEqual(testObject.getValue('configurationService'), { 'folder': { 'testSetting': 'isSet' } });
});
test('globals override defaults', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }');
return testObject.reloadConfiguration()
.then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'userValue'));
});
test('globals', () => {
fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }');
return testObject.reloadConfiguration()
.then(() => assert.equal(testObject.getValue('testworkbench.editor.tabs'), true));
});
test('workspace settings', () => {
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "testworkbench.editor.icons": true }');
return testObject.reloadConfiguration()
.then(() => assert.equal(testObject.getValue('testworkbench.editor.icons'), true));
});
test('workspace settings override user settings', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }');
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }');
return testObject.reloadConfiguration()
.then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue'));
});
test('workspace change triggers event', () => {
// {{SQL CARBON EDIT}}
const settingsFile = path.join(workspaceDir, '.sqlops', 'settings.json');
fs.writeFileSync(settingsFile, '{ "configurationService.folder.testSetting": "workspaceValue" }');
const event = new FileChangesEvent([{ resource: URI.file(settingsFile), type: FileChangeType.ADDED }]);
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return (<WorkspaceService>testObject).handleWorkspaceFileEvents(event)
.then(() => {
assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue');
assert.ok(target.called);
});
});
test('reload configuration emits events after global configuraiton changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }');
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.reloadConfiguration().then(() => assert.ok(target.called));
});
test('reload configuration emits events after workspace configuraiton changes', () => {
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }');
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.reloadConfiguration().then(() => assert.ok(target.called));
});
test('reload configuration should not emit event if no changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "testworkbench.editor.tabs": true }');
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(() => { target(); });
return testObject.reloadConfiguration()
.then(() => assert.ok(!target.called));
});
});
test('inspect', () => {
let actual = testObject.inspect('something.missing');
assert.equal(actual.default, void 0);
assert.equal(actual.user, void 0);
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, void 0);
actual = testObject.inspect('configurationService.folder.testSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, void 0);
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'isSet');
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.inspect('configurationService.folder.testSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, 'userValue');
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'userValue');
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.inspect('configurationService.folder.testSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, 'userValue');
assert.equal(actual.workspace, 'workspaceValue');
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'workspaceValue');
});
});
});
test('keys', () => {
let actual = testObject.keys();
assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1);
assert.deepEqual(actual.user, []);
assert.deepEqual(actual.workspace, []);
assert.deepEqual(actual.workspaceFolder, []);
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.keys();
assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1);
assert.deepEqual(actual.user, ['configurationService.folder.testSetting']);
assert.deepEqual(actual.workspace, []);
assert.deepEqual(actual.workspaceFolder, []);
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(workspaceDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.keys();
assert.ok(actual.default.indexOf('configurationService.folder.testSetting') !== -1);
assert.deepEqual(actual.user, ['configurationService.folder.testSetting']);
assert.deepEqual(actual.workspace, ['configurationService.folder.testSetting']);
assert.deepEqual(actual.workspaceFolder, []);
});
});
});
test('update user configuration', () => {
return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER)
.then(() => assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'value'));
});
test('update workspace configuration', () => {
return testObject.updateValue('tasks.service.testSetting', 'value', ConfigurationTarget.WORKSPACE)
.then(() => assert.equal(testObject.getValue('tasks.service.testSetting'), 'value'));
});
test('update tasks configuration', () => {
return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE)
.then(() => assert.deepEqual(testObject.getValue('tasks'), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }));
});
test('update user configuration should trigger change event before promise is resolve', () => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.USER)
.then(() => assert.ok(target.called));
});
test('update workspace configuration should trigger change event before promise is resolve', () => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.folder.testSetting', 'value', ConfigurationTarget.WORKSPACE)
.then(() => assert.ok(target.called));
});
test('update task configuration should trigger change event before promise is resolve', () => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE)
.then(() => assert.ok(target.called));
});
test('initialize with different folder triggers configuration event if there are changes', () => {
return setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`)
.then(({ folderDir }) => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(folderDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return (<WorkspaceService>testObject).initialize(folderDir)
.then(() => {
assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2');
assert.ok(target.called);
});
});
});
test('initialize with different folder triggers configuration event if there are no changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return testObject.reloadConfiguration()
.then(() => setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`))
.then(({ folderDir }) => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(() => target());
// {{SQL CARBON EDIT}}
fs.writeFileSync(path.join(folderDir, '.sqlops', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return (<WorkspaceService>testObject).initialize(folderDir)
.then(() => {
assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2');
assert.ok(!target.called);
});
});
});
});
suite('WorkspaceConfigurationService - Update (Multiroot)', () => {
let parentResource: string, workspaceContextService: IWorkspaceContextService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService;
suiteSetup(() => {
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'configurationService.workspace.testSetting': {
'type': 'string',
'default': 'isSet'
},
'configurationService.workspace.testResourceSetting': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.RESOURCE
}
}
});
});
setup(() => {
return setUpWorkspace(['1', '2'])
.then(({ parentDir, configPath }) => {
parentResource = parentDir;
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json'));
const workspaceService = new WorkspaceService(environmentService, null);
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize({ id: configPath, configPath }).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, new TestTextResourceConfigurationService(), workspaceService, { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.setInstantiationService(instantiationService);
workspaceContextService = workspaceService;
jsonEditingServce = instantiationService.createInstance(JSONEditingService);
testObject = workspaceService;
});
});
});
teardown(done => {
if (testObject) {
(<WorkspaceService>testObject).dispose();
}
if (parentResource) {
extfs.del(parentResource, os.tmpdir(), () => { }, done);
}
});
test('update user configuration', () => {
return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER)
.then(() => assert.equal(testObject.getValue('configurationService.workspace.testSetting'), 'userValue'));
});
test('update user configuration should trigger change event before promise is resolve', () => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER)
.then(() => assert.ok(target.called));
});
test('update workspace configuration', () => {
return testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE)
.then(() => assert.equal(testObject.getValue('configurationService.workspace.testSetting'), 'workspaceValue'));
});
test('update workspace configuration should trigger change event before promise is resolve', () => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.workspace.testSetting', 'workspaceValue', ConfigurationTarget.WORKSPACE)
.then(() => assert.ok(target.called));
});
test('update workspace folder configuration', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
.then(() => assert.equal(testObject.getValue('configurationService.workspace.testResourceSetting', { resource: workspace.folders[0].uri }), 'workspaceFolderValue'));
});
test('update workspace folder configuration should trigger change event before promise is resolve', () => {
const workspace = workspaceContextService.getWorkspace();
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
.then(() => assert.ok(target.called));
});
test('update tasks configuration in a folder', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
.then(() => assert.deepEqual(testObject.getValue('tasks', { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }));
});
test('update tasks configuration in a workspace is not supported', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true)
.then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET));
});
test('update launch configuration in a workspace is not supported', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('launch', { 'version': '1.0.0', configurations: [{ 'name': 'myLaunch' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true)
.then(() => assert.fail('Should not be supported'), (e) => assert.equal(e.code, ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET));
});
test('task configurations are not read from workspace', () => {
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration, { key: 'tasks', value: { 'version': '1.0' } }, true)
.then(() => testObject.reloadConfiguration())
.then(() => {
const actual = testObject.inspect('tasks.version');
assert.equal(actual.workspace, void 0);
});
});
test('launch configurations are not read from workspace', () => {
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration, { key: 'launch', value: { 'version': '1.0' } }, true)
.then(() => testObject.reloadConfiguration())
.then(() => {
const actual = testObject.inspect('launch.version');
assert.equal(actual.workspace, void 0);
});
assert.equal(0, 0);
});
});