mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
parent
16125bcbe3
commit
f837c3e54f
|
@ -88,6 +88,10 @@
|
|||
"fileMatch": "/.vscode/tasks.json",
|
||||
"url": "vscode://schemas/tasks"
|
||||
},
|
||||
{
|
||||
"fileMatch": "%APP_SETTINGS_HOME%/tasks.json",
|
||||
"url": "vscode://schemas/tasks"
|
||||
},
|
||||
{
|
||||
"fileMatch": "%APP_SETTINGS_HOME%/snippets/*.json",
|
||||
"url": "vscode://schemas/snippets"
|
||||
|
|
|
@ -7,12 +7,12 @@ import { URI } from 'vs/base/common/uri';
|
|||
import * as resources from 'vs/base/common/resources';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable, IDisposable, dispose, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
|
||||
import { FileChangeType, FileChangesEvent, IFileService, whenProviderRegistered } from 'vs/platform/files/common/files';
|
||||
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
||||
import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
|
@ -26,28 +26,61 @@ import { hash } from 'vs/base/common/hash';
|
|||
|
||||
export class UserConfiguration extends Disposable {
|
||||
|
||||
private readonly parser: ConfigurationModelParser;
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
private readonly _onDidInitializeCompleteConfiguration: Emitter<void> = this._register(new Emitter<void>());
|
||||
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
|
||||
|
||||
private readonly userConfiguration: MutableDisposable<UserSettings | FileServiceBasedConfigurationWithNames> = this._register(new MutableDisposable<UserSettings | FileServiceBasedConfigurationWithNames>());
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
|
||||
constructor(
|
||||
private readonly userSettingsResource: URI,
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
|
||||
this.userConfiguration.value = new UserSettings(this.userSettingsResource, this.scopes, this.fileService);
|
||||
this._register(this.userConfiguration.value.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
|
||||
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this.reloadConfigurationScheduler.schedule()));
|
||||
|
||||
runWhenIdle(() => this._onDidInitializeCompleteConfiguration.fire(), 5000);
|
||||
this._register(Event.once(this._onDidInitializeCompleteConfiguration.event)(() => this.reloadConfigurationScheduler.schedule()));
|
||||
}
|
||||
|
||||
async initialize(): Promise<ConfigurationModel> {
|
||||
return this.reload();
|
||||
return this.userConfiguration.value!.loadConfiguration();
|
||||
}
|
||||
|
||||
async reload(): Promise<ConfigurationModel> {
|
||||
if (!(this.userConfiguration.value instanceof FileServiceBasedConfigurationWithNames)) {
|
||||
this.userConfiguration.value = new FileServiceBasedConfigurationWithNames(resources.dirname(this.userSettingsResource), [FOLDER_SETTINGS_NAME, TASKS_CONFIGURATION_KEY], this.scopes, this.fileService);
|
||||
this._register(this.userConfiguration.value.onDidChange(() => this.reloadConfigurationScheduler.schedule()));
|
||||
}
|
||||
return this.userConfiguration.value!.loadConfiguration();
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
return this.userConfiguration.value!.reprocess();
|
||||
}
|
||||
}
|
||||
|
||||
class UserSettings extends Disposable {
|
||||
|
||||
private readonly parser: ConfigurationModelParser;
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(
|
||||
private readonly userSettingsResource: URI,
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
|
||||
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this._onDidChange.fire()));
|
||||
}
|
||||
|
||||
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||
try {
|
||||
const content = await this.fileService.readFile(this.userSettingsResource);
|
||||
this.parser.parseContent(content.value.toString() || '{}');
|
||||
|
@ -63,6 +96,127 @@ export class UserConfiguration extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
class FileServiceBasedConfigurationWithNames extends Disposable {
|
||||
|
||||
private _folderSettingsModelParser: ConfigurationModelParser;
|
||||
private _standAloneConfigurations: ConfigurationModel[];
|
||||
private _cache: ConfigurationModel;
|
||||
|
||||
protected readonly configurationResources: URI[];
|
||||
protected changeEventTriggerScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(protected readonly configurationFolder: URI,
|
||||
private readonly configurationNames: string[],
|
||||
private readonly scopes: ConfigurationScope[] | undefined,
|
||||
private fileService: IFileService) {
|
||||
super();
|
||||
this.configurationResources = this.configurationNames.map(name => resources.joinPath(this.configurationFolder, `${name}.json`));
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser(this.configurationFolder.toString(), this.scopes);
|
||||
this._standAloneConfigurations = [];
|
||||
this._cache = new ConfigurationModel();
|
||||
|
||||
this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this._register(this.fileService.onFileChanges((e) => this.handleFileEvents(e)));
|
||||
}
|
||||
|
||||
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||
const configurationContents = await Promise.all(this.configurationResources.map(async resource => {
|
||||
try {
|
||||
const content = await this.fileService.readFile(resource);
|
||||
return content.value.toString();
|
||||
} catch (error) {
|
||||
const exists = await this.fileService.exists(resource);
|
||||
if (exists) {
|
||||
errors.onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}));
|
||||
|
||||
// reset
|
||||
this._standAloneConfigurations = [];
|
||||
this._folderSettingsModelParser.parseContent('');
|
||||
|
||||
// parse
|
||||
if (configurationContents[0]) {
|
||||
this._folderSettingsModelParser.parseContent(configurationContents[0]);
|
||||
}
|
||||
for (let index = 1; index < configurationContents.length; index++) {
|
||||
const contents = configurationContents[index];
|
||||
if (contents) {
|
||||
const standAloneConfigurationModelParser = new StandaloneConfigurationModelParser(this.configurationResources[index].toString(), this.configurationNames[index]);
|
||||
standAloneConfigurationModelParser.parseContent(contents);
|
||||
this._standAloneConfigurations.push(standAloneConfigurationModelParser.configurationModel);
|
||||
}
|
||||
}
|
||||
|
||||
// Consolidate (support *.json files in the workspace settings folder)
|
||||
this.consolidate();
|
||||
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
const oldContents = this._folderSettingsModelParser.configurationModel.contents;
|
||||
this._folderSettingsModelParser.parse();
|
||||
if (!equals(oldContents, this._folderSettingsModelParser.configurationModel.contents)) {
|
||||
this.consolidate();
|
||||
}
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
private consolidate(): void {
|
||||
this._cache = this._folderSettingsModelParser.configurationModel.merge(...this._standAloneConfigurations);
|
||||
}
|
||||
|
||||
protected async handleFileEvents(event: FileChangesEvent): Promise<void> {
|
||||
const events = event.changes;
|
||||
let affectedByChanges = false;
|
||||
|
||||
// Find changes that affect workspace configuration files
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
const resource = events[i].resource;
|
||||
const basename = resources.basename(resource);
|
||||
const isJson = extname(basename) === '.json';
|
||||
const isConfigurationFolderDeleted = (events[i].type === FileChangeType.DELETED && resources.isEqual(resource, this.configurationFolder));
|
||||
|
||||
if (!isJson && !isConfigurationFolderDeleted) {
|
||||
continue; // only JSON files or the actual settings folder
|
||||
}
|
||||
|
||||
const folderRelativePath = this.toFolderRelativePath(resource);
|
||||
if (!folderRelativePath) {
|
||||
continue; // event is not inside folder
|
||||
}
|
||||
|
||||
// Handle case where ".vscode" got deleted
|
||||
if (isConfigurationFolderDeleted) {
|
||||
affectedByChanges = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// only valid workspace config files
|
||||
if (this.configurationResources.some(configurationResource => resources.isEqual(configurationResource, resource))) {
|
||||
affectedByChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (affectedByChanges) {
|
||||
this.changeEventTriggerScheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private toFolderRelativePath(resource: URI): string | undefined {
|
||||
if (resources.isEqualOrParent(resource, this.configurationFolder)) {
|
||||
return resources.relativePath(this.configurationFolder, resource);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoteUserConfiguration extends Disposable {
|
||||
|
||||
private readonly _cachedConfiguration: CachedRemoteUserConfiguration;
|
||||
|
@ -546,125 +700,12 @@ export interface IFolderConfiguration extends IDisposable {
|
|||
reprocess(): ConfigurationModel;
|
||||
}
|
||||
|
||||
class FileServiceBasedFolderConfiguration extends Disposable implements IFolderConfiguration {
|
||||
class FileServiceBasedFolderConfiguration extends FileServiceBasedConfigurationWithNames implements IFolderConfiguration {
|
||||
|
||||
private _folderSettingsModelParser: ConfigurationModelParser;
|
||||
private _standAloneConfigurations: ConfigurationModel[];
|
||||
private _cache: ConfigurationModel;
|
||||
|
||||
private readonly configurationNames: string[];
|
||||
protected readonly configurationResources: URI[];
|
||||
private changeEventTriggerScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private fileService: IFileService) {
|
||||
super();
|
||||
|
||||
this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY];
|
||||
this.configurationResources = this.configurationNames.map(name => resources.joinPath(this.configurationFolder, `${name}.json`));
|
||||
this._folderSettingsModelParser = new ConfigurationModelParser(FOLDER_SETTINGS_PATH, WorkbenchState.WORKSPACE === workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES);
|
||||
this._standAloneConfigurations = [];
|
||||
this._cache = new ConfigurationModel();
|
||||
|
||||
this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
|
||||
constructor(configurationFolder: URI, workbenchState: WorkbenchState, fileService: IFileService) {
|
||||
super(configurationFolder, [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY], WorkbenchState.WORKSPACE === workbenchState ? FOLDER_SCOPES : WORKSPACE_SCOPES, fileService);
|
||||
}
|
||||
|
||||
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||
const configurationContents = await Promise.all(this.configurationResources.map(async resource => {
|
||||
try {
|
||||
const content = await this.fileService.readFile(resource);
|
||||
return content.value.toString();
|
||||
} catch (error) {
|
||||
const exists = await this.fileService.exists(resource);
|
||||
if (exists) {
|
||||
errors.onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}));
|
||||
|
||||
// reset
|
||||
this._standAloneConfigurations = [];
|
||||
this._folderSettingsModelParser.parseContent('');
|
||||
|
||||
// parse
|
||||
if (configurationContents[0]) {
|
||||
this._folderSettingsModelParser.parseContent(configurationContents[0]);
|
||||
}
|
||||
for (let index = 1; index < configurationContents.length; index++) {
|
||||
const contents = configurationContents[index];
|
||||
if (contents) {
|
||||
const standAloneConfigurationModelParser = new StandaloneConfigurationModelParser(this.configurationResources[index].toString(), this.configurationNames[index]);
|
||||
standAloneConfigurationModelParser.parseContent(contents);
|
||||
this._standAloneConfigurations.push(standAloneConfigurationModelParser.configurationModel);
|
||||
}
|
||||
}
|
||||
|
||||
// Consolidate (support *.json files in the workspace settings folder)
|
||||
this.consolidate();
|
||||
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
const oldContents = this._folderSettingsModelParser.configurationModel.contents;
|
||||
this._folderSettingsModelParser.parse();
|
||||
if (!equals(oldContents, this._folderSettingsModelParser.configurationModel.contents)) {
|
||||
this.consolidate();
|
||||
}
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
private consolidate(): void {
|
||||
this._cache = this._folderSettingsModelParser.configurationModel.merge(...this._standAloneConfigurations);
|
||||
}
|
||||
|
||||
private handleWorkspaceFileEvents(event: FileChangesEvent): void {
|
||||
const events = event.changes;
|
||||
let affectedByChanges = false;
|
||||
|
||||
// Find changes that affect workspace configuration files
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
const resource = events[i].resource;
|
||||
const basename = resources.basename(resource);
|
||||
const isJson = extname(basename) === '.json';
|
||||
const isConfigurationFolderDeleted = (events[i].type === FileChangeType.DELETED && resources.isEqual(resource, this.configurationFolder));
|
||||
|
||||
if (!isJson && !isConfigurationFolderDeleted) {
|
||||
continue; // only JSON files or the actual settings folder
|
||||
}
|
||||
|
||||
const folderRelativePath = this.toFolderRelativePath(resource);
|
||||
if (!folderRelativePath) {
|
||||
continue; // event is not inside folder
|
||||
}
|
||||
|
||||
// Handle case where ".vscode" got deleted
|
||||
if (isConfigurationFolderDeleted) {
|
||||
affectedByChanges = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// only valid workspace config files
|
||||
if (this.configurationResources.some(configurationResource => resources.isEqual(configurationResource, resource))) {
|
||||
affectedByChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (affectedByChanges) {
|
||||
this.changeEventTriggerScheduler.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private toFolderRelativePath(resource: URI): string | undefined {
|
||||
if (resources.isEqualOrParent(resource, this.configurationFolder)) {
|
||||
return resources.relativePath(this.configurationFolder, resource);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class CachedFolderConfiguration extends Disposable implements IFolderConfiguration {
|
||||
|
|
|
@ -28,6 +28,8 @@ export const LAUNCH_CONFIGURATION_KEY = 'launch';
|
|||
export const WORKSPACE_STANDALONE_CONFIGURATIONS = Object.create(null);
|
||||
WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${TASKS_CONFIGURATION_KEY}.json`;
|
||||
WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${LAUNCH_CONFIGURATION_KEY}.json`;
|
||||
export const USER_STANDALONE_CONFIGURATIONS = Object.create(null);
|
||||
USER_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${TASKS_CONFIGURATION_KEY}.json`;
|
||||
|
||||
export type ConfigurationKey = { type: 'user' | 'workspaces' | 'folder', key: string };
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import * as json from 'vs/base/common/json';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { setProperty } from 'vs/base/common/jsonEdit';
|
||||
|
@ -19,7 +20,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 } 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 { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, USER_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
@ -430,8 +431,8 @@ export class ConfigurationEditingService {
|
|||
}
|
||||
|
||||
if (operation.workspaceStandAloneConfigurationKey) {
|
||||
// Global tasks and launches are not supported
|
||||
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
|
||||
// Global launches are not supported
|
||||
if ((operation.workspaceStandAloneConfigurationKey !== TASKS_CONFIGURATION_KEY) && (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE)) {
|
||||
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation);
|
||||
}
|
||||
}
|
||||
|
@ -497,9 +498,10 @@ export class ConfigurationEditingService {
|
|||
|
||||
// Check for standalone workspace configurations
|
||||
if (config.key) {
|
||||
const standaloneConfigurationKeys = Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
const standaloneConfigurationMap = target === EditableConfigurationTarget.USER_LOCAL ? USER_STANDALONE_CONFIGURATIONS : WORKSPACE_STANDALONE_CONFIGURATIONS;
|
||||
const standaloneConfigurationKeys = Object.keys(standaloneConfigurationMap);
|
||||
for (const key of standaloneConfigurationKeys) {
|
||||
const resource = this.getConfigurationFileResource(target, config, WORKSPACE_STANDALONE_CONFIGURATIONS[key], overrides.resource);
|
||||
const resource = this.getConfigurationFileResource(target, config, standaloneConfigurationMap[key], overrides.resource);
|
||||
|
||||
// Check for prefix
|
||||
if (config.key === key) {
|
||||
|
@ -536,7 +538,11 @@ export class ConfigurationEditingService {
|
|||
|
||||
private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null {
|
||||
if (target === EditableConfigurationTarget.USER_LOCAL) {
|
||||
return this.environmentService.settingsResource;
|
||||
if (relativePath) {
|
||||
return resources.joinPath(resources.dirname(this.environmentService.settingsResource), relativePath);
|
||||
} else {
|
||||
return this.environmentService.settingsResource;
|
||||
}
|
||||
}
|
||||
if (target === EditableConfigurationTarget.USER_REMOTE) {
|
||||
return this.remoteSettingsResource;
|
||||
|
|
|
@ -18,7 +18,7 @@ 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 { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
||||
import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH, USER_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/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';
|
||||
|
@ -60,6 +60,7 @@ suite('ConfigurationEditingService', () => {
|
|||
let parentDir: string;
|
||||
let workspaceDir: string;
|
||||
let globalSettingsFile: string;
|
||||
let globalTasksFile: string;
|
||||
let workspaceSettingsDir;
|
||||
|
||||
suiteSetup(() => {
|
||||
|
@ -94,6 +95,7 @@ suite('ConfigurationEditingService', () => {
|
|||
parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
workspaceDir = path.join(parentDir, 'workspaceconfig', id);
|
||||
globalSettingsFile = path.join(workspaceDir, 'settings.json');
|
||||
globalTasksFile = path.join(workspaceDir, 'tasks.json');
|
||||
workspaceSettingsDir = path.join(workspaceDir, '.vscode');
|
||||
|
||||
return await mkdirp(workspaceSettingsDir, 493);
|
||||
|
@ -149,12 +151,6 @@ suite('ConfigurationEditingService', () => {
|
|||
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY));
|
||||
});
|
||||
|
||||
test('errors cases - invalid target', () => {
|
||||
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(EditableConfigurationTarget.WORKSPACE, { key: 'configurationEditing.service.testSetting', value: 'value' }))
|
||||
|
@ -162,11 +158,19 @@ suite('ConfigurationEditingService', () => {
|
|||
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED));
|
||||
});
|
||||
|
||||
test('errors cases - invalid configuration', () => {
|
||||
fs.writeFileSync(globalSettingsFile, ',,,,,,,,,,,,,,');
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' })
|
||||
function errorCasesInvalidConfig(file: string, key: string) {
|
||||
fs.writeFileSync(file, ',,,,,,,,,,,,,,');
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key, value: 'value' })
|
||||
.then(() => assert.fail('Should fail with ERROR_INVALID_CONFIGURATION'),
|
||||
(error: ConfigurationEditingError) => assert.equal(error.code, ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION));
|
||||
}
|
||||
|
||||
test('errors cases - invalid configuration', () => {
|
||||
return errorCasesInvalidConfig(globalSettingsFile, 'configurationEditing.service.testSetting');
|
||||
});
|
||||
|
||||
test('errors cases - invalid global tasks configuration', () => {
|
||||
return errorCasesInvalidConfig(globalTasksFile, 'tasks.configurationEditing.service.testSetting');
|
||||
});
|
||||
|
||||
test('errors cases - dirty', () => {
|
||||
|
@ -271,44 +275,89 @@ suite('ConfigurationEditingService', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('write workspace standalone setting - empty file', () => {
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' })
|
||||
function writeStandaloneSettingEmptyFile(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
return testObject.writeConfiguration(configTarget, { key: 'tasks.service.testSetting', value: 'value' })
|
||||
.then(() => {
|
||||
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
const contents = fs.readFileSync(target).toString('utf8');
|
||||
const parsed = json.parse(contents);
|
||||
assert.equal(parsed['service.testSetting'], 'value');
|
||||
});
|
||||
}
|
||||
|
||||
test('write workspace standalone setting - empty file', () => {
|
||||
return writeStandaloneSettingEmptyFile(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write workspace standalone setting - existing file', () => {
|
||||
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['launch']);
|
||||
test('write user standalone setting - empty file', () => {
|
||||
return writeStandaloneSettingEmptyFile(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
function writeStandaloneSettingExitingFile(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }');
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'launch.service.testSetting', value: 'value' })
|
||||
return testObject.writeConfiguration(configTarget, { key: 'tasks.service.testSetting', value: 'value' })
|
||||
.then(() => {
|
||||
const contents = fs.readFileSync(target).toString('utf8');
|
||||
const parsed = json.parse(contents);
|
||||
assert.equal(parsed['service.testSetting'], 'value');
|
||||
assert.equal(parsed['my.super.setting'], 'my.super.value');
|
||||
});
|
||||
}
|
||||
|
||||
test('write workspace standalone setting - existing file', () => {
|
||||
return writeStandaloneSettingExitingFile(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write user standalone setting - existing file', () => {
|
||||
return writeStandaloneSettingExitingFile(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
function writeStandaloneSettingEmptyFileFullJson(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
return testObject.writeConfiguration(configTarget, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
|
||||
.then(() => {
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
const contents = fs.readFileSync(target).toString('utf8');
|
||||
const parsed = json.parse(contents);
|
||||
|
||||
assert.equal(parsed['version'], '1.0.0');
|
||||
assert.equal(parsed['tasks'][0]['taskName'], 'myTask');
|
||||
});
|
||||
}
|
||||
|
||||
test('write workspace standalone setting - empty file - full JSON', () => {
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
|
||||
return writeStandaloneSettingEmptyFileFullJson(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write user standalone setting - empty file - full JSON', () => {
|
||||
return writeStandaloneSettingEmptyFileFullJson(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
function writeStandaloneSettingExistingFileFullJson(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
fs.writeFileSync(target, '{ "my.super.setting": "my.super.value" }');
|
||||
return testObject.writeConfiguration(configTarget, { 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);
|
||||
|
||||
assert.equal(parsed['version'], '1.0.0');
|
||||
assert.equal(parsed['tasks'][0]['taskName'], 'myTask');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
|
||||
return writeStandaloneSettingExistingFileFullJson(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write user standalone setting - existing file - full JSON', () => {
|
||||
return writeStandaloneSettingExistingFileFullJson(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
function writeStandaloneSettingExistingFileWithJsonErrorFullJson(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
fs.writeFileSync(target, '{ "my.super.setting": '); // invalid JSON
|
||||
return testObject.writeConfiguration(configTarget, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] } })
|
||||
.then(() => {
|
||||
const contents = fs.readFileSync(target).toString('utf8');
|
||||
const parsed = json.parse(contents);
|
||||
|
@ -316,23 +365,18 @@ suite('ConfigurationEditingService', () => {
|
|||
assert.equal(parsed['version'], '1.0.0');
|
||||
assert.equal(parsed['tasks'][0]['taskName'], 'myTask');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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(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);
|
||||
|
||||
assert.equal(parsed['version'], '1.0.0');
|
||||
assert.equal(parsed['tasks'][0]['taskName'], 'myTask');
|
||||
});
|
||||
return writeStandaloneSettingExistingFileWithJsonErrorFullJson(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write workspace standalone setting should replace complete file', () => {
|
||||
const target = path.join(workspaceDir, WORKSPACE_STANDALONE_CONFIGURATIONS['tasks']);
|
||||
test('write user standalone setting - existing file with JSON errors - full JSON', () => {
|
||||
return writeStandaloneSettingExistingFileWithJsonErrorFullJson(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
function writeStandaloneSettingShouldReplace(configTarget: EditableConfigurationTarget, pathMap: any) {
|
||||
const target = path.join(workspaceDir, pathMap['tasks']);
|
||||
fs.writeFileSync(target, `{
|
||||
"version": "1.0.0",
|
||||
"tasks": [
|
||||
|
@ -344,11 +388,19 @@ suite('ConfigurationEditingService', () => {
|
|||
}
|
||||
]
|
||||
}`);
|
||||
return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks', value: { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask1' }] } })
|
||||
return testObject.writeConfiguration(configTarget, { 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);
|
||||
});
|
||||
}
|
||||
|
||||
test('write workspace standalone setting should replace complete file', () => {
|
||||
return writeStandaloneSettingShouldReplace(EditableConfigurationTarget.WORKSPACE, WORKSPACE_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
|
||||
test('write user standalone setting should replace complete file', () => {
|
||||
return writeStandaloneSettingShouldReplace(EditableConfigurationTarget.USER_LOCAL, USER_STANDALONE_CONFIGURATIONS);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -47,6 +47,7 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file
|
|||
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||
import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
class TestEnvironmentService extends NativeWorkbenchEnvironmentService {
|
||||
|
||||
|
@ -717,7 +718,7 @@ suite('WorkspaceService - Initialization', () => {
|
|||
|
||||
suite('WorkspaceConfigurationService - Folder', () => {
|
||||
|
||||
let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: IConfigurationService, globalSettingsFile: string;
|
||||
let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: IConfigurationService, globalSettingsFile: string, globalTasksFile: string;
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
|
||||
suiteSetup(() => {
|
||||
|
@ -756,6 +757,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
|
|||
parentResource = parentDir;
|
||||
workspaceDir = folderDir;
|
||||
globalSettingsFile = path.join(parentDir, 'settings.json');
|
||||
globalTasksFile = path.join(parentDir, 'tasks.json');
|
||||
|
||||
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
|
||||
const environmentService = new TestEnvironmentService(URI.file(parentDir));
|
||||
|
@ -1074,6 +1076,17 @@ suite('WorkspaceConfigurationService - Folder', () => {
|
|||
.then(() => assert.ok(target.called));
|
||||
});
|
||||
|
||||
test('no change event when there are no global tasks', async () => {
|
||||
const target = sinon.spy();
|
||||
testObject.onDidChangeConfiguration(target);
|
||||
await timeout(500);
|
||||
assert.ok(target.notCalled);
|
||||
});
|
||||
|
||||
test('change event when there are global tasks', () => {
|
||||
fs.writeFileSync(globalTasksFile, '{ "version": "1.0.0", "tasks": [{ "taskName": "myTask" }');
|
||||
return new Promise((c) => testObject.onDidChangeConfiguration(() => c()));
|
||||
});
|
||||
});
|
||||
|
||||
suite('WorkspaceConfigurationService-Multiroot', () => {
|
||||
|
@ -1430,7 +1443,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('inspect tasks configuration', () => {
|
||||
test('inspect tasks configuration', async () => {
|
||||
const expectedTasksConfiguration = {
|
||||
'version': '2.0.0',
|
||||
'tasks': [
|
||||
|
@ -1445,12 +1458,10 @@ suite('WorkspaceConfigurationService-Multiroot', () => {
|
|||
}
|
||||
]
|
||||
};
|
||||
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: expectedTasksConfiguration }], true)
|
||||
.then(() => testObject.reloadConfiguration())
|
||||
.then(() => {
|
||||
const actual = testObject.inspect('tasks').workspaceValue;
|
||||
assert.deepEqual(actual, expectedTasksConfiguration);
|
||||
});
|
||||
await jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: expectedTasksConfiguration }], true);
|
||||
await testObject.reloadConfiguration();
|
||||
const actual = testObject.inspect('tasks').workspaceValue;
|
||||
assert.deepEqual(actual, expectedTasksConfiguration);
|
||||
});
|
||||
|
||||
test('update user configuration', () => {
|
||||
|
|
Loading…
Reference in a new issue