actions.ts 40.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

8
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
9 10
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
J
Joao Moreno 已提交
11
import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService';
12
import { IWindowService, IWindowsService, MenuBarVisibility } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
13
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
E
Erich Gamma 已提交
14
import nls = require('vs/nls');
15 16
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
B
Benjamin Pasero 已提交
17
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
18 19 20 21
import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
22
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
J
Johannes Rieken 已提交
23 24
import { IExtensionManagementService, LocalExtensionType, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
B
Benjamin Pasero 已提交
25
import paths = require('vs/base/common/paths');
26
import { isMacintosh, isLinux } from 'vs/base/common/platform';
J
Johannes Rieken 已提交
27
import { IQuickOpenService, IFilePickOpenEntry, ISeparator } from 'vs/platform/quickOpen/common/quickOpen';
J
Johannes Rieken 已提交
28
import { KeyMod } from 'vs/base/common/keyCodes';
29
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
30
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
B
Benjamin Pasero 已提交
31
import { IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
B
Benjamin Pasero 已提交
32
import { ITimerService, IStartupMetrics } from 'vs/workbench/services/timer/common/timerService';
S
sj.hwang 已提交
33 34 35 36
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IPartService, Parts, Position as SidebarPosition } from 'vs/workbench/services/part/common/partService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
37 38
import { QuickOpenAction } from "vs/workbench/browser/quickopen";
import { SWITCH_WINDOWS_PREFIX } from "vs/workbench/electron-browser/windowPicker";
E
Erich Gamma 已提交
39

B
Benjamin Pasero 已提交
40
import * as os from 'os';
41
import { webFrame } from 'electron';
E
Erich Gamma 已提交
42

43 44
// --- actions

E
Erich Gamma 已提交
45 46 47 48 49 50 51 52
export class CloseEditorAction extends Action {

	public static ID = 'workbench.action.closeActiveEditor';
	public static LABEL = nls.localize('closeActiveEditor', "Close Editor");

	constructor(
		id: string,
		label: string,
53
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
E
Erich Gamma 已提交
54 55 56 57
	) {
		super(id, label);
	}

58
	public run(): TPromise<any> {
B
Benjamin Pasero 已提交
59
		const activeEditor = this.editorService.getActiveEditor();
E
Erich Gamma 已提交
60
		if (activeEditor) {
61
			return this.editorService.closeEditor(activeEditor.position, activeEditor.input);
E
Erich Gamma 已提交
62 63
		}

A
Alex Dima 已提交
64
		return TPromise.as(false);
E
Erich Gamma 已提交
65 66 67 68 69 70 71 72
	}
}

export class CloseWindowAction extends Action {

	public static ID = 'workbench.action.closeWindow';
	public static LABEL = nls.localize('closeWindow', "Close Window");

J
Joao Moreno 已提交
73
	constructor(id: string, label: string, @IWindowIPCService private windowService: IWindowIPCService) {
E
Erich Gamma 已提交
74 75 76
		super(id, label);
	}

77
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
78 79
		this.windowService.getWindow().close();

A
Alex Dima 已提交
80
		return TPromise.as(true);
E
Erich Gamma 已提交
81 82 83
	}
}

84
export class SwitchWindow extends QuickOpenAction {
85

J
Joao Moreno 已提交
86
	static ID = 'workbench.action.switchWindow';
B
Benjamin Pasero 已提交
87
	static LABEL = nls.localize('switchWindow', "Switch Window...");
88 89 90 91

	constructor(
		id: string,
		label: string,
92
		@IQuickOpenService quickOpenService: IQuickOpenService
93
	) {
94
		super(id, label, SWITCH_WINDOWS_PREFIX, quickOpenService);
95 96 97
	}
}

E
Erich Gamma 已提交
98 99
export class CloseFolderAction extends Action {

J
Joao Moreno 已提交
100 101
	static ID = 'workbench.action.closeFolder';
	static LABEL = nls.localize('closeFolder', "Close Folder");
E
Erich Gamma 已提交
102 103 104 105 106

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
B
Benjamin Pasero 已提交
107
		@IMessageService private messageService: IMessageService,
J
Joao Moreno 已提交
108
		@IWindowService private windowService: IWindowService
E
Erich Gamma 已提交
109 110 111 112
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
113
	run(): TPromise<void> {
B
Benjamin Pasero 已提交
114
		if (!this.contextService.hasWorkspace()) {
E
Erich Gamma 已提交
115
			this.messageService.show(Severity.Info, nls.localize('noFolderOpened', "There is currently no folder opened in this instance to close."));
J
Joao Moreno 已提交
116
			return TPromise.as(null);
E
Erich Gamma 已提交
117 118
		}

J
Joao Moreno 已提交
119
		return this.windowService.closeFolder();
E
Erich Gamma 已提交
120 121 122 123 124
	}
}

export class NewWindowAction extends Action {

J
Joao Moreno 已提交
125 126
	static ID = 'workbench.action.newWindow';
	static LABEL = nls.localize('newWindow', "New Window");
E
Erich Gamma 已提交
127

B
Benjamin Pasero 已提交
128 129 130
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
131
		@IWindowsService private windowsService: IWindowsService
B
Benjamin Pasero 已提交
132
	) {
E
Erich Gamma 已提交
133 134 135
		super(id, label);
	}

J
Joao Moreno 已提交
136 137
	run(): TPromise<void> {
		return this.windowsService.openNewWindow();
E
Erich Gamma 已提交
138 139 140 141 142
	}
}

export class ToggleFullScreenAction extends Action {

J
Joao Moreno 已提交
143 144
	static ID = 'workbench.action.toggleFullScreen';
	static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen");
E
Erich Gamma 已提交
145

J
Joao Moreno 已提交
146
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
147 148 149
		super(id, label);
	}

