diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index a10d1da0d55..3abc6a2361b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -164,7 +164,7 @@ declare module 'vscode' { * * **Example:** adding a new workspace folder at the end of workspace folders * ```typescript - * workspace.updateWorkspaceFolders(workspace.workspaceFolders ? workspace.workspaceFolders.length : 0, null, [{ uri: ...}]); + * workspace.updateWorkspaceFolders(workspace.workspaceFolders ? workspace.workspaceFolders.length : 0, null, { uri: ...}); * ``` * * **Example:** removing the first workspace folder @@ -174,7 +174,7 @@ declare module 'vscode' { * * **Example:** replacing an existing workspace folder with a new one * ```typescript - * workspace.updateWorkspaceFolders(0, 1, [{ uri: ...}]); + * workspace.updateWorkspaceFolders(0, 1, { uri: ...}); * ``` * * It is valid to remove an existing workspace folder and add it again with a different name @@ -183,16 +183,14 @@ declare module 'vscode' { * Note: if the first workspace folder is added, removed or changed, all extensions will be restarted * so that the (deprecated) `rootPath` property is updated to point to the first workspace * folder. - * - * @param index the zero-based index in the list of currently opened [workspace folders](#WorkspaceFolder) - * from where to delete workspace folders or from where to add to. - * @param deleteCount the optional number of workspace folders to delete from the index that is provided. - * @param workspaceFoldersToAdd the optional set of workspace folders to add at the index that is provided. + * @param start the zero-based location in the list of currently opened [workspace folders](#WorkspaceFolder) + * from which to start deleting workspace folders. + * @param deleteCount the optional number of workspace folders to remove. + * @param workspaceFoldersToAdd the optional variable set of workspace folders to add in place of the deleted ones. * Each workspace is identified with a mandatory URI and an optional name. - * @return A thenable that resolves when the workspace folder was removed successfully. The user might prevent - * the operation from happening and this will be indicated with the return type. + * @return A thenable that resolves when the workspace folder was removed successfully. */ - export function updateWorkspaceFolders(index: number, deleteCount?: number, workspaceFoldersToAdd?: { uri: Uri, name?: string }[]): Thenable; + export function updateWorkspaceFolders(start: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: Uri, name?: string }[]): Thenable; } export namespace window { diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 48412fceb9c..d315aa12f99 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -13,21 +13,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; -import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; import { localize } from 'vs/nls'; -import { getPathLabel } from 'vs/base/common/labels'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { - private static CONFIRM_CHANGES_TO_WORKSPACES_KEY = 'workbench.confirmChangesToWorkspaceFromExtensions'; - private readonly _toDispose: IDisposable[] = []; private readonly _activeSearches: { [id: number]: TPromise } = Object.create(null); private readonly _proxy: ExtHostWorkspaceShape; @@ -39,9 +32,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ITextFileService private readonly _textFileService: ITextFileService, @IConfigurationService private _configurationService: IConfigurationService, @IWorkspaceEditingService private _workspaceEditingService: IWorkspaceEditingService, - @IMessageService private _messageService: IMessageService, - @IStatusbarService private _statusbarService: IStatusbarService, - @IEnvironmentService private _environmentService: IEnvironmentService, + @IStatusbarService private _statusbarService: IStatusbarService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace); this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose); @@ -59,7 +50,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- workspace --- - $updateWorkspaceFolders(extensionName: string, index: number, deleteCount?: number, add?: { uri: UriComponents, name?: string }[]): Thenable { + $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, ...add: { uri: UriComponents, name?: string }[]): Thenable { let workspaceFoldersToAdd: { uri: URI, name?: string }[] = []; if (Array.isArray(add)) { workspaceFoldersToAdd = add.map(f => ({ uri: URI.revive(f.uri), name: f.name })); @@ -74,33 +65,10 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return TPromise.as(false); // return early if we neither have folders to add nor remove } - return this.confirmUpdateWorkspaceFolders(extensionName, workspaceFoldersToAdd.map(f => f.uri), workspaceFoldersToRemove).then(confirmed => { - if (!confirmed) { - return TPromise.as(false); // return if not confirmed by the user - } + // Indicate in status message + this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd.map(f => f.uri), workspaceFoldersToRemove), 10 * 1000 /* 10s */); - return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true).then(() => true); - }); - } - - private confirmUpdateWorkspaceFolders(extensionName: string, workspaceFoldersToAdd?: URI[], workspaceFoldersToRemove?: URI[]): Thenable { - if (!this._configurationService.getValue(MainThreadWorkspace.CONFIRM_CHANGES_TO_WORKSPACES_KEY)) { - - // Indicate in status message - this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd, workspaceFoldersToRemove), 10 * 1000 /* 10s */); - - // return confirmed if the setting indicates this - return TPromise.as(true); - } - - return this._messageService.confirmWithCheckbox(this.getConfirmationOptions(extensionName, workspaceFoldersToAdd, workspaceFoldersToRemove)).then(confirmation => { - let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); - if (confirmation.confirmed && confirmation.checkboxChecked === true) { - updateConfirmSettingsPromise = this._configurationService.updateValue(MainThreadWorkspace.CONFIRM_CHANGES_TO_WORKSPACES_KEY, false, ConfigurationTarget.USER); - } - - return updateConfirmSettingsPromise.then(() => confirmation.confirmed); - }); + return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true).then(() => true); } private getStatusMessage(extensionName, workspaceFoldersToAdd?: URI[], workspaceFoldersToRemove?: URI[]): string { @@ -135,71 +103,6 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return message; } - private getConfirmationOptions(extensionName, workspaceFoldersToAdd?: URI[], workspaceFoldersToRemove?: URI[]): IConfirmation { - const wantsToDelete = Array.isArray(workspaceFoldersToRemove) && workspaceFoldersToRemove.length; - const wantsToAdd = Array.isArray(workspaceFoldersToAdd) && workspaceFoldersToAdd.length; - - let message: string; - let detail: string; - let primaryButton: string; - - // Add Folders - if (wantsToAdd && !wantsToDelete) { - if (workspaceFoldersToAdd.length === 1) { - message = localize('folderMessageAddSingleFolder', "Extension '{0}' wants to add a folder to the workspace. Please confirm.", extensionName); - primaryButton = localize('addFolder', "&&Add Folder"); - } else { - message = localize('folderMessageAddMultipleFolders', "Extension '{0}' wants to add {1} folders to the workspace. Please confirm.", extensionName, workspaceFoldersToAdd.length); - primaryButton = localize('addFolders', "&&Add Folders"); - } - - detail = this.getConfirmationDetail(workspaceFoldersToAdd, false); - } - - // Delete Folders - else if (wantsToDelete && !wantsToAdd) { - if (workspaceFoldersToRemove.length === 1) { - message = localize('folderMessageRemoveSingleFolder', "Extension '{0}' wants to remove a folder from the workspace. Please confirm.", extensionName); - primaryButton = localize('removeFolder', "&&Remove Folder"); - } else { - message = localize('folderMessageRemoveMultipleFolders', "Extension '{0}' wants to remove {1} folders from the workspace. Please confirm.", extensionName, workspaceFoldersToRemove.length); - primaryButton = localize('removeFolders', "&&Remove Folders"); - } - - detail = this.getConfirmationDetail(workspaceFoldersToRemove, true); - } - - // Change Folders - else { - message = localize('folderChangeFolder', "Extension '{0}' wants to change the folders of the workspace. Please confirm.", extensionName); - primaryButton = localize('changeFolders', "&&Change Folders"); - - detail = [this.getConfirmationDetail(workspaceFoldersToAdd, false), this.getConfirmationDetail(workspaceFoldersToRemove, true)].join('\n\n'); - } - - return { message, detail, type: 'question', primaryButton, checkbox: { label: localize('doNotAskAgain', "Do not ask me again") } }; - } - - private getConfirmationDetail(folders: URI[], isRemove: boolean): string { - const getFolderName = uri => { - return uri.scheme === 'file' ? getPathLabel(uri.fsPath, null, this._environmentService) : uri.toString(); - }; - - if (folders.length === 1) { - if (isRemove) { - return [localize('folderToRemove', "Folder to remove:"), ...folders.map(f => getFolderName(f))].join('\n'); - } - - return [localize('folderToAdd', "Folder to add:"), ...folders.map(f => getFolderName(f))].join('\n'); - } - - if (isRemove) { - return [localize('foldersToRemove', "Folders to remove:"), ...folders.map(f => getFolderName(f))].join('\n'); - } - - return [localize('foldersToAdd', "Folders to add:"), ...folders.map(f => getFolderName(f))].join('\n'); - } - private _onDidChangeWorkspace(): void { this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace()); } @@ -277,20 +180,4 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return result.results.every(each => each.success === true); }); } -} - -const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - -configurationRegistry.registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', - 'properties': { - 'workbench.confirmChangesToWorkspaceFromExtensions': { - 'type': 'boolean', - 'description': localize('confirmChangesFromExtensions', "Controls if a confirmation should be shown for extensions that add or remove workspace folders."), - 'default': true - } - } -}); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 18074ec7c82..2871bb7447b 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -418,8 +418,8 @@ export function createApiFactory( set name(value) { throw errors.readonly(); }, - updateWorkspaceFolders: proposedApiFunction(extension, (index, deleteCount, workspaceFoldersToAdd) => { - return extHostWorkspace.updateWorkspaceFolders(extension.displayName || extension.name, index, deleteCount, workspaceFoldersToAdd); + updateWorkspaceFolders: proposedApiFunction(extension, (index, deleteCount, ...workspaceFoldersToAdd) => { + return extHostWorkspace.updateWorkspaceFolders(extension.displayName || extension.name, index, deleteCount, ...workspaceFoldersToAdd); }), onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 9c08e2e2f84..ed925eadfc5 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -365,7 +365,7 @@ export interface MainThreadWorkspaceShape extends IDisposable { $startSearch(includePattern: string, includeFolder: string, excludePattern: string, maxResults: number, requestId: number): Thenable; $cancelSearch(requestId: number): Thenable; $saveAll(includeUntitled?: boolean): Thenable; - $updateWorkspaceFolders(extensionName: string, index: number, deleteCount?: number, workspaceFoldersToAdd?: { uri: UriComponents, name?: string }[]): Thenable; + $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable; } export interface IFileChangeDto { diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 6431e6fbdf5..eab2ad97d7d 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -86,8 +86,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } } - updateWorkspaceFolders(extensionName: string, index: number, deleteCount?: number, workspaceFoldersToAdd?: { uri: vscode.Uri, name?: string }[]): Thenable { - return this._proxy.$updateWorkspaceFolders(extensionName, index, deleteCount, workspaceFoldersToAdd); + updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[]): Thenable { + return this._proxy.$updateWorkspaceFolders(extensionName, index, deleteCount, ...workspaceFoldersToAdd); } getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder {