workspaceActions.ts 11.9 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";
B
Benjamin Pasero 已提交
25
import { isParent } from "vs/platform/files/common/files";
26 27 28 29 30 31 32 33 34 35 36 37 38 39

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);
	}

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

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);
	}

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

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

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

S
Sandeep Somavarapu 已提交
75
	protected handleNotInMultiFolderWorkspaceCase(message: string, actionLabel: string): boolean {
76
		const newWorkspace = { label: mnemonicButtonLabel(actionLabel), canceled: false };
B
Benjamin Pasero 已提交
77 78 79 80 81 82 83 84 85 86 87 88
		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 已提交
89
			detail: nls.localize('workspaceDetail', "Workspaces allow to open multiple folders at once."),
B
Benjamin Pasero 已提交
90
			noLink: true,
B
Benjamin Pasero 已提交
91
			type: 'question',
B
Benjamin Pasero 已提交
92 93 94 95 96
			buttons: buttons.map(button => button.label),
			cancelId: buttons.indexOf(cancel)
		};

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

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

B
Benjamin Pasero 已提交
104
	protected pickFolders(buttonLabel: string, title: string): string[] {
B
Benjamin Pasero 已提交
105
		return this.windowService.showOpenDialog({
B
Benjamin Pasero 已提交
106 107
			buttonLabel,
			title,
B
Benjamin Pasero 已提交
108 109 110 111
			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
		});
	}
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> {
132
		let folders = this.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'select', comment: ['&& denotes a mnemonic'] }, "&&Select")), nls.localize('selectWorkspace', "Select Folders for Workspace"));
S
Sandeep Somavarapu 已提交
133 134
		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
		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> {
152
		let folders = this.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'select', comment: ['&& denotes a mnemonic'] }, "&&Select")), nls.localize('selectWorkspace', "Select Folders for Workspace"));
S
Sandeep Somavarapu 已提交
153 154 155 156
		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
		if (!this.contextService.hasWorkspace()) {
			return this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL).run();
		}

		if (this.contextService.hasFolderWorkspace()) {
B
Benjamin Pasero 已提交
187
			if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('addSupported', "Adding a folder to workspace is not supported when window is 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 and 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

193
		const folders = super.pickFolders(mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"));
S
Sandeep Somavarapu 已提交
194 195 196 197 198 199 200
		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

223
export class SaveWorkspaceAsAction extends BaseWorkspacesAction {
224

225 226
	static ID = 'workbench.action.saveWorkspaceAs';
	static LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As...");
227 228 229 230

	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
		}

B
Benjamin Pasero 已提交
250
		this.messageService.show(Severity.Info, nls.localize('saveEmptyWorkspaceNotSupported', "Saving a workspace is not supported when the window is opened without a folder. Please open a folder first."));
251
		return TPromise.as(null);
S
Sandeep Somavarapu 已提交
252 253 254
	}

	private saveFolderWorkspace(): TPromise<void> {
B
Benjamin Pasero 已提交
255
		if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('saveNotSupported', "Saving a workspace is not supported when the window is 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 and 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
		return TPromise.as(null);
	}

	private getNewWorkspaceConfiPath(): string {
B
Benjamin Pasero 已提交
282 283 284 285 286 287 288 289
		const workspace = this.contextService.getWorkspace();
		let defaultPath: string;
		if (this.contextService.hasMultiFolderWorkspace() && !this.isUntitledWorkspace(workspace.configuration.fsPath)) {
			defaultPath = workspace.configuration.fsPath;
		} else {
			defaultPath = dirname(this.contextService.getWorkspace().roots[0].fsPath); // pick the parent of the first root by default
		}

S
Sandeep Somavarapu 已提交
290
		return this.windowService.showSaveDialog({
291
			buttonLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")),
S
Sandeep Somavarapu 已提交
292 293
			title: nls.localize('saveWorkspace', "Save Workspace"),
			filters: WORKSPACE_FILTER,
B
Benjamin Pasero 已提交
294
			defaultPath
S
Sandeep Somavarapu 已提交
295
		});
296
	}
B
Benjamin Pasero 已提交
297 298 299 300

	private isUntitledWorkspace(path: string): boolean {
		return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */);
	}
301 302 303 304 305 306 307 308 309 310 311
}

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 已提交
312
		@IWorkspaceContextService private contextService: IWorkspaceContextService
313 314 315 316 317
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
318
		return this.windowService.openWorkspace();
319 320
	}
}