J
Joao Moreno 已提交
150 151
	run(): TPromise<void> {
		return this.windowService.toggleFullScreen();
E
Erich Gamma 已提交
152 153 154
	}
}

155 156
export class ToggleMenuBarAction extends Action {

J
Joao Moreno 已提交
157 158
	static ID = 'workbench.action.toggleMenuBar';
	static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar");
159

160
	private static menuBarVisibilityKey = 'window.menuBarVisibility';
161 162 163 164 165 166 167 168

	constructor(
		id: string,
		label: string,
		@IMessageService private messageService: IMessageService,
		@IConfigurationService private configurationService: IConfigurationService,
		@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
	) {
169 170 171
		super(id, label);
	}

172
	public run(): TPromise<any> {
173 174 175
		let currentVisibilityValue = this.configurationService.lookup<MenuBarVisibility>(ToggleMenuBarAction.menuBarVisibilityKey).value;
		if (typeof currentVisibilityValue !== 'string') {
			currentVisibilityValue = 'default';
176 177 178
		}

		let newVisibilityValue: string;
179
		if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') {
180 181
			newVisibilityValue = 'toggle';
		} else {
182
			newVisibilityValue = 'default';
183 184
		}

S
Sandeep Somavarapu 已提交
185
		this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMenuBarAction.menuBarVisibilityKey, value: newVisibilityValue });
186 187

		return TPromise.as(null);
188 189 190
	}
}

E
Erich Gamma 已提交
191 192
export class ToggleDevToolsAction extends Action {

J
Joao Moreno 已提交
193 194
	static ID = 'workbench.action.toggleDevTools';
	static LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools");
E
Erich Gamma 已提交
195

J
Joao Moreno 已提交
196
	constructor(id: string, label: string, @IWindowService private windowsService: IWindowService) {
E
Erich Gamma 已提交
197 198 199
		super(id, label);
	}

B
Benjamin Pasero 已提交
200
	public run(): TPromise<void> {
J
Joao Moreno 已提交
201
		return this.windowsService.toggleDevTools();
E
Erich Gamma 已提交
202 203 204
	}
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
export abstract class BaseZoomAction extends Action {
	private static SETTING_KEY = 'window.zoomLevel';

	constructor(
		id: string,
		label: string,
		@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
	) {
		super(id, label);
	}

	protected setConfiguredZoomLevel(level: number): void {
		let target = ConfigurationTarget.USER;
		if (typeof this.configurationService.lookup(BaseZoomAction.SETTING_KEY).workspace === 'number') {
			target = ConfigurationTarget.WORKSPACE;
		}

223 224
		level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels

B
Benjamin Pasero 已提交
225
		const applyZoom = () => {
226
			webFrame.setZoomLevel(level);
B
Benjamin Pasero 已提交
227
			browser.setZoomFactor(webFrame.getZoomFactor());
228 229 230 231
			// See https://github.com/Microsoft/vscode/issues/26151
			// Cannot be trusted because the webFrame might take some time
			// until it really applies the new zoom level
			browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
232 233
		};

S
Sandeep Somavarapu 已提交
234
		this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }, { donotNotifyError: true }).done(() => applyZoom(), error => applyZoom());
235 236 237 238
	}
}

export class ZoomInAction extends BaseZoomAction {
E
Erich Gamma 已提交
239 240

	public static ID = 'workbench.action.zoomIn';
B
Benjamin Pasero 已提交
241
	public static LABEL = nls.localize('zoomIn', "Zoom In");
E
Erich Gamma 已提交
242

243 244 245 246 247 248
	constructor(
		id: string,
		label: string,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
	) {
B
Benjamin Pasero 已提交
249
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
250 251
	}

252
	public run(): TPromise<boolean> {
253
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() + 1);
E
Erich Gamma 已提交
254

A
Alex Dima 已提交
255
		return TPromise.as(true);
E
Erich Gamma 已提交
256 257 258
	}
}

259
export class ZoomOutAction extends BaseZoomAction {
E
Erich Gamma 已提交
260 261

	public static ID = 'workbench.action.zoomOut';
B
Benjamin Pasero 已提交
262
	public static LABEL = nls.localize('zoomOut', "Zoom Out");
E
Erich Gamma 已提交
263

264 265
	constructor(
		id: string,
266 267 268
		label: string,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
269
	) {
B
Benjamin Pasero 已提交
270
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
271 272
	}

273
	public run(): TPromise<boolean> {
274
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
275

276
		return TPromise.as(true);
E
Erich Gamma 已提交
277 278 279
	}
}

280
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
281 282 283 284

	public static ID = 'workbench.action.zoomReset';
	public static LABEL = nls.localize('zoomReset', "Reset Zoom");

285 286 287
	constructor(
		id: string,
		label: string,
288 289
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
290
	) {
B
Benjamin Pasero 已提交
291
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
292 293
	}

294
	public run(): TPromise<boolean> {
295
		this.setConfiguredZoomLevel(0);
296

297
		return TPromise.as(true);
E
Erich Gamma 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
	}
}

/* Copied from loader.ts */
enum LoaderEventType {
	LoaderAvailable = 1,

	BeginLoadingScript = 10,
	EndLoadingScriptOK = 11,
	EndLoadingScriptError = 12,

	BeginInvokeFactory = 21,
	EndInvokeFactory = 22,

	NodeBeginEvaluatingScript = 31,
	NodeEndEvaluatingScript = 32,

	NodeBeginNativeRequire = 33,
	NodeEndNativeRequire = 34
}
318

E
Erich Gamma 已提交
319 320 321 322 323
interface ILoaderEvent {
	type: LoaderEventType;
	timestamp: number;
	detail: string;
}
324

