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

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

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

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

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

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

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

S
Sandeep Somavarapu 已提交
76
	protected handleNotInMultiFolderWorkspaceCase(message: string): boolean {
77
		const newWorkspace = { label: mnemonicLabel(nls.localize({ key: 'reload', comment: ['&& denotes a mnemonic'] }, "&&Reload")), canceled: false };
B
Benjamin Pasero 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90
		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,
			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[] {
105 106 107 108 109 110
		const workspace = this.contextService.getWorkspace();
		let defaultPath: string;
		if (workspace && workspace.roots.length > 0) {
			defaultPath = dirname(workspace.roots[0].fsPath); // pick the parent of the first root by default
		}

B
Benjamin Pasero 已提交
111
		return this.windowService.showOpenDialog({
B
Benjamin Pasero 已提交
112 113
			buttonLabel,
			title,
B
Benjamin Pasero 已提交
114
			properties: ['multiSelections', 'openDirectory', 'createDirectory'],
115
			defaultPath
B
Benjamin Pasero 已提交
116 117
		});
	}
B
Benjamin Pasero 已提交
118 119
}

120
export class NewWorkspaceFromExistingAction extends BaseWorkspacesAction {
B
Benjamin Pasero 已提交
121

122 123
	static ID = 'workbench.action.newWorkspaceFromExisting';
	static LABEL = nls.localize('newWorkspaceFormExisting', "New Workspace From Existing...");
B
Benjamin Pasero 已提交
124 125 126 127

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
128
		@IWindowService windowService: IWindowService,
B
Benjamin Pasero 已提交
129
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
130 131 132
		@IEnvironmentService environmentService: IEnvironmentService,
		@IWorkspacesService protected workspacesService: IWorkspacesService,
		@IWindowsService protected windowsService: IWindowsService,
B
Benjamin Pasero 已提交
133
	) {
S
Sandeep Somavarapu 已提交
134
		super(id, label, windowService, environmentService, contextService);
B
Benjamin Pasero 已提交
135 136 137
	}

	public run(): TPromise<any> {
S
Sandeep Somavarapu 已提交
138
		if (this.contextService.hasWorkspace()) {
139
			let folders = this.pickFolders(mnemonicLabel(nls.localize({ key: 'select', comment: ['&& denotes a mnemonic'] }, "&&Select")), nls.localize('selectWorkspace', "Select Folders for Workspace"));
S
Sandeep Somavarapu 已提交
140 141 142 143
			if (folders && folders.length) {
				if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('addSupported', "To open multiple folders, window reload is required."))) {
					return this.createWorkspace([this.contextService.getWorkspace().roots[0], ...folders.map(folder => URI.file(folder))]);
				}
144
			}
B
Benjamin Pasero 已提交
145
		}
S
Sandeep Somavarapu 已提交
146 147 148
		return TPromise.as(null);
	}

149
	private createWorkspace(folders: URI[]): TPromise<void> {
S
Sandeep Somavarapu 已提交
150 151 152 153 154 155
		return this.workspacesService.createWorkspace(distinct(folders.map(folder => folder.toString(true /* encoding */))))
			.then(({ configPath }) => this.windowsService.openWindow([configPath]));
	}
}

export class AddRootFolderAction extends BaseWorkspacesAction {
156

S
Sandeep Somavarapu 已提交
157 158
	static ID = 'workbench.action.addRootFolder';
	static LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace...");
159 160 161 162

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
163 164
		@IWindowService windowService: IWindowService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
165 166
		@IEnvironmentService environmentService: IEnvironmentService,
		@IInstantiationService private instantiationService: IInstantiationService,
167
		@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
S
Sandeep Somavarapu 已提交
168
		@IViewletService private viewletService: IViewletService
169
	) {
S
Sandeep Somavarapu 已提交
170
		super(id, label, windowService, environmentService, contextService);
171 172
	}

S
Sandeep Somavarapu 已提交
173
	public run(): TPromise<any> {
174 175 176 177 178
		if (!this.contextService.hasWorkspace()) {
			return this.instantiationService.createInstance(NewWorkspaceAction, NewWorkspaceAction.ID, NewWorkspaceAction.LABEL).run();
		}

		if (this.contextService.hasFolderWorkspace()) {
S
Sandeep Somavarapu 已提交
179
			return this.instantiationService.createInstance(NewWorkspaceFromExistingAction, NewWorkspaceFromExistingAction.ID, NewWorkspaceFromExistingAction.LABEL).run();
B
Benjamin Pasero 已提交
180
		}
B
Benjamin Pasero 已提交
181

182
		const folders = super.pickFolders(mnemonicLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")), nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"));
S
Sandeep Somavarapu 已提交
183 184 185 186 187 188 189
		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);
		});
190 191 192
	}
}

I
isidor 已提交
193
export class RemoveRootFolderAction extends Action {
B
Benjamin Pasero 已提交
194

I
isidor 已提交
195
	static ID = 'workbench.action.removeRootFolder';
196
	static LABEL = nls.localize('removeFolderFromWorkspace', "Remove Folder from Workspace");
B
Benjamin Pasero 已提交
197 198

