Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to update workspace folders #42026

Merged
merged 25 commits into from
Jan 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
752c7b7
first cut updateFolders API
bpasero Jan 22, 2018
f963973
first cut of proposed updateWorkspaceFolders API
bpasero Jan 22, 2018
d2501cd
polish API docs
bpasero Jan 23, 2018
fc22b94
more API docs
bpasero Jan 23, 2018
c9cc93c
Merge branch 'master' into ben/workspace-api
bpasero Jan 23, 2018
1172986
add status message when not showing confirmation
bpasero Jan 23, 2018
e410a78
handle single folder case better
bpasero Jan 23, 2018
8284fc6
respect index property when adding folders
bpasero Jan 23, 2018
3660fb8
address some feedback
bpasero Jan 23, 2018
a5f5d37
Merge branch 'master' into ben/workspace-api
bpasero Jan 23, 2018
de1dd85
updateWorkspaceFolders - add some validation
bpasero Jan 23, 2018
7d20e75
:lipstick:
bpasero Jan 23, 2018
d35e6e3
Merge branch 'master' into ben/workspace-api
bpasero Jan 24, 2018
5c9b0eb
simplify code
bpasero Jan 24, 2018
40798a9
use live objects and avoid promises
bpasero Jan 25, 2018
1a381b4
add test to verify $acceptWorkspaceData keeps existing workspace fold…
bpasero Jan 25, 2018
c345b67
updateWorkspaceFolders tests
bpasero Jan 25, 2018
91f4de5
more tests and fix liveness issue
bpasero Jan 25, 2018
202c3fe
:lipstick:
bpasero Jan 25, 2018
b62dbb6
fix tests
bpasero Jan 25, 2018
7b29aa6
Merge branch 'master' into ben/workspace-api
bpasero Jan 26, 2018
a0de412
actually implement and test live objects
bpasero Jan 26, 2018
49eb095
add test and fix issue with swapping folders
bpasero Jan 26, 2018
5b1bd55
extract common delta code
bpasero Jan 26, 2018
d134615
more tests
bpasero Jan 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/vs/platform/workspace/common/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ export class Workspace implements IWorkspace {
export class WorkspaceFolder implements IWorkspaceFolder {

readonly uri: URI;
readonly name: string;
readonly index: number;
name: string;
index: number;

constructor(data: IWorkspaceFolderData,
readonly raw?: IStoredWorkspaceFolder) {
Expand Down
35 changes: 35 additions & 0 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,41 @@ declare module 'vscode' {

export namespace workspace {
export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider): Disposable;

/**
* Updates the workspace folders of the currently opened workspace. This method allows to add, remove
* and change workspace folders a the same time.
*
* **Example:** adding a new workspace folder at the end of workspace folders
* ```typescript
* workspace.updateWorkspaceFolders(workspace.workspaceFolders ? workspace.workspaceFolders.length : 0, null, { uri: ...});
* ```
*
* **Example:** removing the first workspace folder
* ```typescript
* workspace.updateWorkspaceFolders(0, 1);
* ```
*
* **Example:** replacing an existing workspace folder with a new one
* ```typescript
* workspace.updateWorkspaceFolders(0, 1, { uri: ...});
* ```
*
* It is valid to remove an existing workspace folder and add it again with a different name
* to rename that folder.
*
* 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 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 true if the operation was successfully started. Use the [onDidChangeWorkspaceFolders()](#onDidChangeWorkspaceFolders)
* event to get notified when the workspace folders have been updated.
*/
export function updateWorkspaceFolders(start: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: Uri, name?: string }[]): boolean;
}

export namespace window {
Expand Down
52 changes: 49 additions & 3 deletions src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'use strict';

import { isPromiseCanceledError } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { ISearchService, QueryType, ISearchQuery, IFolderQuery, ISearchConfiguration } from 'vs/platform/search/common/search';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
Expand All @@ -14,6 +14,9 @@ import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainCo
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { localize } from 'vs/nls';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';

@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
Expand All @@ -27,7 +30,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@ISearchService private readonly _searchService: ISearchService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ITextFileService private readonly _textFileService: ITextFileService,
@IConfigurationService private _configurationService: IConfigurationService
@IConfigurationService private _configurationService: IConfigurationService,
@IWorkspaceEditingService private _workspaceEditingService: IWorkspaceEditingService,
@IStatusbarService private _statusbarService: IStatusbarService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
Expand All @@ -45,6 +50,47 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {

// --- workspace ---

$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, foldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void> {
const workspaceFoldersToAdd = foldersToAdd.map(f => ({ uri: URI.revive(f.uri), name: f.name }));

// Indicate in status message
this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), 10 * 1000 /* 10s */);

return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true);
}

private getStatusMessage(extensionName, addCount: number, removeCount: number): string {
let message: string;

const wantsToAdd = addCount > 0;
const wantsToDelete = removeCount > 0;

// Add Folders
if (wantsToAdd && !wantsToDelete) {
if (addCount === 1) {
message = localize('folderStatusMessageAddSingleFolder', "Extension '{0}' added 1 folder to the workspace", extensionName);
} else {
message = localize('folderStatusMessageAddMultipleFolders', "Extension '{0}' added {1} folders to the workspace", extensionName, addCount);
}
}

// Delete Folders
else if (wantsToDelete && !wantsToAdd) {
if (removeCount === 1) {
message = localize('folderStatusMessageRemoveSingleFolder', "Extension '{0}' removed 1 folder from the workspace", extensionName);
} else {
message = localize('folderStatusMessageRemoveMultipleFolders', "Extension '{0}' removed {1} folders from the workspace", extensionName, removeCount);
}
}

// Change Folders
else {
message = localize('folderStatusChangeFolder', "Extension '{0}' changed folders of the workspace", extensionName);
}

return message;
}

private _onDidChangeWorkspace(): void {
this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace());
}
Expand Down Expand Up @@ -122,4 +168,4 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
return result.results.every(each => each.success === true);
});
}
}
}
3 changes: 3 additions & 0 deletions src/vs/workbench/api/node/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@ 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);
}),
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
},
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ export interface MainThreadWorkspaceShape extends IDisposable {
$startSearch(includePattern: string, includeFolder: string, excludePattern: string, maxResults: number, requestId: number): Thenable<UriComponents[]>;
$cancelSearch(requestId: number): Thenable<boolean>;
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void>;
}

export interface IFileChangeDto {
Expand Down
Loading