Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
@@ -18,49 +17,38 @@ export interface IWorkspaceEditingService {
* Add folders to the existing workspace.
* When `donotNotifyError` is `true`, error will be bubbled up otherwise, the service handles the error with proper message and action
*/
addFolders(folders: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): TPromise<void>;
addFolders(folders: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise<void>;
/**
* Remove folders from the existing workspace
* When `donotNotifyError` is `true`, error will be bubbled up otherwise, the service handles the error with proper message and action
*/
removeFolders(folders: URI[], donotNotifyError?: boolean): TPromise<void>;
removeFolders(folders: URI[], donotNotifyError?: boolean): Promise<void>;
/**
* Allows to add and remove folders to the existing workspace at once.
* When `donotNotifyError` is `true`, error will be bubbled up otherwise, the service handles the error with proper message and action
*/
updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): TPromise<void>;
updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise<void>;
/**
* enters the workspace with the provided path.
*/
enterWorkspace(path: string): TPromise<void>;
enterWorkspace(path: URI): Promise<void>;
/**
* creates a new workspace with the provided folders and opens it. if path is provided
* the workspace will be saved into that location.
*/
createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise<void>;
createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise<void>;
/**
* saves the workspace to the provided path and opens it. requires a workspace to be opened.
* saves the current workspace to the provided path and opens it. requires a workspace to be opened.
*/
saveAndEnterWorkspace(path: string): TPromise<void>;
saveAndEnterWorkspace(path: URI): Promise<void>;
/**
* copies current workspace settings to the target workspace.
*/
copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise<void>;
}
export const IWorkspaceMigrationService = createDecorator<IWorkspaceMigrationService>('workspaceMigrationService');
export interface IWorkspaceMigrationService {
/**
* Migrate current workspace to given workspace
*/
migrate(toWokspaceId: IWorkspaceIdentifier): TPromise<void>;
copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise<void>;
}

View File

@@ -6,15 +6,14 @@
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows';
import { IWindowService, MessageBoxOptions, IWindowsService } from 'vs/platform/windows/common/windows';
import { IJSONEditingService, JSONEditingError, JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing';
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, isWorkspaceIdentifier, toWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { DelegatingStorageService } from 'vs/platform/storage/node/storageService';
import { StorageService } from 'vs/platform/storage/node/storageService';
import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -23,27 +22,32 @@ import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileS
import { ICommandService } from 'vs/platform/commands/common/commands';
import { distinct } from 'vs/base/common/arrays';
import { isLinux } from 'vs/base/common/platform';
import { isEqual } from 'vs/base/common/resources';
import { isEqual, basename } from 'vs/base/common/resources';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IFileService } from 'vs/platform/files/common/files';
import { rewriteWorkspaceFileForNewLocation } from 'vs/platform/workspaces/node/workspaces';
export class WorkspaceEditingService implements IWorkspaceEditingService {
_serviceBrand: any;
constructor(
@IJSONEditingService private jsonEditingService: IJSONEditingService,
@IWorkspaceContextService private contextService: WorkspaceService,
@IWindowService private windowService: IWindowService,
@IWorkspaceConfigurationService private workspaceConfigurationService: IWorkspaceConfigurationService,
@IStorageService private storageService: IStorageService,
@IExtensionService private extensionService: IExtensionService,
@IBackupFileService private backupFileService: IBackupFileService,
@INotificationService private notificationService: INotificationService,
@ICommandService private commandService: ICommandService
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
@IWorkspaceContextService private readonly contextService: WorkspaceService,
@IWindowService private readonly windowService: IWindowService,
@IWorkspaceConfigurationService private readonly workspaceConfigurationService: IWorkspaceConfigurationService,
@IStorageService private readonly storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IBackupFileService private readonly backupFileService: IBackupFileService,
@INotificationService private readonly notificationService: INotificationService,
@ICommandService private readonly commandService: ICommandService,
@IFileService private readonly fileSystemService: IFileService,
@IWindowsService private readonly windowsService: IWindowsService,
@IWorkspacesService private readonly workspaceService: IWorkspacesService
) {
}
updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): TPromise<void> {
updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise<void> {
const folders = this.contextService.getWorkspace().folders;
let foldersToDelete: URI[] = [];
@@ -55,7 +59,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
const wantsToAdd = Array.isArray(foldersToAdd) && foldersToAdd.length > 0;
if (!wantsToAdd && !wantsToDelete) {
return TPromise.as(void 0); // return early if there is nothing to do
return Promise.resolve(); // return early if there is nothing to do
}
// Add Folders
@@ -88,16 +92,16 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
}
private doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): TPromise<void> {
private doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): Promise<void> {
return this.contextService.updateFolders(foldersToAdd, foldersToDelete, index)
.then(() => null, error => donotNotifyError ? TPromise.wrapError(error) : this.handleWorkspaceConfigurationEditingError(error));
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
}
addFolders(foldersToAdd: IWorkspaceFolderCreationData[], donotNotifyError: boolean = false): TPromise<void> {
return this.doAddFolders(foldersToAdd, void 0, donotNotifyError);
addFolders(foldersToAdd: IWorkspaceFolderCreationData[], donotNotifyError: boolean = false): Promise<void> {
return this.doAddFolders(foldersToAdd, undefined, donotNotifyError);
}
private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): TPromise<void> {
private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> {
const state = this.contextService.getWorkbenchState();
// If we are in no-workspace or single-folder workspace, adding folders has to
@@ -108,7 +112,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
newWorkspaceFolders = distinct(newWorkspaceFolders, folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase());
if (state === WorkbenchState.EMPTY && newWorkspaceFolders.length === 0 || state === WorkbenchState.FOLDER && newWorkspaceFolders.length === 1) {
return TPromise.as(void 0); // return if the operation is a no-op for the current state
return Promise.resolve(); // return if the operation is a no-op for the current state
}
return this.createAndEnterWorkspace(newWorkspaceFolders);
@@ -116,10 +120,10 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
// Delegate addition of folders to workspace service otherwise
return this.contextService.addFolders(foldersToAdd, index)
.then(() => null, error => donotNotifyError ? TPromise.wrapError(error) : this.handleWorkspaceConfigurationEditingError(error));
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
}
removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): TPromise<void> {
removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): Promise<void> {
// If we are in single-folder state and the opened folder is to be removed,
// we create an empty workspace and enter it.
@@ -129,7 +133,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
// Delegate removal of folders to workspace service otherwise
return this.contextService.removeFolders(foldersToRemove)
.then(() => null, error => donotNotifyError ? TPromise.wrapError(error) : this.handleWorkspaceConfigurationEditingError(error));
.then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error));
}
private includesSingleFolderWorkspace(folders: URI[]): boolean {
@@ -141,30 +145,78 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
return false;
}
enterWorkspace(path: string): TPromise<void> {
return this.doEnterWorkspace(() => this.windowService.enterWorkspace(path));
async createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise<void> {
if (path && !this.isValidTargetWorkspacePath(path)) {
return Promise.reject(null);
}
const untitledWorkspace = await this.workspaceService.createUntitledWorkspace(folders);
if (path) {
await this.saveWorkspaceAs(untitledWorkspace, path);
} else {
path = URI.file(untitledWorkspace.configPath);
}
return this.enterWorkspace(path);
}
createAndEnterWorkspace(folders?: IWorkspaceFolderCreationData[], path?: string): TPromise<void> {
return this.doEnterWorkspace(() => this.windowService.createAndEnterWorkspace(folders, path));
async saveAndEnterWorkspace(path: URI): Promise<void> {
if (!this.isValidTargetWorkspacePath(path)) {
return Promise.reject(null);
}
const currentWorkspaceIdentifier = toWorkspaceIdentifier(this.contextService.getWorkspace());
if (!isWorkspaceIdentifier(currentWorkspaceIdentifier)) {
return Promise.reject(null);
}
await this.saveWorkspaceAs(currentWorkspaceIdentifier, path);
return this.enterWorkspace(path);
}
saveAndEnterWorkspace(path: string): TPromise<void> {
return this.doEnterWorkspace(() => this.windowService.saveAndEnterWorkspace(path));
async isValidTargetWorkspacePath(path: URI): Promise<boolean> {
const windows = await this.windowsService.getWindows();
// Prevent overwriting a workspace that is currently opened in another window
if (windows.some(window => window.workspace && isEqual(URI.file(window.workspace.configPath), path))) {
const options: MessageBoxOptions = {
type: 'info',
buttons: [nls.localize('ok', "OK")],
message: nls.localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)),
detail: nls.localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
noLink: true
};
return this.windowService.showMessageBox(options).then(() => false);
}
return Promise.resolve(true); // OK
}
private handleWorkspaceConfigurationEditingError(error: JSONEditingError): TPromise<void> {
private async saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPathURI: URI): Promise<any> {
const configPathURI = URI.file(workspace.configPath);
// Return early if target is same as source
if (isEqual(configPathURI, targetConfigPathURI)) {
return Promise.resolve(null);
}
// Read the contents of the workspace file, update it to new location and save it.
const raw = await this.fileSystemService.resolveContent(configPathURI);
const newRawWorkspaceContents = rewriteWorkspaceFileForNewLocation(raw.value, configPathURI, targetConfigPathURI);
await this.fileSystemService.createFile(targetConfigPathURI, newRawWorkspaceContents, { overwrite: true });
}
private handleWorkspaceConfigurationEditingError(error: JSONEditingError): Promise<void> {
switch (error.code) {
case JSONEditingErrorCode.ERROR_INVALID_FILE:
this.onInvalidWorkspaceConfigurationFileError();
return TPromise.as(void 0);
return Promise.resolve();
case JSONEditingErrorCode.ERROR_FILE_DIRTY:
this.onWorkspaceConfigurationFileDirtyError();
return TPromise.as(void 0);
return Promise.resolve();
}
this.notificationService.error(error.message);
return TPromise.as(void 0);
return Promise.resolve();
}
private onInvalidWorkspaceConfigurationFileError(): void {
@@ -186,7 +238,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
);
}
private doEnterWorkspace(mainSidePromise: () => TPromise<IEnterWorkspaceResult>): TPromise<void> {
enterWorkspace(path: URI): Promise<void> {
// Stop the extension host first to give extensions most time to shutdown
this.extensionService.stopExtensionHost();
@@ -197,7 +249,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
extensionHostStarted = true;
};
return mainSidePromise().then(result => {
return this.windowService.enterWorkspace(path).then(result => {
// Migrate storage and settings if we are to enter a workspace
if (result) {
@@ -214,17 +266,17 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
});
}
return TPromise.as(void 0);
}).then(null, error => {
return Promise.resolve();
}).then(undefined, error => {
if (!extensionHostStarted) {
startExtensionHost(); // start the extension host if not started
}
return TPromise.wrapError(error);
return Promise.reject(error);
});
}
private migrate(toWorkspace: IWorkspaceIdentifier): Thenable<void> {
private migrate(toWorkspace: IWorkspaceIdentifier): Promise<void> {
// Storage migration
return this.migrateStorage(toWorkspace).then(() => {
@@ -234,25 +286,25 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
return this.migrateWorkspaceSettings(toWorkspace);
}
return void 0;
return undefined;
});
}
private migrateStorage(toWorkspace: IWorkspaceIdentifier): Thenable<void> {
const storageImpl = this.storageService as DelegatingStorageService;
private migrateStorage(toWorkspace: IWorkspaceIdentifier): Promise<void> {
const storageImpl = this.storageService as StorageService;
return storageImpl.storage.migrate(toWorkspace);
return storageImpl.migrate(toWorkspace);
}
private migrateWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise<void> {
private migrateWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise<void> {
return this.doCopyWorkspaceSettings(toWorkspace, setting => setting.scope === ConfigurationScope.WINDOW);
}
copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise<void> {
copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise<void> {
return this.doCopyWorkspaceSettings(toWorkspace);
}
private doCopyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier, filter?: (config: IConfigurationPropertySchema) => boolean): TPromise<void> {
private doCopyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier, filter?: (config: IConfigurationPropertySchema) => boolean): Promise<void> {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
const targetWorkspaceConfiguration = {};
for (const key of this.workspaceConfigurationService.keys().workspace) {