	constructor(
I
isidor 已提交
199
		private rootUri: URI,
B
Benjamin Pasero 已提交
200 201 202 203 204 205 206 207
		id: string,
		label: string,
		@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
I
isidor 已提交
208
		return this.workspaceEditingService.removeRoots([this.rootUri]);
B
Benjamin Pasero 已提交
209
	}
I
isidor 已提交
210
}
211

212
export class SaveWorkspaceAsAction extends BaseWorkspacesAction {
213

214 215
	static ID = 'workbench.action.saveWorkspaceAs';
	static LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As...");
216 217 218 219

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
220 221
		@IWindowService windowService: IWindowService,
		@IEnvironmentService environmentService: IEnvironmentService,
B
Benjamin Pasero 已提交
222
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
223
		@IWorkspacesService protected workspacesService: IWorkspacesService,
224 225
		@IWindowsService private windowsService: IWindowsService,
		@IMessageService private messageService: IMessageService
226
	) {
S
Sandeep Somavarapu 已提交
227
		super(id, label, windowService, environmentService, contextService);
228 229 230
	}

	public run(): TPromise<any> {
S
Sandeep Somavarapu 已提交
231 232 233
		if (!this.contextService.hasWorkspace()) {
			this.messageService.show(Severity.Info, nls.localize('saveEmptyWorkspaceNotSupported', "Please open a workspace first to save."));
			return TPromise.as(null);
S
Sandeep Somavarapu 已提交
234 235
		}

S
Sandeep Somavarapu 已提交
236 237 238 239 240
		const configPath = this.getNewWorkspaceConfigPath();
		if (configPath) {
			if (this.contextService.hasFolderWorkspace()) {
				return this.saveFolderWorkspace(configPath);
			}
S
Sandeep Somavarapu 已提交
241

S
Sandeep Somavarapu 已提交
242 243
			if (this.contextService.hasMultiFolderWorkspace()) {
				return this.contextService.saveWorkspace(URI.file(configPath));
S
Sandeep Somavarapu 已提交
244 245
			}
		}
S
Sandeep Somavarapu 已提交
246

S
Sandeep Somavarapu 已提交
247 248 249
		return TPromise.as(null);
	}

S
Sandeep Somavarapu 已提交
250 251 252 253 254 255 256 257 258 259
	private saveFolderWorkspace(configPath: string): TPromise<void> {
		if (this.handleNotInMultiFolderWorkspaceCase(nls.localize('saveNotSupported', "To save workspace, window reload is required."))) {
			// 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]));
				});
260
		}
S
Sandeep Somavarapu 已提交
261 262 263
		return TPromise.as(null);
	}

264
	private getNewWorkspaceConfigPath(): string {
B
Benjamin Pasero 已提交
265 266 267 268
		const workspace = this.contextService.getWorkspace();
		let defaultPath: string;
		if (this.contextService.hasMultiFolderWorkspace() && !this.isUntitledWorkspace(workspace.configuration.fsPath)) {
			defaultPath = workspace.configuration.fsPath;
269 270
		} else if (workspace && workspace.roots.length > 0) {
			defaultPath = dirname(workspace.roots[0].fsPath); // pick the parent of the first root by default
B
Benjamin Pasero 已提交
271 272
		}

S
Sandeep Somavarapu 已提交
273
		return this.windowService.showSaveDialog({
274
			buttonLabel: mnemonicLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")),
S
Sandeep Somavarapu 已提交
275 276
			title: nls.localize('saveWorkspace', "Save Workspace"),
			filters: WORKSPACE_FILTER,
B
Benjamin Pasero 已提交
277
			defaultPath
S
Sandeep Somavarapu 已提交
278
		});
279
	}
B
Benjamin Pasero 已提交
280 281 282 283

	private isUntitledWorkspace(path: string): boolean {
		return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */);
	}
284 285 286 287 288 289 290 291 292 293 294
}

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 已提交
295
		@IWorkspaceContextService private contextService: IWorkspaceContextService
296 297 298 299 300
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
301
		return this.windowService.openWorkspace();
302
	}
303 304
}

305
class NewWorkspaceAction extends Action {
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

	static ID = 'workbench.action.newWorkspace';
	static LABEL = nls.localize('newWorkspace', "New Workspace...");

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

	public run(): TPromise<any> {
		return this.windowService.newWorkspace();
	}
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
}

export class OpenWorkspaceConfigFileAction extends Action {

	public static ID = 'workbench.action.openWorkspaceConfigFile';
	public static LABEL = nls.localize('openWorkspaceConfigFile', "Open Workspace Configuration File");

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
		this.enabled = this.workspaceContextService.hasMultiFolderWorkspace();
	}

	public run(): TPromise<any> {
		return this.editorService.openEditor({ resource: this.workspaceContextService.getWorkspace().configuration });
	}
342
}