E
Erich Gamma 已提交
325 326 327 328 329
export class ShowStartupPerformance extends Action {

	public static ID = 'workbench.action.appPerf';
	public static LABEL = nls.localize('appPerf', "Startup Performance");

330 331 332
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
333
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
334
		@ITimerService private timerService: ITimerService,
335
		@IEnvironmentService private environmentService: IEnvironmentService
336
	) {
E
Erich Gamma 已提交
337
		super(id, label);
338 339 340 341 342 343 344 345 346
	}

	public run(): TPromise<boolean> {

		// Show dev tools
		this.windowService.openDevTools();

		// Print to console
		setTimeout(() => {
347
			(<any>console).group('Startup Performance Measurement');
B
Benjamin Pasero 已提交
348 349 350 351 352
			const metrics: IStartupMetrics = this.timerService.startupMetrics;
			console.log(`OS: ${metrics.platform} (${metrics.release})`);
			console.log(`CPUs: ${metrics.cpus.model} (${metrics.cpus.count} x ${metrics.cpus.speed})`);
			console.log(`Memory (System): ${(metrics.totalmem / (1024 * 1024 * 1024)).toFixed(2)}GB (${(metrics.freemem / (1024 * 1024 * 1024)).toFixed(2)}GB free)`);
			console.log(`Memory (Process): ${(metrics.meminfo.workingSetSize / 1024).toFixed(2)}MB working set (${(metrics.meminfo.peakWorkingSetSize / 1024).toFixed(2)}MB peak, ${(metrics.meminfo.privateBytes / 1024).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / 1024).toFixed(2)}MB shared)`);
353
			console.log(`VM (likelyhood): ${metrics.isVMLikelyhood}%`);
B
Benjamin Pasero 已提交
354 355 356
			console.log(`Initial Startup: ${metrics.initialStartup}`);
			console.log(`Screen Reader Active: ${metrics.hasAccessibilitySupport}`);
			console.log(`Empty Workspace: ${metrics.emptyWorkbench}`);
357 358 359 360 361 362 363 364 365

			let nodeModuleLoadTime: number;
			let nodeModuleLoadDetails: any[];
			if (this.environmentService.performance) {
				const nodeModuleTimes = this.analyzeNodeModulesLoadTimes();
				nodeModuleLoadTime = nodeModuleTimes.duration;
				nodeModuleLoadDetails = nodeModuleTimes.table;
			}

B
Benjamin Pasero 已提交
366
			(<any>console).table(this.getStartupMetricsTable(nodeModuleLoadTime));
367

368 369 370 371 372 373 374
			if (this.environmentService.performance) {
				const data = this.analyzeLoaderStats();
				for (let type in data) {
					(<any>console).groupCollapsed(`Loader: ${type}`);
					(<any>console).table(data[type]);
					(<any>console).groupEnd();
				}
375
			}
376

377 378
			(<any>console).groupEnd();
		}, 1000);
379

380
		return TPromise.as(true);
E
Erich Gamma 已提交
381 382
	}

B
Benjamin Pasero 已提交
383
	private getStartupMetricsTable(nodeModuleLoadTime?: number): any[] {
384
		const table: any[] = [];
B
Benjamin Pasero 已提交
385
		const metrics: IStartupMetrics = this.timerService.startupMetrics;
386

B
Benjamin Pasero 已提交
387
		if (metrics.initialStartup) {
388 389
			table.push({ Topic: '[main] start => app.isReady', 'Took (ms)': metrics.timers.ellapsedAppReady });
			table.push({ Topic: '[main] app.isReady => window.loadUrl()', 'Took (ms)': metrics.timers.ellapsedWindowLoad });
E
Erich Gamma 已提交
390
		}
391

B
Benjamin Pasero 已提交
392 393
		table.push({ Topic: '[renderer] window.loadUrl() => begin to require(workbench.main.js)', 'Took (ms)': metrics.timers.ellapsedWindowLoadToRequire });
		table.push({ Topic: '[renderer] require(workbench.main.js)', 'Took (ms)': metrics.timers.ellapsedRequire });
394 395 396 397 398

		if (nodeModuleLoadTime) {
			table.push({ Topic: '[renderer] -> of which require() node_modules', 'Took (ms)': nodeModuleLoadTime });
		}

B
Benjamin Pasero 已提交
399 400 401 402
		table.push({ Topic: '[renderer] create extension host => extensions onReady()', 'Took (ms)': metrics.timers.ellapsedExtensions });
		table.push({ Topic: '[renderer] restore viewlet', 'Took (ms)': metrics.timers.ellapsedViewletRestore });
		table.push({ Topic: '[renderer] restore editor view state', 'Took (ms)': metrics.timers.ellapsedEditorRestore });
		table.push({ Topic: '[renderer] overall workbench load', 'Took (ms)': metrics.timers.ellapsedWorkbench });
403
		table.push({ Topic: '------------------------------------------------------' });
B
Benjamin Pasero 已提交
404 405
		table.push({ Topic: '[main, renderer] start => extensions ready', 'Took (ms)': metrics.timers.ellapsedExtensionsReady });
		table.push({ Topic: '[main, renderer] start => workbench ready', 'Took (ms)': metrics.ellapsed });
E
Erich Gamma 已提交
406

407
		return table;
E
Erich Gamma 已提交
408 409
	}

