Merge VS Code 1.21 source code (#1067)

* Initial VS Code 1.21 file copy with patches

* A few more merges

* Post npm install

* Fix batch of build breaks

* Fix more build breaks

* Fix more build errors

* Fix more build breaks

* Runtime fixes 1

* Get connection dialog working with some todos

* Fix a few packaging issues

* Copy several node_modules to package build to fix loader issues

* Fix breaks from master

* A few more fixes

* Make tests pass

* First pass of license header updates

* Second pass of license header updates

* Fix restore dialog issues

* Remove add additional themes menu items

* fix select box issues where the list doesn't show up

* formatting

* Fix editor dispose issue

* Copy over node modules to correct location on all platforms
This commit is contained in:
Karl Burtram
2018-04-04 15:27:51 -07:00
committed by GitHub
parent 5fba3e31b4
commit dafb780987
9412 changed files with 141255 additions and 98813 deletions

View File

@@ -16,7 +16,7 @@ import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files
import { isLinux } from 'vs/base/common/platform';
import { ConfigWatcher } from 'vs/base/node/config';
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser, WorkspaceSettingsModel } from 'vs/workbench/services/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser } 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';
@@ -82,6 +82,9 @@ export class WorkspaceConfiguration extends Disposable {
private _onDidUpdateConfiguration: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidUpdateConfiguration: Event<void> = this._onDidUpdateConfiguration.event;
private _workspaceConfigurationModelParser: WorkspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(this._workspaceConfigPath ? this._workspaceConfigPath.fsPath : '');
private _cache: ConfigurationModel = new ConfigurationModel();
load(workspaceConfigPath: URI): TPromise<void> {
if (this._workspaceConfigPath && this._workspaceConfigPath.fsPath === workspaceConfigPath.fsPath) {
return this.reload();
@@ -89,29 +92,28 @@ export class WorkspaceConfiguration extends Disposable {
this._workspaceConfigPath = workspaceConfigPath;
this.stopListeningToWatcher();
return new TPromise<void>((c, e) => {
const defaultConfig = new WorkspaceConfigurationModelParser(this._workspaceConfigPath.fsPath);
defaultConfig.parse(JSON.stringify({ folders: [] } as IStoredWorkspace, null, '\t'));
if (this._workspaceConfigurationWatcher) {
this.disposeConfigurationWatcher();
}
this._workspaceConfigurationWatcher = new ConfigWatcher(this._workspaceConfigPath.fsPath, {
changeBufferDelay: 300,
onError: error => errors.onUnexpectedError(error),
defaultConfig,
parse: (content: string, parseErrors: any[]) => {
const workspaceConfigurationModel = new WorkspaceConfigurationModelParser(this._workspaceConfigPath.fsPath);
workspaceConfigurationModel.parse(content);
parseErrors = [...workspaceConfigurationModel.errors];
return workspaceConfigurationModel;
this._workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(this._workspaceConfigPath.fsPath);
this._workspaceConfigurationModelParser.parse(content);
parseErrors = [...this._workspaceConfigurationModelParser.errors];
this.consolidate();
return this._workspaceConfigurationModelParser;
}, initCallback: () => c(null)
});
this.listenToWatcher();
});
}
private get workspaceConfigurationModelParser(): WorkspaceConfigurationModelParser {
return this._workspaceConfigurationWatcher ? this._workspaceConfigurationWatcher.getConfig() : new WorkspaceConfigurationModelParser(this._workspaceConfigPath ? this._workspaceConfigPath.fsPath : '');
}
reload(): TPromise<void> {
this.stopListeningToWatcher();
return new TPromise<void>(c => this._workspaceConfigurationWatcher.reload(() => {
@@ -121,7 +123,7 @@ export class WorkspaceConfiguration extends Disposable {
}
getFolders(): IStoredWorkspaceFolder[] {
return this.workspaceConfigurationModelParser.folders;
return this._workspaceConfigurationModelParser.folders;
}
setFolders(folders: IStoredWorkspaceFolder[], jsonEditingService: JSONEditingService): TPromise<void> {
@@ -130,20 +132,20 @@ export class WorkspaceConfiguration extends Disposable {
}
getConfiguration(): ConfigurationModel {
return this.workspaceConfigurationModelParser.workspaceSettingsModel;
return this._cache;
}
getWorkspaceSettings(): WorkspaceSettingsModel {
return this.workspaceConfigurationModelParser.workspaceSettingsModel;
getUnsupportedKeys(): string[] {
return this._workspaceConfigurationModelParser.settingsModel.unsupportedKeys;
}
reprocessWorkspaceSettings(): ConfigurationModel {
this.workspaceConfigurationModelParser.reprocessWorkspaceSettings();
this._workspaceConfigurationModelParser.reprocessWorkspaceSettings();
this.consolidate();
return this.getConfiguration();
}
private listenToWatcher() {
this._workspaceConfigurationWatcherDisposables.push(this._workspaceConfigurationWatcher);
this._workspaceConfigurationWatcher.onDidUpdateConfiguration(() => this._onDidUpdateConfiguration.fire(), this, this._workspaceConfigurationWatcherDisposables);
}
@@ -151,8 +153,19 @@ export class WorkspaceConfiguration extends Disposable {
this._workspaceConfigurationWatcherDisposables = dispose(this._workspaceConfigurationWatcherDisposables);
}
private consolidate(): void {
this._cache = this._workspaceConfigurationModelParser.settingsModel.merge(this._workspaceConfigurationModelParser.launchModel);
}
private disposeConfigurationWatcher(): void {
this.stopListeningToWatcher();
if (this._workspaceConfigurationWatcher) {
this._workspaceConfigurationWatcher.dispose();
}
}
dispose(): void {
dispose(this._workspaceConfigurationWatcherDisposables);
this.disposeConfigurationWatcher();
super.dispose();
}
}
@@ -190,20 +203,20 @@ export class FolderConfiguration extends Disposable {
}
reprocess(): ConfigurationModel {
const oldContents = this._folderSettingsModelParser.folderSettingsModel.contents;
const oldContents = this._folderSettingsModelParser.settingsModel.contents;
this._folderSettingsModelParser.reprocess();
if (!equals(oldContents, this._folderSettingsModelParser.folderSettingsModel.contents)) {
if (!equals(oldContents, this._folderSettingsModelParser.settingsModel.contents)) {
this.consolidate();
}
return this._cache;
}
getUnsupportedKeys(): string[] {
return this._folderSettingsModelParser.folderSettingsModel.unsupportedKeys;
return this._folderSettingsModelParser.settingsModel.unsupportedKeys;
}
private consolidate(): void {
this._cache = this._folderSettingsModelParser.folderSettingsModel.merge(...this._standAloneConfigurations);
this._cache = this._folderSettingsModelParser.settingsModel.merge(...this._standAloneConfigurations);
}
private loadWorkspaceConfigFiles(): TPromise<{ [relativeWorkspacePath: string]: ConfigurationModelParser }> {

View File

@@ -5,17 +5,16 @@
'use strict';
import nls = require('vs/nls');
import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import * as json from 'vs/base/common/json';
import * as encoding from 'vs/base/node/encoding';
import strings = require('vs/base/common/strings');
import * as strings from 'vs/base/common/strings';
import { setProperty } from 'vs/base/common/jsonEdit';
import { Queue } from 'vs/base/common/async';
import { Edit } from 'vs/base/common/jsonFormatter';
import { IReference } from 'vs/base/common/lifecycle';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Registry } from 'vs/platform/registry/common/platform';
import { Range } from 'vs/editor/common/core/range';
@@ -28,9 +27,11 @@ import { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIG
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';
import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITextModel } from 'vs/editor/common/model';
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
export enum ConfigurationEditingErrorCode {
@@ -127,7 +128,7 @@ export class ConfigurationEditingService {
@ITextModelService private textModelResolverService: ITextModelService,
@ITextFileService private textFileService: ITextFileService,
@IChoiceService private choiceService: IChoiceService,
@IMessageService private messageService: IMessageService,
@INotificationService private notificationService: INotificationService,
@ICommandService private commandService: ICommandService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
@@ -154,7 +155,7 @@ export class ConfigurationEditingService {
.then(() => reference.dispose()));
}
private writeToBuffer(model: editorCommon.IModel, operation: IConfigurationEditOperation, save: boolean): TPromise<any> {
private writeToBuffer(model: ITextModel, operation: IConfigurationEditOperation, save: boolean): TPromise<any> {
const edit = this.getEdits(model, operation)[0];
if (edit && this.applyEditsToBuffer(edit, model) && save) {
return this.textFileService.save(operation.resource, { skipSaveParticipants: true /* programmatic change */ });
@@ -162,7 +163,7 @@ export class ConfigurationEditingService {
return TPromise.as(null);
}
private applyEditsToBuffer(edit: Edit, model: editorCommon.IModel): boolean {
private applyEditsToBuffer(edit: Edit, model: ITextModel): boolean {
const startPosition = model.getPositionAt(edit.offset);
const endPosition = model.getPositionAt(edit.offset + edit.length);
const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
@@ -184,7 +185,7 @@ export class ConfigurationEditingService {
this.onConfigurationFileDirtyError(error, operation, scopes);
break;
default:
this.messageService.show(Severity.Error, error.message);
this.notificationService.error(error.message);
}
}
@@ -193,21 +194,17 @@ export class ConfigurationEditingService {
: operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration")
: null;
if (openStandAloneConfigurationActionLabel) {
this.choiceService.choose(Severity.Error, error.message, [openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 1)
this.choiceService.choose(Severity.Error, error.message, [openStandAloneConfigurationActionLabel])
.then(option => {
switch (option) {
case 0:
this.openFile(operation.resource);
break;
if (option === 0) {
this.openFile(operation.resource);
}
});
} else {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 1)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('open', "Open Settings")])
.then(option => {
switch (option) {
case 0:
this.openSettings(operation);
break;
if (option === 0) {
this.openSettings(operation);
}
});
}
@@ -218,26 +215,26 @@ export class ConfigurationEditingService {
: operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration")
: null;
if (openStandAloneConfigurationActionLabel) {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), openStandAloneConfigurationActionLabel, nls.localize('close', "Close")], 2)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), openStandAloneConfigurationActionLabel])
.then(option => {
switch (option) {
case 0:
case 0 /* Save & Retry */:
const key = operation.key ? `${operation.workspaceStandAloneConfigurationKey}.${operation.key}` : operation.workspaceStandAloneConfigurationKey;
this.writeConfiguration(operation.target, { key, value: operation.value }, <ConfigurationEditingOptions>{ force: true, scopes });
break;
case 1:
case 1 /* Open Config */:
this.openFile(operation.resource);
break;
}
});
} else {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 2)
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save and Retry"), nls.localize('open', "Open Settings")])
.then(option => {
switch (option) {
case 0:
case 0 /* Save and Retry */:
this.writeConfiguration(operation.target, { key: operation.key, value: operation.value }, <ConfigurationEditingOptions>{ force: true, scopes });
break;
case 1:
case 1 /* Open Settings */:
this.openSettings(operation);
break;
}
@@ -288,37 +285,37 @@ export class ConfigurationEditingService {
// User issues
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return nls.localize('errorInvalidTaskConfiguration', "Unable to write into tasks file. Please open **Tasks** file to correct errors/warnings in it and try again.");
return nls.localize('errorInvalidTaskConfiguration', "Unable to write into the tasks configuration file. Please open it to correct errors/warnings in it and try again.");
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return nls.localize('errorInvalidLaunchConfiguration', "Unable to write into launch file. Please open **Launch** file to correct errors/warnings in it and try again.");
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:
return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open **User Settings** file to correct errors/warnings in it and try again.");
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:
return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open **Workspace Settings** file to correct errors/warnings in the file and try again.");
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:
const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name;
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 nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open the '{0}' folder settings 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.");
return nls.localize('errorTasksConfigurationFileDirty', "Unable to write into tasks configuration file because the file is dirty. Please save it first and then try again.");
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch file because the file is dirty. Please save the **Launch Configuration** file and try again.");
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:
return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the **User Settings** file and try again.");
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:
return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the **Workspace Settings** file and try again.");
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:
const workspaceFolderName = this.contextService.getWorkspaceFolder(operation.resource).name;
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 nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the '{0}' folder settings file first and then try again.", workspaceFolderName);
}
return '';
}
@@ -337,7 +334,7 @@ export class ConfigurationEditingService {
return '';
}
private getEdits(model: editorCommon.IModel, edit: IConfigurationEditOperation): Edit[] {
private getEdits(model: ITextModel, edit: IConfigurationEditOperation): Edit[] {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
const { value, jsonPath } = edit;
@@ -363,7 +360,7 @@ export class ConfigurationEditingService {
});
}
private hasParseErrors(model: editorCommon.IModel, operation: IConfigurationEditOperation): boolean {
private hasParseErrors(model: ITextModel, operation: IConfigurationEditOperation): boolean {
// If we write to a workspace standalone file and replace the entire contents (no key provided)
// we can return here because any parse errors can safely be ignored since all contents are replaced
if (operation.workspaceStandAloneConfigurationKey && !operation.key) {
@@ -390,8 +387,8 @@ export class ConfigurationEditingService {
return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation);
}
// Workspace tasks and launches are not supported
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === ConfigurationTarget.WORKSPACE) {
// Workspace tasks are not supported
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === ConfigurationTarget.WORKSPACE) {
return this.wrapError(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation);
}
}
@@ -432,8 +429,6 @@ export class ConfigurationEditingService {
private getConfigurationEditOperation(target: ConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation {
const workspace = this.contextService.getWorkspace();
// Check for standalone workspace configurations
if (config.key) {
const standaloneConfigurationKeys = Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS);
@@ -443,14 +438,14 @@ export class ConfigurationEditingService {
// Check for prefix
if (config.key === key) {
const jsonPath = workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key] : [];
const jsonPath = this.isWorkspaceConfigurationResource(resource) ? [key] : [];
return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, workspaceStandAloneConfigurationKey: key, target };
}
// Check for prefix.<setting>
const keyPrefix = `${key}.`;
if (config.key.indexOf(keyPrefix) === 0) {
const jsonPath = workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath ? [key, config.key.substr(keyPrefix.length)] : [config.key.substr(keyPrefix.length)];
const jsonPath = this.isWorkspaceConfigurationResource(resource) ? [key, config.key.substr(keyPrefix.length)] : [config.key.substr(keyPrefix.length)];
return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource, workspaceStandAloneConfigurationKey: key, target };
}
}
@@ -463,12 +458,17 @@ export class ConfigurationEditingService {
}
const resource = this.getConfigurationFileResource(target, FOLDER_SETTINGS_PATH, overrides.resource);
if (workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath) {
if (this.isWorkspaceConfigurationResource(resource)) {
jsonPath = ['settings', ...jsonPath];
}
return { key, jsonPath, value: config.value, resource, target };
}
private isWorkspaceConfigurationResource(resource: URI): boolean {
const workspace = this.contextService.getWorkspace();
return workspace.configuration && resource && workspace.configuration.fsPath === resource.fsPath;
}
private getConfigurationFileResource(target: ConfigurationTarget, relativePath: string, resource: URI): URI {
if (target === ConfigurationTarget.USER) {
return URI.file(this.environmentService.appSettingsPath);

View File

@@ -5,9 +5,8 @@
'use strict';
import URI from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import { TPromise } from 'vs/base/common/winjs.base';
import { dirname } from 'path';
import { dirname, basename } from 'path';
import * as assert from 'vs/base/common/assert';
import Event, { Emitter } from 'vs/base/common/event';
import { StrictResourceMap } from 'vs/base/common/map';
@@ -16,7 +15,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { Queue } from 'vs/base/common/async';
import { stat, writeFile } from 'vs/base/node/pfs';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { FileChangesEvent } from 'vs/platform/files/common/files';
import { isLinux } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -29,7 +28,7 @@ import { IConfigurationNode, IConfigurationRegistry, Extensions, settingsSchema,
import { createHash } from 'crypto';
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 { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import product from 'vs/platform/node/product';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -110,14 +109,17 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return this.workspace.getFolder(resource);
}
public addFolders(foldersToAdd: IWorkspaceFolderCreationData[]): TPromise<void> {
assert.ok(this.jsonEditingService, 'Workbench is not initialized yet');
return this.workspaceEditingQueue.queue(() => this.doAddFolders(foldersToAdd));
public addFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number): TPromise<void> {
return this.updateFolders(foldersToAdd, [], index);
}
public removeFolders(foldersToRemove: URI[]): TPromise<void> {
return this.updateFolders([], foldersToRemove);
}
public updateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToRemove: URI[], index?: number): TPromise<void> {
assert.ok(this.jsonEditingService, 'Workbench is not initialized yet');
return this.workspaceEditingQueue.queue(() => this.doRemoveFolders(foldersToRemove));
return this.workspaceEditingQueue.queue(() => this.doUpdateFolders(foldersToAdd, foldersToRemove, index));
}
public isInsideWorkspace(resource: URI): boolean {
@@ -134,63 +136,20 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return false;
}
private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[]): TPromise<void> {
private doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToRemove: URI[], index?: number): TPromise<void> {
if (this.getWorkbenchState() !== WorkbenchState.WORKSPACE) {
return TPromise.as(void 0); // we need a workspace to begin with
}
const currentWorkspaceFolders = this.getWorkspace().folders;
const currentWorkspaceFolderUris = currentWorkspaceFolders.map(folder => folder.uri);
const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw);
const storedFoldersToAdd: IStoredWorkspaceFolder[] = [];
const workspaceConfigFolder = dirname(this.getWorkspace().configuration.fsPath);
foldersToAdd.forEach(folderToAdd => {
if (this.contains(currentWorkspaceFolderUris, folderToAdd.uri)) {
return; // already existing
}
let storedFolder: IStoredWorkspaceFolder;
// File resource: use "path" property
if (folderToAdd.uri.scheme === Schemas.file) {
storedFolder = {
path: massageFolderPathForWorkspace(folderToAdd.uri.fsPath, workspaceConfigFolder, currentStoredFolders)
};
}
// Any other resource: use "uri" property
else {
storedFolder = {
uri: folderToAdd.uri.toString(true)
};
}
if (folderToAdd.name) {
storedFolder.name = folderToAdd.name;
}
storedFoldersToAdd.push(storedFolder);
});
if (storedFoldersToAdd.length > 0) {
return this.setFolders([...currentStoredFolders, ...storedFoldersToAdd]);
if (foldersToAdd.length + foldersToRemove.length === 0) {
return TPromise.as(void 0); // nothing to do
}
return TPromise.as(void 0);
}
let foldersHaveChanged = false;
private doRemoveFolders(foldersToRemove: URI[]): TPromise<void> {
if (this.getWorkbenchState() !== WorkbenchState.WORKSPACE) {
return TPromise.as(void 0); // we need a workspace to begin with
}
const currentWorkspaceFolders = this.getWorkspace().folders;
const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw);
const newStoredFolders: IStoredWorkspaceFolder[] = currentStoredFolders.filter((folder, index) => {
// Remove first (if any)
let currentWorkspaceFolders = this.getWorkspace().folders;
let newStoredFolders: IStoredWorkspaceFolder[] = currentWorkspaceFolders.map(f => f.raw).filter((folder, index) => {
if (!isStoredWorkspaceFolder(folder)) {
return true; // keep entries which are unrelated
}
@@ -198,7 +157,61 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
return !this.contains(foldersToRemove, currentWorkspaceFolders[index].uri); // keep entries which are unrelated
});
if (newStoredFolders.length !== currentStoredFolders.length) {
foldersHaveChanged = currentWorkspaceFolders.length !== newStoredFolders.length;
// Add afterwards (if any)
if (foldersToAdd.length) {
// Recompute current workspace folders if we have folders to add
const workspaceConfigFolder = dirname(this.getWorkspace().configuration.fsPath);
currentWorkspaceFolders = toWorkspaceFolders(newStoredFolders, URI.file(workspaceConfigFolder));
const currentWorkspaceFolderUris = currentWorkspaceFolders.map(folder => folder.uri);
const storedFoldersToAdd: IStoredWorkspaceFolder[] = [];
foldersToAdd.forEach(folderToAdd => {
if (this.contains(currentWorkspaceFolderUris, folderToAdd.uri)) {
return; // already existing
}
let storedFolder: IStoredWorkspaceFolder;
// File resource: use "path" property
if (folderToAdd.uri.scheme === Schemas.file) {
storedFolder = {
path: massageFolderPathForWorkspace(folderToAdd.uri.fsPath, workspaceConfigFolder, newStoredFolders)
};
}
// Any other resource: use "uri" property
else {
storedFolder = {
uri: folderToAdd.uri.toString(true)
};
}
if (folderToAdd.name) {
storedFolder.name = folderToAdd.name;
}
storedFoldersToAdd.push(storedFolder);
});
// Apply to array of newStoredFolders
if (storedFoldersToAdd.length > 0) {
foldersHaveChanged = true;
if (typeof index === 'number' && index >= 0 && index < newStoredFolders.length) {
newStoredFolders = newStoredFolders.slice(0);
newStoredFolders.splice(index, 0, ...storedFoldersToAdd);
} else {
newStoredFolders = [...newStoredFolders, ...storedFoldersToAdd];
}
}
}
// Set folders if we recorded a change
if (foldersHaveChanged) {
return this.setFolders(newStoredFolders);
}
@@ -279,7 +292,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
getUnsupportedWorkspaceKeys(): string[] {
const unsupportedWorkspaceKeys = [...this.workspaceConfiguration.getWorkspaceSettings().unsupportedKeys];
const unsupportedWorkspaceKeys = [...this.workspaceConfiguration.getUnsupportedKeys()];
for (const folder of this.workspace.folders) {
unsupportedWorkspaceKeys.push(...this.cachedFolderConfigs.get(folder.uri).getUnsupportedKeys());
}
@@ -322,7 +335,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
const workspaceConfigPath = URI.file(workspaceIdentifier.configPath);
return this.workspaceConfiguration.load(workspaceConfigPath)
.then(() => {
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(paths.dirname(workspaceConfigPath.fsPath)));
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(dirname(workspaceConfigPath.fsPath)));
const workspaceId = workspaceIdentifier.id;
const workspaceName = getWorkspaceLabel({ id: workspaceId, configPath: workspaceConfigPath.fsPath }, this.environmentService);
return new Workspace(workspaceId, workspaceName, workspaceFolders, workspaceConfigPath);
@@ -341,15 +354,15 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
private createEmptyWorkspace(configuration: IWindowConfiguration): TPromise<Workspace> {
let id = configuration.backupPath ? URI.from({ path: paths.basename(configuration.backupPath), scheme: 'empty' }).toString() : '';
let id = configuration.backupPath ? URI.from({ path: basename(configuration.backupPath), scheme: 'empty' }).toString() : '';
return TPromise.as(new Workspace(id));
}
private updateWorkspaceAndInitializeConfiguration(workspace: Workspace): TPromise<void> {
const hasWorkspaceBefore = !!this.workspace;
let previousState;
let previousWorkspacePath;
let previousFolders;
let previousState: WorkbenchState;
let previousWorkspacePath: string;
let previousFolders: WorkspaceFolder[];
if (hasWorkspaceBefore) {
previousState = this.getWorkbenchState();
@@ -382,7 +395,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
private compareFolders(currentFolders: IWorkspaceFolder[], newFolders: IWorkspaceFolder[]): IWorkspaceFoldersChangeEvent {
const result = { added: [], removed: [], changed: [] };
const result = { added: [], removed: [], changed: [] } as IWorkspaceFoldersChangeEvent;
result.added = newFolders.filter(newFolder => !currentFolders.some(currentFolder => newFolder.uri.toString() === currentFolder.uri.toString()));
for (let currentIndex = 0; currentIndex < currentFolders.length; currentIndex++) {
let currentFolder = currentFolders[currentIndex];
@@ -497,7 +510,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
private onWorkspaceConfigurationChanged(): TPromise<void> {
if (this.workspace && this.workspace.configuration && this._configuration) {
const workspaceConfigurationChangeEvent = this._configuration.compareAndUpdateWorkspaceConfiguration(this.workspaceConfiguration.getConfiguration());
let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(paths.dirname(this.workspace.configuration.fsPath)));
let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), URI.file(dirname(this.workspace.configuration.fsPath)));
const changes = this.compareFolders(this.workspace.folders, configuredFolders);
if (changes.added.length || changes.removed.length || changes.changed.length) {
this.workspace.folders = configuredFolders;

View File

@@ -13,7 +13,6 @@ import { setProperty } from 'vs/base/common/jsonEdit';
import { Queue } from 'vs/base/common/async';
import { Edit } from 'vs/base/common/jsonFormatter';
import { IReference } from 'vs/base/common/lifecycle';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
@@ -21,6 +20,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IJSONEditingService, IJSONValue, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing';
import { ITextModel } from 'vs/editor/common/model';
export class JSONEditingService implements IJSONEditingService {
@@ -46,7 +46,7 @@ export class JSONEditingService implements IJSONEditingService {
.then(() => reference.dispose()));
}
private writeToBuffer(model: editorCommon.IModel, value: IJSONValue): TPromise<any> {
private writeToBuffer(model: ITextModel, value: IJSONValue): TPromise<any> {
const edit = this.getEdits(model, value)[0];
if (this.applyEditsToBuffer(edit, model)) {
return this.textFileService.save(model.uri);
@@ -54,7 +54,7 @@ export class JSONEditingService implements IJSONEditingService {
return TPromise.as(null);
}
private applyEditsToBuffer(edit: Edit, model: editorCommon.IModel): boolean {
private applyEditsToBuffer(edit: Edit, model: ITextModel): boolean {
const startPosition = model.getPositionAt(edit.offset);
const endPosition = model.getPositionAt(edit.offset + edit.length);
const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
@@ -67,7 +67,7 @@ export class JSONEditingService implements IJSONEditingService {
return false;
}
private getEdits(model: editorCommon.IModel, configurationValue: IJSONValue): Edit[] {
private getEdits(model: ITextModel, configurationValue: IJSONValue): Edit[] {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
const { key, value } = configurationValue;
@@ -93,7 +93,7 @@ export class JSONEditingService implements IJSONEditingService {
});
}
private hasParseErrors(model: editorCommon.IModel): boolean {
private hasParseErrors(model: ITextModel): boolean {
const parseErrors: json.ParseError[] = [];
json.parse(model.getValue(), parseErrors, { allowTrailingComma: true });
return parseErrors.length > 0;
@@ -132,4 +132,4 @@ export class JSONEditingService implements IJSONEditingService {
}
}
}
}
}