Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028)

This commit is contained in:
Anthony Dresser
2019-04-14 22:29:14 -07:00
committed by GitHub
parent 6dbf757385
commit 57242a2e13
210 changed files with 4898 additions and 3018 deletions

View File

@@ -29,7 +29,6 @@ export class RemoteUserConfiguration extends Disposable {
private readonly _cachedConfiguration: CachedUserConfiguration;
private readonly _configurationFileService: IConfigurationFileService;
private _userConfiguration: UserConfiguration | CachedUserConfiguration;
private _userConfigurationDisposable: IDisposable = Disposable.None;
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
@@ -43,13 +42,14 @@ export class RemoteUserConfiguration extends Disposable {
super();
this._configurationFileService = configurationFileService;
this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, configurationCache);
remoteAgentService.getEnvironment().then(environment => {
remoteAgentService.getEnvironment().then(async environment => {
if (environment) {
const userConfiguration = this._register(new UserConfiguration(environment.settingsPath, MACHINE_SCOPES, this._configurationFileService));
this._register(userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
const configurationModel = await userConfiguration.initialize();
this._userConfiguration.dispose();
this._userConfigurationDisposable.dispose();
this._userConfiguration = this._register(new UserConfiguration(environment.settingsPath, MACHINE_SCOPES, this._configurationFileService));
this._userConfigurationDisposable = this._register(this._userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
this._userConfiguration.initialize().then(configurationModel => this.onDidUserConfigurationChange(configurationModel));
this._userConfiguration = userConfiguration;
this.onDidUserConfigurationChange(configurationModel);
}
});
}

View File

@@ -18,10 +18,10 @@ import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides
import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, IConfigurationFileService, machineSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
@@ -269,6 +269,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
inspect<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
userLocal?: T,
userRemote?: T,
workspace?: T,
workspaceFolder?: T,
memory?: T,
@@ -419,8 +421,15 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
}
private reloadUserConfiguration(key?: string): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> {
return Promise.all([this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()), this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel())])
.then(([local, remote]) => ({ local, remote }));
return Promise.all([this.reloadLocalUserConfiguration(), this.reloadRemoeUserConfiguration()]).then(([local, remote]) => ({ local, remote }));
}
private reloadLocalUserConfiguration(key?: string): Promise<ConfigurationModel> {
return this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel());
}
private reloadRemoeUserConfiguration(key?: string): Promise<ConfigurationModel> {
return this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel());
}
private reloadWorkspaceConfiguration(key?: string): Promise<void> {
@@ -503,16 +512,18 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
};
const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in User Settings"));
const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user Settings"));
const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user Settings"));
const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema);
jsonRegistry.registerSchema(userSettingsSchemaId, allSettingsSchema);
jsonRegistry.registerSchema(machineSettingsSchemaId, workspaceSettingsSchema);
jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema);
if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) {
const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties, localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly."));
const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema);
jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema);
} else {
@@ -613,20 +624,25 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
return Promise.resolve(undefined);
}
return this.configurationEditingService.writeConfiguration(target, { key, value }, { scopes: overrides, donotNotifyError })
const editableConfigurationTarget = this.toEditableConfigurationTarget(target, key);
if (!editableConfigurationTarget) {
return Promise.reject(new Error('Invalid configuration target'));
}
if (editableConfigurationTarget === EditableConfigurationTarget.USER_REMOTE && !this.remoteUserConfiguration) {
return Promise.reject(new Error('Invalid configuration target'));
}
return this.configurationEditingService.writeConfiguration(editableConfigurationTarget, { key, value }, { scopes: overrides, donotNotifyError })
.then(() => {
switch (target) {
case ConfigurationTarget.USER:
return this.reloadUserConfiguration()
.then(({ local, remote }) => {
this.onLocalUserConfigurationChanged(local);
if (this.remoteUserConfiguration) {
this.onRemoteUserConfigurationChanged(remote);
}
});
case ConfigurationTarget.WORKSPACE:
switch (editableConfigurationTarget) {
case EditableConfigurationTarget.USER_LOCAL:
return this.reloadLocalUserConfiguration().then(local => this.onLocalUserConfigurationChanged(local));
case EditableConfigurationTarget.USER_REMOTE:
return this.reloadRemoeUserConfiguration().then(remote => this.onRemoteUserConfigurationChanged(remote));
case EditableConfigurationTarget.WORKSPACE:
return this.reloadWorkspaceConfiguration();
case ConfigurationTarget.WORKSPACE_FOLDER:
case EditableConfigurationTarget.WORKSPACE_FOLDER:
const workspaceFolder = overrides && overrides.resource ? this.workspace.getFolder(overrides.resource) : null;
if (workspaceFolder) {
return this.reloadWorkspaceFolderConfiguration(workspaceFolder, key);
@@ -681,4 +697,26 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
}
return {};
}
private toEditableConfigurationTarget(target: ConfigurationTarget, key: string): EditableConfigurationTarget | null {
if (target === ConfigurationTarget.USER) {
if (this.inspect(key).userRemote !== undefined) {
return EditableConfigurationTarget.USER_REMOTE;
}
return EditableConfigurationTarget.USER_LOCAL;
}
if (target === ConfigurationTarget.USER_LOCAL) {
return EditableConfigurationTarget.USER_LOCAL;
}
if (target === ConfigurationTarget.USER_REMOTE) {
return EditableConfigurationTarget.USER_REMOTE;
}
if (target === ConfigurationTarget.WORKSPACE) {
return EditableConfigurationTarget.WORKSPACE;
}
if (target === ConfigurationTarget.WORKSPACE_FOLDER) {
return EditableConfigurationTarget.WORKSPACE_FOLDER;
}
return null;
}
}

View File

@@ -20,7 +20,7 @@ export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace';
export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
export const launchSchemaId = 'vscode://schemas/launch';
export const MACHINE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE];

View File

@@ -18,7 +18,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/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 { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/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, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
@@ -42,6 +42,11 @@ export const enum ConfigurationEditingErrorCode {
*/
ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION,
/**
* Error when trying to write a machne setting into workspace settings.
*/
ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE,
/**
* Error when trying to write an invalid folder configuration key to folder settings.
*/
@@ -104,8 +109,15 @@ export interface IConfigurationEditingOptions {
scopes?: IConfigurationOverrides;
}
export const enum EditableConfigurationTarget {
USER_LOCAL = 1,
USER_REMOTE,
WORKSPACE,
WORKSPACE_FOLDER
}
interface IConfigurationEditOperation extends IConfigurationValue {
target: ConfigurationTarget;
target: EditableConfigurationTarget;
jsonPath: json.JSONPath;
resource?: URI;
workspaceStandAloneConfigurationKey?: string;
@@ -143,7 +155,7 @@ export class ConfigurationEditingService {
});
}
writeConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise<void> {
writeConfiguration(target: EditableConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise<void> {
const operation = this.getConfigurationEditOperation(target, value, options.scopes || {});
return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(operation, options) // queue up writes to prevent race conditions
.then(() => null,
@@ -251,13 +263,16 @@ export class ConfigurationEditingService {
private openSettings(operation: IConfigurationEditOperation): void {
switch (operation.target) {
case ConfigurationTarget.USER:
case EditableConfigurationTarget.USER_LOCAL:
this.preferencesService.openGlobalSettings(true);
break;
case ConfigurationTarget.WORKSPACE:
case EditableConfigurationTarget.USER_REMOTE:
this.preferencesService.openRemoteSettings();
break;
case EditableConfigurationTarget.WORKSPACE:
this.preferencesService.openWorkspaceSettings(true);
break;
case ConfigurationTarget.WORKSPACE_FOLDER:
case EditableConfigurationTarget.WORKSPACE_FOLDER:
if (operation.resource) {
const workspaceFolder = this.contextService.getWorkspaceFolder(operation.resource);
if (workspaceFolder) {
@@ -272,18 +287,19 @@ export class ConfigurationEditingService {
this.editorService.openEditor({ resource });
}
private reject<T = never>(code: ConfigurationEditingErrorCode, target: ConfigurationTarget, operation: IConfigurationEditOperation): Promise<T> {
private reject<T = never>(code: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): Promise<T> {
const message = this.toErrorMessage(code, target, operation);
return Promise.reject(new ConfigurationEditingError(message, code));
}
private toErrorMessage(error: ConfigurationEditingErrorCode, target: ConfigurationTarget, operation: IConfigurationEditOperation): string {
private toErrorMessage(error: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): string {
switch (error) {
// API constraints
case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return nls.localize('errorUnknownKey', "Unable to write to {0} because {1} is not a registered configuration.", this.stringifyTarget(target), operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION: return nls.localize('errorInvalidWorkspaceConfigurationApplication', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE: return nls.localize('errorInvalidWorkspaceConfigurationMachine', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION: return nls.localize('errorInvalidFolderConfiguration', "Unable to write to Folder Settings because {0} does not support the folder resource scope.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET: return nls.localize('errorInvalidUserTarget', "Unable to write to User Settings because {0} does not support for global scope.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET: return nls.localize('errorInvalidWorkspaceTarget', "Unable to write to Workspace Settings because {0} does not support for workspace scope in a multi folder workspace.", operation.key);
@@ -299,11 +315,13 @@ export class ConfigurationEditingService {
return nls.localize('errorInvalidLaunchConfiguration', "Unable to write into the launch configuration file. Please open it to correct errors/warnings in it and try again.");
}
switch (target) {
case ConfigurationTarget.USER:
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open the user settings to correct errors/warnings in it and try again.");
case ConfigurationTarget.WORKSPACE:
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('errorInvalidRemoteConfiguration', "Unable to write into remote user settings. Please open the remote user settings to correct errors/warnings in it and try again.");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open the workspace settings to correct errors/warnings in the file and try again.");
case ConfigurationTarget.WORKSPACE_FOLDER:
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = this.contextService.getWorkspaceFolder(operation.resource);
@@ -323,11 +341,13 @@ export class ConfigurationEditingService {
return nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch configuration file because the file is dirty. Please save it first and then try again.");
}
switch (target) {
case ConfigurationTarget.USER:
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the user settings file first and then try again.");
case ConfigurationTarget.WORKSPACE:
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('errorRemoteConfigurationFileDirty', "Unable to write into remote user settings because the file is dirty. Please save the remote user settings file first and then try again.");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the workspace settings file first and then try again.");
case ConfigurationTarget.WORKSPACE_FOLDER:
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = this.contextService.getWorkspaceFolder(operation.resource);
@@ -342,13 +362,15 @@ export class ConfigurationEditingService {
}
}
private stringifyTarget(target: ConfigurationTarget): string {
private stringifyTarget(target: EditableConfigurationTarget): string {
switch (target) {
case ConfigurationTarget.USER:
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('userTarget', "User Settings");
case ConfigurationTarget.WORKSPACE:
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('remoteUserTarget', "Remote User Settings");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('workspaceTarget', "Workspace Settings");
case ConfigurationTarget.WORKSPACE_FOLDER:
case EditableConfigurationTarget.WORKSPACE_FOLDER:
return nls.localize('folderTarget', "Folder Settings");
}
return '';
@@ -375,7 +397,7 @@ export class ConfigurationEditingService {
private async resolveModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
const exists = await this.fileService.exists(resource);
if (!exists) {
await this.textFileService.write(resource, '{}');
await this.textFileService.write(resource, '{}', { encoding: 'utf8' });
}
return this.textModelResolverService.createModelReference(resource);
}
@@ -391,7 +413,7 @@ export class ConfigurationEditingService {
return parseErrors.length > 0;
}
private resolveAndValidate(target: ConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): Promise<IReference<IResolvedTextEditorModel>> {
private resolveAndValidate(target: EditableConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): Promise<IReference<IResolvedTextEditorModel>> {
// Any key must be a known setting from the registry (unless this is a standalone config)
if (!operation.workspaceStandAloneConfigurationKey) {
@@ -403,31 +425,34 @@ export class ConfigurationEditingService {
if (operation.workspaceStandAloneConfigurationKey) {
// Global tasks and launches are not supported
if (target === ConfigurationTarget.USER) {
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation);
}
// Workspace tasks are not supported
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === ConfigurationTarget.WORKSPACE) {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === EditableConfigurationTarget.WORKSPACE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation);
}
}
// Target cannot be workspace or folder if no workspace opened
if ((target === ConfigurationTarget.WORKSPACE || target === ConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
if ((target === EditableConfigurationTarget.WORKSPACE || target === EditableConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
return this.reject(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target, operation);
}
if (target === ConfigurationTarget.WORKSPACE) {
if (target === EditableConfigurationTarget.WORKSPACE) {
if (!operation.workspaceStandAloneConfigurationKey) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[operation.key].scope === ConfigurationScope.APPLICATION) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, target, operation);
}
if (configurationProperties[operation.key].scope === ConfigurationScope.MACHINE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE, target, operation);
}
}
}
if (target === ConfigurationTarget.WORKSPACE_FOLDER) {
if (target === EditableConfigurationTarget.WORKSPACE_FOLDER) {
if (!operation.resource) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation);
}
@@ -460,7 +485,7 @@ export class ConfigurationEditingService {
});
}
private getConfigurationEditOperation(target: ConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation {
private getConfigurationEditOperation(target: EditableConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation {
// Check for standalone workspace configurations
if (config.key) {
@@ -485,7 +510,7 @@ export class ConfigurationEditingService {
let key = config.key;
let jsonPath = overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier), key] : [key];
if (target === ConfigurationTarget.USER) {
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, config, '', null)), target };
}
@@ -501,26 +526,19 @@ export class ConfigurationEditingService {
return !!(workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath);
}
private getConfigurationFileResource(target: ConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null {
if (target === ConfigurationTarget.USER_LOCAL) {
private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null {
if (target === EditableConfigurationTarget.USER_LOCAL) {
return URI.file(this.environmentService.appSettingsPath);
}
if (target === ConfigurationTarget.USER_REMOTE) {
if (target === EditableConfigurationTarget.USER_REMOTE) {
return this.remoteSettingsResource;
}
if (target === ConfigurationTarget.USER) {
if (this.configurationService.inspect(config.key).userRemote !== undefined) {
return this.remoteSettingsResource;
}
return URI.file(this.environmentService.appSettingsPath);
}
const workbenchState = this.contextService.getWorkbenchState();
if (workbenchState !== WorkbenchState.EMPTY) {
const workspace = this.contextService.getWorkspace();
if (target === ConfigurationTarget.WORKSPACE) {
if (target === EditableConfigurationTarget.WORKSPACE) {
if (workbenchState === WorkbenchState.WORKSPACE) {
return withUndefinedAsNull(workspace.configuration);
}
@@ -529,7 +547,7 @@ export class ConfigurationEditingService {
}
}
if (target === ConfigurationTarget.WORKSPACE_FOLDER) {
if (target === EditableConfigurationTarget.WORKSPACE_FOLDER) {
if (resource) {
const folder = this.contextService.getWorkspaceFolder(resource);
if (folder) {

View File

@@ -97,6 +97,8 @@ export class Configuration extends BaseConfiguration {
inspect<C>(key: string, overrides: IConfigurationOverrides = {}): {
default: C,
user: C,
userLocal?: C,
userRemote?: C,
workspace?: C,
workspaceFolder?: C
memory?: C

View File

@@ -86,7 +86,7 @@ export class JSONEditingService implements IJSONEditingService {
private async resolveModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
const exists = await this.fileService.exists(resource);
if (!exists) {
await this.textFileService.write(resource, '{}');
await this.textFileService.write(resource, '{}', { encoding: 'utf8' });
}
return this.textModelResolverService.createModelReference(resource);
}

View File

@@ -35,6 +35,11 @@ suite('FolderSettingsModelParser', () => {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.APPLICATION
},
'FolderSettingsModelParser.machine': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.MACHINE
}
}
});
@@ -43,7 +48,7 @@ suite('FolderSettingsModelParser', () => {
test('parse all folder settings', () => {
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]);
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' }));
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }));
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'window': 'window', 'resource': 'resource' } });
});
@@ -51,7 +56,7 @@ suite('FolderSettingsModelParser', () => {
test('parse resource folder settings', () => {
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE]);
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' }));
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' }));
assert.deepEqual(testObject.configurationModel.contents, { 'FolderSettingsModelParser': { 'resource': 'resource' } });
});
@@ -59,12 +64,12 @@ suite('FolderSettingsModelParser', () => {
test('parse overridable resource settings', () => {
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE]);
testObject.parseContent(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'executable' } }));
testObject.parseContent(JSON.stringify({ '[json]': { 'FolderSettingsModelParser.window': 'window', 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.application': 'application', 'FolderSettingsModelParser.machine': 'executable' } }));
assert.deepEqual(testObject.configurationModel.overrides, [{ 'contents': { 'FolderSettingsModelParser': { 'resource': 'resource' } }, 'identifiers': ['json'] }]);
});
test('reprocess folder settings excludes application setting', () => {
test('reprocess folder settings excludes application and machine setting', () => {
const testObject = new ConfigurationModelParser('settings', [ConfigurationScope.RESOURCE, ConfigurationScope.WINDOW]);
testObject.parseContent(JSON.stringify({ 'FolderSettingsModelParser.resource': 'resource', 'FolderSettingsModelParser.anotherApplicationSetting': 'executable' }));
@@ -80,6 +85,11 @@ suite('FolderSettingsModelParser', () => {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.APPLICATION
},
'FolderSettingsModelParser.anotherMachineSetting': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.MACHINE
}
}
});

View File

@@ -19,9 +19,9 @@ import * as uuid from 'vs/base/common/uuid';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
import { LegacyFileService } from 'vs/workbench/services/files/node/fileService';
import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
@@ -153,41 +153,41 @@ suite('ConfigurationEditingService', () => {
}
test('errors cases - invalid key', () => {
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' })
.then(() => assert.fail('Should fail with ERROR_UNKNOWN_KEY'),
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY));
});
test('errors cases - invalid target', () => {
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'tasks.something', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'tasks.something', value: 'value' })
.then(() => assert.fail('Should fail with ERROR_INVALID_TARGET'),
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET));
});
test('errors cases - no workspace', () => {
return setUpServices(true)
.then(() => testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' }))
.then(() => testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' }))
.then(() => assert.fail('Should fail with ERROR_NO_WORKSPACE_OPENED'),
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED));
});
test('errors cases - invalid configuration', () => {
fs.writeFileSync(globalSettingsFile, ',,,,,,,,,,,,,,');
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' })
.then(() => assert.fail('Should fail with ERROR_INVALID_CONFIGURATION'),
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION));
});
test('errors cases - dirty', () => {
instantiationService.stub(ITextFileService, 'isDirty', true);
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' })
.then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'),
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY));
});
test('dirty error is not thrown if not asked to save', () => {
instantiationService.stub(ITextFileService, 'isDirty', true);
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotSave: true })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotSave: true })
.then(() => null, error => assert.fail('Should not fail.'));
});
@@ -195,7 +195,7 @@ suite('ConfigurationEditingService', () => {
instantiationService.stub(ITextFileService, 'isDirty', true);
const target = sinon.stub();
instantiationService.stub(INotificationService, <INotificationService>{ prompt: target, _serviceBrand: null, notify: null!, error: null!, info: null!, warn: null! });
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true })
.then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'),
(error: ConfigurationEditingError) => {
assert.equal(false, target.calledOnce);
@@ -204,7 +204,7 @@ suite('ConfigurationEditingService', () => {
});
test('write one setting - empty file', () => {
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
@@ -214,7 +214,7 @@ suite('ConfigurationEditingService', () => {
test('write one setting - existing file', () => {
fs.writeFileSync(globalSettingsFile, '{ "my.super.setting": "my.super.value" }');
return testObject.writeConfiguration(ConfigurationTarget.USER, { key: 'configurationEditing.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
@@ -225,7 +225,7 @@ 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 })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
@@ -236,7 +236,7 @@ suite('ConfigurationEditingService', () => {
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 })
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: undefined })
.then(() => {
const contents = fs.readFileSync(globalSettingsFile).toString('utf8');
const parsed = json.parse(contents);
@@ -246,7 +246,7 @@ suite('ConfigurationEditingService', () => {
});
test('write workspace standalone setting - empty file', () => {
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' })
.then(() => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
const contents = fs.readFileSync(target).toString('utf8');
@@ -258,7 +258,7 @@ suite('ConfigurationEditingService', () => {
test('write workspace standalone setting - existing file', () => {
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']);
fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }');
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' })
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' })
.then(() => {
const contents = fs.readFileSync(target).toString('utf8');
const parsed = json.parse(contents);
@@ -268,7 +268,7 @@ suite('ConfigurationEditingService', () => {
});
test('write workspace standalone setting - empty file - full JSON', () => {
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
return testObject.writeConfiguration(EditableConfigurationTarget.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');
@@ -282,7 +282,7 @@ suite('ConfigurationEditingService', () => {
test('write workspace standalone setting - existing file - full JSON', () => {
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' }] } })
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
.then(() => {
const contents = fs.readFileSync(target).toString('utf8');
const parsed = json.parse(contents);
@@ -295,7 +295,7 @@ suite('ConfigurationEditingService', () => {
test('write workspace standalone setting - existing file with JSON errors - full JSON', () => {
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' }] } })
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
.then(() => {
const contents = fs.readFileSync(target).toString('utf8');
const parsed = json.parse(contents);
@@ -318,7 +318,7 @@ suite('ConfigurationEditingService', () => {
}
]
}`);
return testObject.writeConfiguration(ConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } })
return testObject.writeConfiguration(EditableConfigurationTarget.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');