410
	private analyzeNodeModulesLoadTimes(): { table: any[], duration: number } {
411 412 413 414 415 416 417 418 419
		const stats = <ILoaderEvent[]>(<any>require).getStats();
		const result = [];

		let total = 0;

		for (let i = 0, len = stats.length; i < len; i++) {
			if (stats[i].type === LoaderEventType.NodeEndNativeRequire) {
				if (stats[i - 1].type === LoaderEventType.NodeBeginNativeRequire && stats[i - 1].detail === stats[i].detail) {
					const entry: any = {};
420
					const dur = (stats[i].timestamp - stats[i - 1].timestamp);
421
					entry['Event'] = 'nodeRequire ' + stats[i].detail;
422 423 424 425
					entry['Took (ms)'] = dur.toFixed(2);
					total += dur;
					entry['Start (ms)'] = '**' + stats[i - 1].timestamp.toFixed(2);
					entry['End (ms)'] = '**' + stats[i - 1].timestamp.toFixed(2);
426 427 428 429 430 431
					result.push(entry);
				}
			}
		}

		if (total > 0) {
432 433
			result.push({ Event: '------------------------------------------------------' });

434
			const entry: any = {};
435 436
			entry['Event'] = '[renderer] total require() node_modules';
			entry['Took (ms)'] = total.toFixed(2);
437 438 439 440 441
			entry['Start (ms)'] = '**';
			entry['End (ms)'] = '**';
			result.push(entry);
		}

442
		return { table: result, duration: Math.round(total) };
E
Erich Gamma 已提交
443
	}
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

	private analyzeLoaderStats(): { [type: string]: any[] } {
		const stats = <ILoaderEvent[]>(<any>require).getStats().slice(0).sort((a, b) => {
			if (a.detail < b.detail) {
				return -1;
			} else if (a.detail > b.detail) {
				return 1;
			} else if (a.type < b.type) {
				return -1;
			} else if (a.type > b.type) {
				return 1;
			} else {
				return 0;
			}
		});

		class Tick {

			public readonly duration: number;
			public readonly detail: string;

			constructor(public readonly start: ILoaderEvent, public readonly end: ILoaderEvent) {
				console.assert(start.detail === end.detail);

				this.duration = this.end.timestamp - this.start.timestamp;
				this.detail = start.detail;
			}

			toTableObject() {
				return {
					['Path']: this.start.detail,
					['Took (ms)']: this.duration.toFixed(2),
					// ['Start (ms)']: this.start.timestamp,
					// ['End (ms)']: this.end.timestamp
				};
			}

			static compareUsingStartTimestamp(a: Tick, b: Tick): number {
				if (a.start.timestamp < b.start.timestamp) {
					return -1;
				} else if (a.start.timestamp > b.start.timestamp) {
					return 1;
				} else {
					return 0;
				}
			}
		}

		const ticks: { [type: number]: Tick[] } = {
			[LoaderEventType.BeginLoadingScript]: [],
			[LoaderEventType.BeginInvokeFactory]: [],
			[LoaderEventType.NodeBeginEvaluatingScript]: [],
			[LoaderEventType.NodeBeginNativeRequire]: [],
		};

		for (let i = 1; i < stats.length - 1; i++) {
			const stat = stats[i];
			const nextStat = stats[i + 1];

			if (nextStat.type - stat.type > 2) {
				//bad?!
				break;
			}

			i += 1;
			ticks[stat.type].push(new Tick(stat, nextStat));
		}

		ticks[LoaderEventType.BeginInvokeFactory].sort(Tick.compareUsingStartTimestamp);
		ticks[LoaderEventType.BeginInvokeFactory].sort(Tick.compareUsingStartTimestamp);
		ticks[LoaderEventType.NodeBeginEvaluatingScript].sort(Tick.compareUsingStartTimestamp);
		ticks[LoaderEventType.NodeBeginNativeRequire].sort(Tick.compareUsingStartTimestamp);

		const ret = {
			'Load Script': ticks[LoaderEventType.BeginLoadingScript].map(t => t.toTableObject()),
			'(Node) Load Script': ticks[LoaderEventType.NodeBeginNativeRequire].map(t => t.toTableObject()),
			'Eval Script': ticks[LoaderEventType.BeginInvokeFactory].map(t => t.toTableObject()),
			'(Node) Eval Script': ticks[LoaderEventType.NodeBeginEvaluatingScript].map(t => t.toTableObject()),
		};

		function total(ticks: Tick[]): number {
			let sum = 0;
			for (const tick of ticks) {
				sum += tick.duration;
			}
			return sum;
		}

		// totals
		ret['Load Script'].push({
			['Path']: 'TOTAL TIME',
			['Took (ms)']: total(ticks[LoaderEventType.BeginLoadingScript]).toFixed(2)
		});
		ret['Eval Script'].push({
			['Path']: 'TOTAL TIME',
			['Took (ms)']: total(ticks[LoaderEventType.BeginInvokeFactory]).toFixed(2)
		});
		ret['(Node) Load Script'].push({
			['Path']: 'TOTAL TIME',
			['Took (ms)']: total(ticks[LoaderEventType.NodeBeginNativeRequire]).toFixed(2)
		});
		ret['(Node) Eval Script'].push({
			['Path']: 'TOTAL TIME',
			['Took (ms)']: total(ticks[LoaderEventType.NodeBeginEvaluatingScript]).toFixed(2)
		});

		return ret;
	}
E
Erich Gamma 已提交
552 553 554 555
}

export class ReloadWindowAction extends Action {

556 557
	static ID = 'workbench.action.reloadWindow';
	static LABEL = nls.localize('reloadWindow', "Reload Window");
E
Erich Gamma 已提交
558

559 560 561
	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
562
		@IWindowService private windowService: IWindowService
563
	) {
E
Erich Gamma 已提交
564 565 566
		super(id, label);
	}

567 568
	run(): TPromise<boolean> {
		return this.windowService.reloadWindow().then(() => true);
E
Erich Gamma 已提交
569 570 571 572 573 574 575 576 577 578 579
	}
}

export class OpenRecentAction extends Action {

	public static ID = 'workbench.action.openRecent';
	public static LABEL = nls.localize('openRecent', "Open Recent");

