workspaceActions.ts 11.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import nls = require('vs/nls');
S
Sandeep Somavarapu 已提交
11
import { distinct } from 'vs/base/common/arrays';
12
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
13
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
B
Benjamin Pasero 已提交
14 15 16 17
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import URI from 'vs/base/common/uri';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
18
import { IInstantiationService } from "vs/platform/instantiation/common/instantiation";
19
import { IWorkspacesService, WORKSPACE_FILTER } from "vs/platform/workspaces/common/workspaces";
20
import { IMessageService, Severity } from "vs/platform/message/common/message";
B
Benjamin Pasero 已提交
21
import { IEnvironmentService } from "vs/platform/environment/common/environment";
22
import { isLinux } from "vs/base/common/platform";
B
Benjamin Pasero 已提交
23
import { dirname } from "vs/base/common/paths";
24
import { mnemonicButtonLabel } from "vs/base/common/labels";
25 26 27 28 29 30 31 32 33 34 35 36 37 38

export class OpenFolderAction extends Action {

	static ID = 'workbench.action.files.openFolder';
	static LABEL = nls.localize('openFolder', "Open Folder...");

	constructor(
		id: string,
		label: string,
		@IWindowService private windowService: IWindowService
	) {
		super(id, label);
	}

39
	run(event?: any, data?: ITelemetryData): TPromise<any> {
B
renames  
Benjamin Pasero 已提交
40
		return this.windowService.pickFolderAndOpen(undefined, data);
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
	}
}

export class OpenFileFolderAction extends Action {

	static ID = 'workbench.action.files.openFileFolder';
	static LABEL = nls.localize('openFileFolder', "Open...");

	constructor(
		id: string,
		label: string,
		@IWindowService private windowService: IWindowService
	) {
		super(id, label);
	}

57
	run(event?: any, data?: ITelemetryData): TPromise<any> {
B
renames  
Benjamin Pasero 已提交
58
		return this.windowService.pickFileFolderAndOpen(undefined, data);
59
	}
B
Benjamin Pasero 已提交
60 61
}

B
Benjamin Pasero 已提交
62
export abstract class BaseWorkspacesAction extends Action {
B
Benjamin Pasero 已提交
63 64 65 66 67

	constructor(
		id: string,
		label: string,
		protected windowService: IWindowService,
B
Benjamin Pasero 已提交
68 69
		protected environmentService: IEnvironmentService,
		protected contextService: IWorkspaceContextService
B
Benjamin Pasero 已提交
70 71 72 73
	) {
		super(id, label);
	}

S
Sandeep Somavarapu 已提交
74
	protected handleNotInMultiFolderWorkspaceCase(message: string, actionLabel: string): boolean {
75
		const newWorkspace = { label: mnemonicButtonLabel(actionLabel), canceled: false };
B
Benjamin Pasero 已提交
76 77 78 79 80 81 82 83 84 85 86 87
		const cancel = { label: nls.localize('cancel', "Cancel"), canceled: true };

		const buttons: { label: string; canceled: boolean; }[] = [];
		if (isLinux) {
			buttons.push(cancel, newWorkspace);
		} else {
			buttons.push(newWorkspace, cancel);
		}

		const opts: Electron.ShowMessageBoxOptions = {
			title: this.environmentService.appNameLong,
			message,
S
Sandeep Somavarapu 已提交
88
			detail: nls.localize('workspaceDetail', "Workspaces allow to open multiple folders at once."),
B
Benjamin Pasero 已提交
89 90 91 92 93 94 95
			noLink: true,
			type: 'info',
			buttons: buttons.map(button => button.label),
			cancelId: buttons.indexOf(cancel)
		};

		if (isLinux) {
B
Benjamin Pasero 已提交
96
			opts.defaultId = 1;
B
Benjamin Pasero 已提交
97 98 99
		}

		const res = this.windowService.showMessageBox(opts);
S
Sandeep Somavarapu 已提交
100
		return !buttons[res].canceled;
B
Benjamin Pasero 已提交
101 102
	}

B
Benjamin Pasero 已提交
103
	protected pickFolders(buttonLabel: string, title: string): string[] {
B
Benjamin Pasero 已提交
104
		return this.windowService.showOpenDialog({
B
Benjamin Pasero 已提交
105 106
			buttonLabel,
			title,
B
Benjamin Pasero 已提交
107 108 109 110
			properties: ['multiSelections', 'openDirectory', 'createDirectory'],
			defaultPath: this.contextService.hasWorkspace() ? dirname(this.contextService.getWorkspace().roots[0].fsPath) : void 0 // pick the parent of the first root by default
		});
	}
S
Sandeep Somavarapu 已提交
111

B
Benjamin Pasero 已提交
112 113
}