	constructor(
		id: string,
		label: string,
580
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
581
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
582 583
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
E
Erich Gamma 已提交
584 585 586 587
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
588 589 590
	public run(): TPromise<void> {
		return this.windowService.getRecentlyOpen()
			.then(({ files, folders }) => this.openRecent(files, folders));
B
Benjamin Pasero 已提交
591 592 593
	}

	private openRecent(recentFiles: string[], recentFolders: string[]): void {
B
Benjamin Pasero 已提交
594
		function toPick(path: string, separator: ISeparator, isFolder: boolean): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
595
			return {
B
Benjamin Pasero 已提交
596 597
				resource: URI.file(path),
				isFolder,
B
Benjamin Pasero 已提交
598 599 600
				label: paths.basename(path),
				description: paths.dirname(path),
				separator,
B
Benjamin Pasero 已提交
601
				run: context => runPick(path, context)
B
Benjamin Pasero 已提交
602 603 604
			};
		}

B
Benjamin Pasero 已提交
605
		const runPick = (path: string, context: IEntryRunContext) => {
606 607
			const forceNewWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;
			this.windowsService.openWindow([path], { forceNewWindow });
608
		};
B
Benjamin Pasero 已提交
609

B
Benjamin Pasero 已提交
610 611
		const folderPicks: IFilePickOpenEntry[] = recentFolders.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('folders', "folders") } : void 0, true));
		const filePicks: IFilePickOpenEntry[] = recentFiles.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('files', "files"), border: true } : void 0, false));
B
Benjamin Pasero 已提交
612

B
Benjamin Pasero 已提交
613
		const hasWorkspace = this.contextService.hasWorkspace();
B
Benjamin Pasero 已提交
614 615 616 617 618 619

		this.quickOpenService.pick(folderPicks.concat(...filePicks), {
			autoFocus: { autoFocusFirstEntry: !hasWorkspace, autoFocusSecondEntry: hasWorkspace },
			placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select a path (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select a path to open (hold Ctrl-key to open in new window)"),
			matchOnDescription: true
		}).done(null, errors.onUnexpectedError);
E
Erich Gamma 已提交
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
	}
}

export class CloseMessagesAction extends Action {

	public static ID = 'workbench.action.closeMessages';
	public static LABEL = nls.localize('closeMessages', "Close Notification Messages");

	constructor(
		id: string,
		label: string,
		@IMessageService private messageService: IMessageService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
	}

637
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
638 639 640 641 642 643 644 645 646 647

		// Close any Message if visible
		this.messageService.hideAll();

		// Restore focus if we got an editor
		const editor = this.editorService.getActiveEditor();
		if (editor) {
			editor.focus();
		}

648
		return TPromise.as(true);
E
Erich Gamma 已提交
649
	}
650 651
}

B
Benjamin Pasero 已提交
652 653 654 655 656 657 658 659 660
export class ReportIssueAction extends Action {

	public static ID = 'workbench.action.reportIssues';
	public static LABEL = nls.localize('reportIssues', "Report Issues");

	constructor(
		id: string,
		label: string,
		@IIntegrityService private integrityService: IIntegrityService,
B
Benjamin Pasero 已提交
661
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService
B
Benjamin Pasero 已提交
662 663 664 665
	) {
		super(id, label);
	}

666 667 668 669 670 671 672 673 674 675 676
	private _optimisticIsPure(): TPromise<boolean> {
		let isPure = true;
		let integrityPromise = this.integrityService.isPure().then(res => {
			isPure = res.isPure;
		});

		return TPromise.any([TPromise.timeout(100), integrityPromise]).then(() => {
			return isPure;
		});
	}

B
Benjamin Pasero 已提交
677
	public run(): TPromise<boolean> {
678
		return this._optimisticIsPure().then(isPure => {
B
Benjamin Pasero 已提交
679
			return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
680
				const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions);
B
Benjamin Pasero 已提交
681

B
Benjamin Pasero 已提交
682
				window.open(issueUrl);
B
Benjamin Pasero 已提交
683

B
Benjamin Pasero 已提交
684 685
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
686 687 688
		});
	}

J
Johannes Rieken 已提交
689
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[]): string {
C
Christof Marti 已提交
690
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
691 692 693 694 695
		const osVersion = `${os.type()} ${os.arch()} ${os.release()}`;
		const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&';
		const body = encodeURIComponent(
			`- VSCode Version: ${name} ${version}${isPure ? '' : ' **[Unsupported]**'} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})
- OS Version: ${osVersion}
B
Benjamin Pasero 已提交
696
- Extensions: ${this.generateExtensionTable(extensions)}
697
---
B
Benjamin Pasero 已提交
698 699 700 701 702 703 704 705 706

Steps to Reproduce:

1.
2.`
		);

		return `${baseUrl}${queryStringPrefix}body=${body}`;
	}
707 708

	private generateExtensionTable(extensions: ILocalExtension[]): string {
B
Benjamin Pasero 已提交
709 710 711 712
		if (!extensions.length) {
			return 'none';
		}

713 714
		let tableHeader = `|Extension|Author|Version|
|---|---|---|`;
715
		const table = extensions.map(e => {
716
			return `|${e.manifest.name}|${e.manifest.publisher}|${e.manifest.version}|`;
717 718
		}).join('\n');

719
		const extensionTable = `
B
Benjamin Pasero 已提交
720 721 722 723

${tableHeader}\n${table};

`;
724 725 726
		// 2000 chars is browsers de-facto limit for URLs, 400 chars are allowed for other string parts of the issue URL
		// http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
		if (encodeURIComponent(extensionTable).length > 1600) {
727
			return 'the listing length exceeds browsers\' URL characters limit';
728 729 730
		}

		return extensionTable;
731
	}
B
Benjamin Pasero 已提交
732 733
}

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
export class ReportPerformanceIssueAction extends Action {

	public static ID = 'workbench.action.reportPerformanceIssue';
	public static LABEL = nls.localize('reportPerformanceIssue', "Report Performance Issue");

	constructor(
		id: string,
		label: string,
		@IIntegrityService private integrityService: IIntegrityService,
		@IEnvironmentService private environmentService: IEnvironmentService,
		@ITimerService private timerService: ITimerService
	) {
		super(id, label);
	}

749
	public run(appendix?: string): TPromise<boolean> {
750
		return this.integrityService.isPure().then(res => {
751
			const issueUrl = this.generatePerformanceIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, appendix);
752 753 754 755 756 757 758

			window.open(issueUrl);

			return TPromise.as(true);
		});
	}

759 760 761 762 763 764 765 766 767
	private generatePerformanceIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, appendix?: string): string {

		if (!appendix) {
			appendix = `Additional Steps to Reproduce (if any):

1.
2.`;
		}

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
		let nodeModuleLoadTime: number;
		if (this.environmentService.performance) {
			nodeModuleLoadTime = this.computeNodeModulesLoadTime();
		}

		const metrics: IStartupMetrics = this.timerService.startupMetrics;

		const osVersion = `${os.type()} ${os.arch()} ${os.release()}`;
		const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&';
		const body = encodeURIComponent(
			`- VSCode Version: <code>${name} ${version}${isPure ? '' : ' **[Unsupported]**'} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})</code>
- OS Version: <code>${osVersion}</code>
- CPUs: <code>${metrics.cpus.model} (${metrics.cpus.count} x ${metrics.cpus.speed})</code>
- Memory (System): <code>${(metrics.totalmem / (1024 * 1024 * 1024)).toFixed(2)}GB (${(metrics.freemem / (1024 * 1024 * 1024)).toFixed(2)}GB free)</code>
- Memory (Process): <code>${(metrics.meminfo.workingSetSize / 1024).toFixed(2)}MB working set (${(metrics.meminfo.peakWorkingSetSize / 1024).toFixed(2)}MB peak, ${(metrics.meminfo.privateBytes / 1024).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / 1024).toFixed(2)}MB shared)</code>
- Load (avg): <code>${metrics.loadavg.map(l => Math.round(l)).join(', ')}</code>
784
- VM: <code>${metrics.isVMLikelyhood}%</code>
785
- Initial Startup: <code>${metrics.initialStartup ? 'yes' : 'no'}</code>
786
- Screen Reader: <code>${metrics.hasAccessibilitySupport ? 'yes' : 'no'}</code>
787 788 789 790 791 792 793
- Empty Workspace: <code>${metrics.emptyWorkbench ? 'yes' : 'no'}</code>
- Timings:

${this.generatePerformanceTable(nodeModuleLoadTime)}

---

794
${appendix}`
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
		);

		return `${baseUrl}${queryStringPrefix}body=${body}`;
	}

	private computeNodeModulesLoadTime(): number {
		const stats = <ILoaderEvent[]>(<any>require).getStats();
		let total = 0;

		for (let i = 0, len = stats.length; i < len; i++) {
			if (stats[i].type === LoaderEventType.NodeEndNativeRequire) {
				if (stats[i - 1].type === LoaderEventType.NodeBeginNativeRequire && stats[i - 1].detail === stats[i].detail) {
					const dur = (stats[i].timestamp - stats[i - 1].timestamp);
					total += dur;
				}
			}
		}

		return Math.round(total);
	}

	private generatePerformanceTable(nodeModuleLoadTime?: number): string {
		let tableHeader = `|Component|Task|Time (ms)|
|---|---|---|`;

		const table = this.getStartupMetricsTable(nodeModuleLoadTime).map(e => {
821
			return `|${e.component}|${e.task}|${e.time}|`;
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
		}).join('\n');

		return `${tableHeader}\n${table}`;
	}

	private getStartupMetricsTable(nodeModuleLoadTime?: number): { component: string, task: string; time: number; }[] {
		const table: any[] = [];
		const metrics: IStartupMetrics = this.timerService.startupMetrics;

		if (metrics.initialStartup) {
			table.push({ component: 'main', task: 'start => app.isReady', time: metrics.timers.ellapsedAppReady });
			table.push({ component: 'main', task: 'app.isReady => window.loadUrl()', time: metrics.timers.ellapsedWindowLoad });
		}

		table.push({ component: 'renderer', task: 'window.loadUrl() => begin to require(workbench.main.js)', time: metrics.timers.ellapsedWindowLoadToRequire });
		table.push({ component: 'renderer', task: 'require(workbench.main.js)', time: metrics.timers.ellapsedRequire });

		if (nodeModuleLoadTime) {
			table.push({ component: 'renderer', task: '-> of which require() node_modules', time: nodeModuleLoadTime });
		}

		table.push({ component: 'renderer', task: 'create extension host => extensions onReady()', time: metrics.timers.ellapsedExtensions });
		table.push({ component: 'renderer', task: 'restore viewlet', time: metrics.timers.ellapsedViewletRestore });
		table.push({ component: 'renderer', task: 'restore editor view state', time: metrics.timers.ellapsedEditorRestore });
		table.push({ component: 'renderer', task: 'overall workbench load', time: metrics.timers.ellapsedWorkbench });
		table.push({ component: 'main + renderer', task: 'start => extensions ready', time: metrics.timers.ellapsedExtensionsReady });
		table.push({ component: 'main + renderer', task: 'start => workbench ready', time: metrics.ellapsed });

		return table;
	}
}

854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
export class KeybindingsReferenceAction extends Action {

	public static ID = 'workbench.action.keybindingsReference';
	public static LABEL = nls.localize('keybindingsReference', "Keyboard Shortcuts Reference");