S
Sandeep Somavarapu 已提交
114
export class NewWorkspaceAction extends BaseWorkspacesAction {
B
Benjamin Pasero 已提交
115

S
Sandeep Somavarapu 已提交
116 117
	static ID = 'workbench.action.newWorkspace';
	static LABEL = nls.localize('newWorkspace', "New Workspace...");
B
Benjamin Pasero 已提交
118 119 120 121

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
122
		@IWindowService windowService: IWindowService,
B
Benjamin Pasero 已提交
123
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
124 125 126
		@IEnvironmentService environmentService: IEnvironmentService,
		@IWorkspacesService protected workspacesService: IWorkspacesService,
		@IWindowsService protected windowsService: IWindowsService,
B
Benjamin Pasero 已提交
127
	) {
S
Sandeep Somavarapu 已提交
128
		super(id, label, windowService, environmentService, contextService);
B
Benjamin Pasero 已提交
129 130 131
	}

	public run(): TPromise<any> {
S
Sandeep Somavarapu 已提交
132 133 134
		let folders = this.pickFolders(nls.localize('select', "Select"), nls.localize('selectWorkspace', "Select Folders for Workspace"));
		if (folders && folders.length) {
			return this.createWorkspace(folders.map(folder => URI.file(folder)));
B
Benjamin Pasero 已提交
135 136
		}

S
Sandeep Somavarapu 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
		return TPromise.as(null);
	}

	protected createWorkspace(folders: URI[]): TPromise<void> {
		return this.workspacesService.createWorkspace(distinct(folders.map(folder => folder.toString(true /* encoding */))))
			.then(({ configPath }) => this.windowsService.openWindow([configPath]));
	}
}

export class NewWorkspaceFromExistingAction extends NewWorkspaceAction {

	static ID = 'workbench.action.newWorkspaceFromExisting';
	static LABEL = nls.localize('newWorkspaceFormExisting', "New Workspace From Existing...");

	public run(): TPromise<any> {
		let folders = this.pickFolders(nls.localize('select', "Select"), nls.localize('selectWorkspace', "Select Folders for Workspace"));
		if (folders && folders.length) {
			if (this.contextService.hasWorkspace()) {
				return this.createWorkspace([this.contextService.getWorkspace().roots[0], ...folders.map(folder => URI.file(folder))]);
			}
B
Benjamin Pasero 已提交
157
		}
158

S
Sandeep Somavarapu 已提交
159
		return TPromise.as(null);
B
Benjamin Pasero 已提交
160 161 162
	}
}

S
Sandeep Somavarapu 已提交
163
export class AddRootFolderAction extends BaseWorkspacesAction {
164

S
Sandeep Somavarapu 已提交
165 166
	static ID = 'workbench.action.addRootFolder';
	static LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace...");
167 168 169 170

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
171 172
		@IWindowService windowService: IWindowService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
173 174
		@IEnvironmentService environmentService: IEnvironmentService,
		@IInstantiationService private instantiationService: IInstantiationService,
175
		@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
S
Sandeep Somavarapu 已提交
176
		@IViewletService private viewletService: IViewletService
177
	) {
S
Sandeep Somavarapu 已提交
178
		super(id, label, windowService, environmentService, contextService);
179 180
	}

S
Sandeep Somavarapu 已提交
181
	public run(): TPromise<any> {
182 183 184 185 186 187
		if (!this.contextService.hasWorkspace()) {
			return this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL).run();
		}

		if (this.contextService.hasFolderWorkspace()) {
			if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('addSupported', "Adding a folder to workspace is not supported when opened with a folder.\n\nDo you want to create a new workspace with the current folder and add folders to it?\n"), nls.localize({ key: 'createAndAdd', comment: ['&& denotes a mnemonic'] }, "&&Create Workspace & Add"))) {
S
Sandeep Somavarapu 已提交
188
				return this.instantiationService.createInstance(NewWorkspaceFromExistingAction, NewWorkspaceFromExistingAction.ID, NewWorkspaceFromExistingAction.LABEL).run();
S
Sandeep Somavarapu 已提交
189
			}
S
Sandeep Somavarapu 已提交
190
			return TPromise.as(null);
B
Benjamin Pasero 已提交
191
		}
B
Benjamin Pasero 已提交
192

S
Sandeep Somavarapu 已提交
193 194 195 196 197 198 199 200
		const folders = super.pickFolders(nls.localize('add', "Add"), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"));
		if (!folders || !folders.length) {
			return TPromise.as(null);
		}

		return this.workspaceEditingService.addRoots(folders.map(folder => URI.file(folder))).then(() => {
			return this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true);
		});
201 202 203
	}
}

I
isidor 已提交
204
export class RemoveRootFolderAction extends Action {
B
Benjamin Pasero 已提交
205

I
isidor 已提交
206
	static ID = 'workbench.action.removeRootFolder';
207
	static LABEL = nls.localize('removeFolderFromWorkspace', "Remove Folder from Workspace");
B
Benjamin Pasero 已提交
208 209