	private static URL = isLinux ? product.keyboardShortcutsUrlLinux : isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin;
	public static AVAILABLE = !!KeybindingsReferenceAction.URL;

	constructor(
		id: string,
		label: string
	) {
		super(id, label);
	}

	public run(): TPromise<void> {
		window.open(KeybindingsReferenceAction.URL);
		return null;
	}
}

C
Christof Marti 已提交
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
export class OpenDocumentationUrlAction extends Action {

	public static ID = 'workbench.action.openDocumentationUrl';
	public static LABEL = nls.localize('openDocumentationUrl', "Documentation");

	private static URL = product.documentationUrl;
	public static AVAILABLE = !!OpenDocumentationUrlAction.URL;

	constructor(
		id: string,
		label: string
	) {
		super(id, label);
	}

	public run(): TPromise<void> {
		window.open(OpenDocumentationUrlAction.URL);
		return null;
	}
}

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
export class OpenIntroductoryVideosUrlAction extends Action {

	public static ID = 'workbench.action.openIntroductoryVideosUrl';
	public static LABEL = nls.localize('openIntroductoryVideosUrl', "Introductory Videos");

	private static URL = product.introductoryVideosUrl;
	public static AVAILABLE = !!OpenIntroductoryVideosUrlAction.URL;

	constructor(
		id: string,
		label: string
	) {
		super(id, label);
	}

	public run(): TPromise<void> {
		window.open(OpenIntroductoryVideosUrlAction.URL);
		return null;
	}
915
}
916

917 918 919 920 921 922 923 924 925 926 927 928
export class ToggleSharedProcessAction extends Action {

	static ID = 'workbench.action.toggleSharedProcess';
	static LABEL = nls.localize('toggleSharedProcess', "Toggle Shared Process");

	constructor(id: string, label: string, @IWindowsService private windowsService: IWindowsService) {
		super(id, label);
	}

	run(): TPromise<void> {
		return this.windowsService.toggleSharedProcess();
	}
929 930
}

S
sj.hwang 已提交
931 932 933 934
enum Direction {
	Next,
	Previous,
}
935

S
sj.hwang 已提交
936
export abstract class BaseNavigationAction extends Action {
937

938
	constructor(
S
sj.hwang 已提交
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
		id: string,
		label: string,
		@IEditorGroupService protected groupService: IEditorGroupService,
		@IPanelService protected panelService: IPanelService,
		@IPartService protected partService: IPartService,
		@IViewletService protected viewletService: IViewletService
	) {
		super(id, label);
	}

	public run(): TPromise<any> {
		const isEditorFocus = this.partService.hasFocus(Parts.EDITOR_PART);
		const isPanelFocus = this.partService.hasFocus(Parts.PANEL_PART);
		const isSidebarFocus = this.partService.hasFocus(Parts.SIDEBAR_PART);

		const isEditorGroupVertical = this.groupService.getGroupOrientation() === 'vertical';
		const isSidebarPositionLeft = this.partService.getSideBarPosition() === SidebarPosition.LEFT;

		if (isEditorFocus) {
			return this.navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft);
959 960
		}

S
sj.hwang 已提交
961 962
		if (isPanelFocus) {
			return this.navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft);
963 964
		}

S
sj.hwang 已提交
965 966
		if (isSidebarFocus) {
			return this.navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft);
967 968
		}

S
sj.hwang 已提交
969
		return TPromise.as(false);
970 971
	}

S
sj.hwang 已提交
972 973
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
974 975
	}

S
sj.hwang 已提交
976 977
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
978 979
	}

S
sj.hwang 已提交
980 981
	protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
982 983
	}

S
sj.hwang 已提交
984 985 986
	protected navigateToPanel(): TPromise<any> {
		if (!this.partService.isVisible(Parts.PANEL_PART)) {
			return TPromise.as(false);
987 988
		}

S
sj.hwang 已提交
989 990
		const activePanelId = this.panelService.getActivePanel().getId();
		return this.panelService.openPanel(activePanelId, true);
991 992
	}

S
sj.hwang 已提交
993 994 995
	protected navigateToSidebar(): TPromise<any> {
		if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
			return TPromise.as(false);
996 997
		}

S
sj.hwang 已提交
998 999
		const activeViewletId = this.viewletService.getActiveViewlet().getId();
		return this.viewletService.openViewlet(activeViewletId, true);
1000 1001
	}

S
sj.hwang 已提交
1002
	protected navigateAcrossEditorGroup(direction): TPromise<any> {
1003 1004
		const model = this.groupService.getStacksModel();
		const currentPosition = model.positionOfGroup(model.activeGroup);
S
sj.hwang 已提交
1005
		const nextPosition = direction === Direction.Next ? currentPosition + 1 : currentPosition - 1;
1006 1007 1008 1009 1010 1011 1012 1013 1014

		if (nextPosition < 0 || nextPosition > model.groups.length - 1) {
			return TPromise.as(false);
		}

		this.groupService.focusGroup(nextPosition);
		return TPromise.as(true);
	}

1015
	protected navigateToLastActiveGroup(): TPromise<any> {
S
sj.hwang 已提交
1016
		const model = this.groupService.getStacksModel();
1017 1018 1019
		const lastActiveGroup = model.activeGroup;
		this.groupService.focusGroup(lastActiveGroup);
		return TPromise.as(true);
1020 1021
	}

1022 1023 1024
	protected navigateToFirstEditorGroup(): TPromise<any> {
		this.groupService.focusGroup(0);
		return TPromise.as(true);
1025 1026
	}