	constructor(
I
isidor 已提交
210
		private rootUri: URI,
B
Benjamin Pasero 已提交
211 212 213 214 215 216 217 218
		id: string,
		label: string,
		@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
I
isidor 已提交
219
		return this.workspaceEditingService.removeRoots([this.rootUri]);
B
Benjamin Pasero 已提交
220
	}
I
isidor 已提交
221
}
222

B
Benjamin Pasero 已提交
223
export class SaveWorkspaceAction extends BaseWorkspacesAction {
224 225 226 227 228 229 230

	static ID = 'workbench.action.saveWorkspace';
	static LABEL = nls.localize('saveWorkspaceAction', "Save Workspace...");

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
231 232
		@IWindowService windowService: IWindowService,
		@IEnvironmentService environmentService: IEnvironmentService,
B
Benjamin Pasero 已提交
233
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
234
		@IWorkspacesService protected workspacesService: IWorkspacesService,
235 236
		@IWindowsService private windowsService: IWindowsService,
		@IMessageService private messageService: IMessageService
237
	) {
S
Sandeep Somavarapu 已提交
238
		super(id, label, windowService, environmentService, contextService);
239 240 241
	}

	public run(): TPromise<any> {
S
Sandeep Somavarapu 已提交
242 243
		if (this.contextService.hasFolderWorkspace()) {
			return this.saveFolderWorkspace();
244 245
		}

S
Sandeep Somavarapu 已提交
246
		if (this.contextService.hasMultiFolderWorkspace()) {
247
			return this.saveMultiFolderWorkspace();
S
Sandeep Somavarapu 已提交
248 249
		}

250 251
		this.messageService.show(Severity.Info, nls.localize('saveEmptyWorkspaceNotSupported', "Cannot save an empty workspace"));
		return TPromise.as(null);
S
Sandeep Somavarapu 已提交
252 253 254
	}

	private saveFolderWorkspace(): TPromise<void> {
255
		if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('saveNotSupported', "Saving a workspace is not supported when opened with a folder.\n\nDo you want to create a new workspace with the current folder and save it?\n"), nls.localize({ key: 'createAndSave', comment: ['&& denotes a mnemonic'] }, "&&Create Workspace & Save"))) {
S
Sandeep Somavarapu 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
			const configPath = this.getNewWorkspaceConfiPath();
			if (configPath) {
				// Create workspace first
				this.workspacesService.createWorkspace(this.contextService.getWorkspace().roots.map(root => root.toString(true /* skip encoding */)))
					.then(workspaceIdentifier => {
						// Save the workspace in new location
						return this.workspacesService.saveWorkspace(workspaceIdentifier, configPath)
							// Open the saved workspace
							.then(({ configPath }) => this.windowsService.openWindow([configPath]));
					});
			}
		}
		return TPromise.as(null);
	}

	private saveMultiFolderWorkspace(): TPromise<void> {
		const target = this.getNewWorkspaceConfiPath();
273 274

		if (target) {
275
			return this.contextService.saveWorkspace(URI.file(target));
276 277
		}

S
Sandeep Somavarapu 已提交
278 279 280 281 282 283 284 285 286 287
		return TPromise.as(null);
	}

	private getNewWorkspaceConfiPath(): string {
		return this.windowService.showSaveDialog({
			buttonLabel: nls.localize('save', "Save"),
			title: nls.localize('saveWorkspace', "Save Workspace"),
			filters: WORKSPACE_FILTER,
			defaultPath: dirname(this.contextService.getWorkspace().roots[0].fsPath) // pick the parent of the first root by default
		});
288 289 290 291 292 293 294 295 296 297 298 299
	}
}

export class OpenWorkspaceAction extends Action {

	static ID = 'workbench.action.openWorkspace';
	static LABEL = nls.localize('openWorkspaceAction', "Open Workspace...");

	constructor(
		id: string,
		label: string,
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
300 301
		@IWindowsService private windowsService: IWindowsService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
302 303 304 305 306 307 308 309
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
		const files = this.windowService.showOpenDialog({
			buttonLabel: nls.localize('open', "Open"),
			title: nls.localize('openWorkspace', "Open Workspace"),
310
			filters: WORKSPACE_FILTER,
B
Benjamin Pasero 已提交
311 312
			properties: ['openFile'],
			defaultPath: this.contextService.hasWorkspace() ? dirname(this.contextService.getWorkspace().roots[0].fsPath) : void 0 // pick the parent of the first root by default
313 314 315 316 317 318 319 320 321
		});

		if (!files || !files.length) {
			return TPromise.as(null);
		}

		return this.windowsService.openWindow([files[0]]);
	}
}