1027
	protected navigateToLastEditorGroup(): TPromise<any> {
S
sj.hwang 已提交
1028
		const model = this.groupService.getStacksModel();
1029 1030 1031
		const lastEditorGroupPosition = model.groups.length - 1;
		this.groupService.focusGroup(lastEditorGroupPosition);
		return TPromise.as(true);
1032 1033
	}
}
S
sj.hwang 已提交
1034 1035 1036 1037

export class NavigateLeftAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateLeft';
1038
	public static LABEL = nls.localize('navigateLeft', "Move to the View on the Left");
S
sj.hwang 已提交
1039 1040 1041 1042 1043 1044 1045 1046 1047

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1048
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1049 1050 1051
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
1052
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1053 1054 1055 1056
			if (isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
S
sj.hwang 已提交
1057
		}
S
sj.hwang 已提交
1058
		return this.navigateAcrossEditorGroup(Direction.Previous)
1059 1060 1061 1062 1063 1064
			.then(didNavigate => {
				if (!didNavigate && isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
S
sj.hwang 已提交
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
	}

	protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isSidebarPositionLeft) {
			return this.navigateToSidebar();
		}
		return TPromise.as(false);
	}

	protected navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isSidebarPositionLeft) {
			return TPromise.as(false);
		}
		if (isEditorGroupVertical) {
1079
			return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1080
		}
1081
		return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1082 1083
	}
}
1084 1085 1086 1087

export class NavigateRightAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateRight';
1088
	public static LABEL = nls.localize('navigateRight', "Move to the View on the Right");
1089 1090 1091 1092 1093 1094 1095 1096 1097

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1098
		super(id, label, groupService, panelService, partService, viewletService);
1099 1100 1101
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
1102
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1103 1104 1105 1106
			if (!isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
1107
		}
S
sj.hwang 已提交
1108
		return this.navigateAcrossEditorGroup(Direction.Next)
1109 1110 1111 1112 1113 1114
			.then(didNavigate => {
				if (!didNavigate && !isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
	}

	protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (!isSidebarPositionLeft) {
			return this.navigateToSidebar();
		}
		return TPromise.as(false);
	}

	protected navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (!isSidebarPositionLeft) {
			return TPromise.as(false);
		}
		if (isEditorGroupVertical) {
1129
			return this.navigateToFirstEditorGroup();
1130
		}
1131
		return this.navigateToLastActiveGroup();
1132 1133
	}
}
S
sj.hwang 已提交
1134 1135 1136 1137

export class NavigateUpAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateUp';
1138
	public static LABEL = nls.localize('navigateUp', "Move to the View Above");
S
sj.hwang 已提交
1139 1140 1141 1142 1143 1144 1145 1146 1147

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1148
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1149 1150 1151 1152 1153 1154
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return TPromise.as(false);
		}
S
sj.hwang 已提交
1155
		return this.navigateAcrossEditorGroup(Direction.Previous);
S
sj.hwang 已提交
1156 1157 1158 1159
	}

	protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
1160
			return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1161
		}
1162
		return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1163 1164
	}
}
S
sj.hwang 已提交
1165 1166 1167 1168

export class NavigateDownAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateDown';
1169
	public static LABEL = nls.localize('navigateDown', "Move to the View Below");
S
sj.hwang 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1179
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1180 1181 1182 1183 1184 1185
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return this.navigateToPanel();
		}
S
sj.hwang 已提交
1186
		return this.navigateAcrossEditorGroup(Direction.Next)
1187 1188 1189 1190 1191 1192
			.then(didNavigate => {
				if (didNavigate) {
					return TPromise.as(true);
				}
				return this.navigateToPanel();
			});
S
sj.hwang 已提交
1193 1194
	}
}
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214

// Resize focused view actions
export abstract class BaseResizeViewAction extends Action {

	// This is a media-size percentage
	protected static RESIZE_INCREMENT = 6.5;

	constructor(
		id: string,
		label: string,
		@IPartService protected partService: IPartService
	) {
		super(id, label);
	}

	protected resizePart(sizeChange: number): void {
		const isEditorFocus = this.partService.hasFocus(Parts.EDITOR_PART);
		const isSidebarFocus = this.partService.hasFocus(Parts.SIDEBAR_PART);
		const isPanelFocus = this.partService.hasFocus(Parts.PANEL_PART);

B
Benjamin Pasero 已提交
1215
		let part: Parts;
1216
		if (isSidebarFocus) {
B
Benjamin Pasero 已提交
1217 1218 1219 1220 1221
			part = Parts.SIDEBAR_PART;
		} else if (isPanelFocus) {
			part = Parts.PANEL_PART;
		} else if (isEditorFocus) {
			part = Parts.EDITOR_PART;
1222
		}
B
Benjamin Pasero 已提交
1223 1224 1225

		if (part) {
			this.partService.resizePart(part, sizeChange);
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
		}
	}
}

export class IncreaseViewSizeAction extends BaseResizeViewAction {

	public static ID = 'workbench.action.increaseViewSize';
	public static LABEL = nls.localize('increaseViewSize', "Increase Current View Size");

	constructor(
		id: string,
		label: string,
		@IPartService partService: IPartService
	) {
		super(id, label, partService);
	}

	public run(): TPromise<boolean> {
		this.resizePart(BaseResizeViewAction.RESIZE_INCREMENT);
		return TPromise.as(true);
	}
}

export class DecreaseViewSizeAction extends BaseResizeViewAction {

	public static ID = 'workbench.action.decreaseViewSize';
	public static LABEL = nls.localize('decreaseViewSize', "Decrease Current View Size");

	constructor(
		id: string,
		label: string,
		@IPartService partService: IPartService

	) {
		super(id, label, partService);
	}

	public run(): TPromise<boolean> {
		this.resizePart(-BaseResizeViewAction.RESIZE_INCREMENT);
		return TPromise.as(true);
	}
}