actions.ts 41.1 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';
E
Erich Gamma 已提交
37

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

41 42
// --- actions

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

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

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

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

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

export class CloseWindowAction extends Action {

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

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

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

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

82
export class SwitchWindow extends Action {
83

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

	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
90
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
91
		@IWindowService private windowService: IWindowService,
92 93 94 95 96
		@IQuickOpenService private quickOpenService: IQuickOpenService
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
97 98
	run(): TPromise<void> {
		const currentWindowId = this.windowService.getCurrentWindowId();
99

J
Joao Moreno 已提交
100 101 102 103 104 105 106 107 108 109
		return this.windowsService.getWindows().then(workspaces => {
			const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window");
			const picks = workspaces.map(w => ({
				label: w.title,
				description: (currentWindowId === w.id) ? nls.localize('current', "Current Window") : void 0,
				run: () => this.windowsService.showWindow(w.id)
			}));

			this.quickOpenService.pick(picks, { placeHolder });
		});
110 111 112
	}
}

E
Erich Gamma 已提交
113 114
export class CloseFolderAction extends Action {

J
Joao Moreno 已提交
115 116
	static ID = 'workbench.action.closeFolder';
	static LABEL = nls.localize('closeFolder', "Close Folder");
E
Erich Gamma 已提交
117 118 119 120 121

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
B
Benjamin Pasero 已提交
122
		@IMessageService private messageService: IMessageService,
J
Joao Moreno 已提交
123
		@IWindowService private windowService: IWindowService
E
Erich Gamma 已提交
124 125 126 127
	) {
		super(id, label);
	}

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

J
Joao Moreno 已提交
134
		return this.windowService.closeFolder();
E
Erich Gamma 已提交
135 136 137 138 139
	}
}

export class NewWindowAction extends Action {

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

B
Benjamin Pasero 已提交
143 144 145
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
146
		@IWindowsService private windowsService: IWindowsService
B
Benjamin Pasero 已提交
147
	) {
E
Erich Gamma 已提交
148 149 150
		super(id, label);
	}

J
Joao Moreno 已提交
151 152
	run(): TPromise<void> {
		return this.windowsService.openNewWindow();
E
Erich Gamma 已提交
153 154 155 156 157
	}
}

export class ToggleFullScreenAction extends Action {

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

J
Joao Moreno 已提交
161
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
162 163 164
		super(id, label);
	}

J
Joao Moreno 已提交
165 166
	run(): TPromise<void> {
		return this.windowService.toggleFullScreen();
E
Erich Gamma 已提交
167 168 169
	}
}

170 171
export class ToggleMenuBarAction extends Action {

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

175
	private static menuBarVisibilityKey = 'window.menuBarVisibility';
176 177 178 179 180 181 182 183

	constructor(
		id: string,
		label: string,
		@IMessageService private messageService: IMessageService,
		@IConfigurationService private configurationService: IConfigurationService,
		@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
	) {
184 185 186
		super(id, label);
	}

187
	public run(): TPromise<any> {
188 189 190
		let currentVisibilityValue = this.configurationService.lookup<MenuBarVisibility>(ToggleMenuBarAction.menuBarVisibilityKey).value;
		if (typeof currentVisibilityValue !== 'string') {
			currentVisibilityValue = 'default';
191 192 193
		}

		let newVisibilityValue: string;
194
		if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') {
195 196
			newVisibilityValue = 'toggle';
		} else {
197
			newVisibilityValue = 'default';
198 199
		}

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

		return TPromise.as(null);
203 204 205
	}
}

E
Erich Gamma 已提交
206 207
export class ToggleDevToolsAction extends Action {

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

J
Joao Moreno 已提交
211
	constructor(id: string, label: string, @IWindowService private windowsService: IWindowService) {
E
Erich Gamma 已提交
212 213 214
		super(id, label);
	}

B
Benjamin Pasero 已提交
215
	public run(): TPromise<void> {
J
Joao Moreno 已提交
216
		return this.windowsService.toggleDevTools();
E
Erich Gamma 已提交
217 218 219
	}
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
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;
		}

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

B
Benjamin Pasero 已提交
240
		const applyZoom = () => {
241
			webFrame.setZoomLevel(level);
B
Benjamin Pasero 已提交
242
			browser.setZoomFactor(webFrame.getZoomFactor());
243 244 245 246
			// 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);
247 248
		};

B
Benjamin Pasero 已提交
249
		this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom());
250 251 252 253
	}
}

export class ZoomInAction extends BaseZoomAction {
E
Erich Gamma 已提交
254 255

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

258 259 260 261 262 263
	constructor(
		id: string,
		label: string,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
	) {
B
Benjamin Pasero 已提交
264
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
265 266
	}

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

A
Alex Dima 已提交
270
		return TPromise.as(true);
E
Erich Gamma 已提交
271 272 273
	}
}

274
export class ZoomOutAction extends BaseZoomAction {
E
Erich Gamma 已提交
275 276

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

279 280
	constructor(
		id: string,
281 282 283
		label: string,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
284
	) {
B
Benjamin Pasero 已提交
285
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
286 287
	}

288
	public run(): TPromise<boolean> {
289
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
290

291
		return TPromise.as(true);
E
Erich Gamma 已提交
292 293 294
	}
}

295
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
296 297 298 299

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

300 301 302
	constructor(
		id: string,
		label: string,
303 304
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
305
	) {
B
Benjamin Pasero 已提交
306
		super(id, label, configurationService, configurationEditingService);
E
Erich Gamma 已提交
307 308
	}

309
	public run(): TPromise<boolean> {
310
		this.setConfiguredZoomLevel(0);
311

312
		return TPromise.as(true);
E
Erich Gamma 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
	}
}

/* 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
}
333

E
Erich Gamma 已提交
334 335 336 337 338
interface ILoaderEvent {
	type: LoaderEventType;
	timestamp: number;
	detail: string;
}
339

E
Erich Gamma 已提交
340 341 342 343 344
export class ShowStartupPerformance extends Action {

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

345 346 347
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
348
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
349
		@ITimerService private timerService: ITimerService,
350
		@IEnvironmentService private environmentService: IEnvironmentService
351
	) {
E
Erich Gamma 已提交
352
		super(id, label);
353 354 355 356 357 358 359 360 361
	}

	public run(): TPromise<boolean> {

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

		// Print to console
		setTimeout(() => {
362
			(<any>console).group('Startup Performance Measurement');
B
Benjamin Pasero 已提交
363 364 365 366 367
			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)`);
368
			console.log(`VM (likelyhood): ${metrics.isVMLikelyhood}%`);
B
Benjamin Pasero 已提交
369 370 371
			console.log(`Initial Startup: ${metrics.initialStartup}`);
			console.log(`Screen Reader Active: ${metrics.hasAccessibilitySupport}`);
			console.log(`Empty Workspace: ${metrics.emptyWorkbench}`);
372 373 374 375 376 377 378 379 380

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

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

383 384 385 386 387 388 389
			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();
				}
390
			}
391

392 393
			(<any>console).groupEnd();
		}, 1000);
394

395
		return TPromise.as(true);
E
Erich Gamma 已提交
396 397
	}

B
Benjamin Pasero 已提交
398
	private getStartupMetricsTable(nodeModuleLoadTime?: number): any[] {
399
		const table: any[] = [];
B
Benjamin Pasero 已提交
400
		const metrics: IStartupMetrics = this.timerService.startupMetrics;
401

B
Benjamin Pasero 已提交
402
		if (metrics.initialStartup) {
403 404
			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 已提交
405
		}
406

B
Benjamin Pasero 已提交
407 408
		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 });
409 410 411 412 413

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

B
Benjamin Pasero 已提交
414 415 416 417
		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 });
418
		table.push({ Topic: '------------------------------------------------------' });
B
Benjamin Pasero 已提交
419 420
		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 已提交
421

422
		return table;
E
Erich Gamma 已提交
423 424
	}

425
	private analyzeNodeModulesLoadTimes(): { table: any[], duration: number } {
426 427 428 429 430 431 432 433 434
		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 = {};
435
					const dur = (stats[i].timestamp - stats[i - 1].timestamp);
436
					entry['Event'] = 'nodeRequire ' + stats[i].detail;
437 438 439 440
					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);
441 442 443 444 445 446
					result.push(entry);
				}
			}
		}

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

449
			const entry: any = {};
450 451
			entry['Event'] = '[renderer] total require() node_modules';
			entry['Took (ms)'] = total.toFixed(2);
452 453 454 455 456
			entry['Start (ms)'] = '**';
			entry['End (ms)'] = '**';
			result.push(entry);
		}

457
		return { table: result, duration: Math.round(total) };
E
Erich Gamma 已提交
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 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566

	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 已提交
567 568 569 570
}

export class ReloadWindowAction extends Action {

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

574 575 576
	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
577
		@IWindowService private windowService: IWindowService
578
	) {
E
Erich Gamma 已提交
579 580 581
		super(id, label);
	}

582 583
	run(): TPromise<boolean> {
		return this.windowService.reloadWindow().then(() => true);
E
Erich Gamma 已提交
584 585 586 587 588 589 590 591 592 593 594
	}
}

export class OpenRecentAction extends Action {

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

	constructor(
		id: string,
		label: string,
595
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
596
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
597 598
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
E
Erich Gamma 已提交
599 600 601 602
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
603 604 605
	public run(): TPromise<void> {
		return this.windowService.getRecentlyOpen()
			.then(({ files, folders }) => this.openRecent(files, folders));
B
Benjamin Pasero 已提交
606 607 608
	}

	private openRecent(recentFiles: string[], recentFolders: string[]): void {
B
Benjamin Pasero 已提交
609
		function toPick(path: string, separator: ISeparator, isFolder: boolean): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
610
			return {
B
Benjamin Pasero 已提交
611 612
				resource: URI.file(path),
				isFolder,
B
Benjamin Pasero 已提交
613 614 615
				label: paths.basename(path),
				description: paths.dirname(path),
				separator,
B
Benjamin Pasero 已提交
616
				run: context => runPick(path, context)
B
Benjamin Pasero 已提交
617 618 619
			};
		}

B
Benjamin Pasero 已提交
620
		const runPick = (path: string, context: IEntryRunContext) => {
621 622
			const forceNewWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;
			this.windowsService.openWindow([path], { forceNewWindow });
623
		};
B
Benjamin Pasero 已提交
624

B
Benjamin Pasero 已提交
625 626
		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 已提交
627

B
Benjamin Pasero 已提交
628
		const hasWorkspace = this.contextService.hasWorkspace();
B
Benjamin Pasero 已提交
629 630 631 632 633 634

		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 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
	}
}

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

652
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
653 654 655 656 657 658 659 660 661 662

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

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

663
		return TPromise.as(true);
E
Erich Gamma 已提交
664
	}
665 666
}

B
Benjamin Pasero 已提交
667 668 669 670 671 672 673 674 675
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 已提交
676
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService
B
Benjamin Pasero 已提交
677 678 679 680
	) {
		super(id, label);
	}

681 682 683 684 685 686 687 688 689 690 691
	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 已提交
692
	public run(): TPromise<boolean> {
693
		return this._optimisticIsPure().then(isPure => {
B
Benjamin Pasero 已提交
694
			return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
695
				const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions);
B
Benjamin Pasero 已提交
696

B
Benjamin Pasero 已提交
697
				window.open(issueUrl);
B
Benjamin Pasero 已提交
698

B
Benjamin Pasero 已提交
699 700
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
701 702 703
		});
	}

J
Johannes Rieken 已提交
704
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[]): string {
C
Christof Marti 已提交
705
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
706 707 708 709 710
		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 已提交
711
- Extensions: ${this.generateExtensionTable(extensions)}
712
---
B
Benjamin Pasero 已提交
713 714 715 716 717 718 719 720 721

Steps to Reproduce:

1.
2.`
		);

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

	private generateExtensionTable(extensions: ILocalExtension[]): string {
B
Benjamin Pasero 已提交
724 725 726 727
		if (!extensions.length) {
			return 'none';
		}

728 729
		let tableHeader = `|Extension|Author|Version|
|---|---|---|`;
730
		const table = extensions.map(e => {
731
			return `|${e.manifest.name}|${e.manifest.publisher}|${e.manifest.version}|`;
732 733
		}).join('\n');

734
		const extensionTable = `
B
Benjamin Pasero 已提交
735 736 737 738

${tableHeader}\n${table};

`;
739 740 741 742 743 744 745
		// 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) {
			return 'the listing exceeds the lower minimum of browsers\' URL characters limit';
		}

		return extensionTable;
746
	}
B
Benjamin Pasero 已提交
747 748
}

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
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);
	}

764
	public run(appendix?: string): TPromise<boolean> {
765
		return this.integrityService.isPure().then(res => {
766
			const issueUrl = this.generatePerformanceIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, appendix);
767 768 769 770 771 772 773

			window.open(issueUrl);

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

774 775 776 777 778 779 780 781 782
	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.`;
		}

783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
		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>
799
- VM: <code>${metrics.isVMLikelyhood}%</code>
800
- Initial Startup: <code>${metrics.initialStartup ? 'yes' : 'no'}</code>
801
- Screen Reader: <code>${metrics.hasAccessibilitySupport ? 'yes' : 'no'}</code>
802 803 804 805 806 807 808
- Empty Workspace: <code>${metrics.emptyWorkbench ? 'yes' : 'no'}</code>
- Timings:

${this.generatePerformanceTable(nodeModuleLoadTime)}

---

809
${appendix}`
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
		);

		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 => {
836
			return `|${e.component}|${e.task}|${e.time}|`;
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
		}).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;
	}
}

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
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 已提交
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
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;
	}
}

911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
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;
	}
930
}
931

932 933 934 935 936 937 938 939 940 941 942 943
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();
	}
944 945
}

S
sj.hwang 已提交
946 947 948 949
enum Direction {
	Next,
	Previous,
}
950

S
sj.hwang 已提交
951
export abstract class BaseNavigationAction extends Action {
952

953
	constructor(
S
sj.hwang 已提交
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
		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);
974 975
		}

S
sj.hwang 已提交
976 977
		if (isPanelFocus) {
			return this.navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft);
978 979
		}

S
sj.hwang 已提交
980 981
		if (isSidebarFocus) {
			return this.navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft);
982 983
		}

S
sj.hwang 已提交
984
		return TPromise.as(false);
985 986
	}

S
sj.hwang 已提交
987 988
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
989 990
	}

S
sj.hwang 已提交
991 992
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
993 994
	}

S
sj.hwang 已提交
995 996
	protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
997 998
	}

S
sj.hwang 已提交
999 1000 1001
	protected navigateToPanel(): TPromise<any> {
		if (!this.partService.isVisible(Parts.PANEL_PART)) {
			return TPromise.as(false);
1002 1003
		}

S
sj.hwang 已提交
1004 1005
		const activePanelId = this.panelService.getActivePanel().getId();
		return this.panelService.openPanel(activePanelId, true);
1006 1007
	}

S
sj.hwang 已提交
1008 1009 1010
	protected navigateToSidebar(): TPromise<any> {
		if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
			return TPromise.as(false);
1011 1012
		}

S
sj.hwang 已提交
1013 1014
		const activeViewletId = this.viewletService.getActiveViewlet().getId();
		return this.viewletService.openViewlet(activeViewletId, true);
1015 1016
	}

S
sj.hwang 已提交
1017
	protected navigateAcrossEditorGroup(direction): TPromise<any> {
1018 1019
		const model = this.groupService.getStacksModel();
		const currentPosition = model.positionOfGroup(model.activeGroup);
S
sj.hwang 已提交
1020
		const nextPosition = direction === Direction.Next ? currentPosition + 1 : currentPosition - 1;
1021 1022 1023 1024 1025 1026 1027 1028 1029

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

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

1030
	protected navigateToLastActiveGroup(): TPromise<any> {
S
sj.hwang 已提交
1031
		const model = this.groupService.getStacksModel();
1032 1033 1034
		const lastActiveGroup = model.activeGroup;
		this.groupService.focusGroup(lastActiveGroup);
		return TPromise.as(true);
1035 1036
	}

1037 1038 1039
	protected navigateToFirstEditorGroup(): TPromise<any> {
		this.groupService.focusGroup(0);
		return TPromise.as(true);
1040 1041
	}

1042
	protected navigateToLastEditorGroup(): TPromise<any> {
S
sj.hwang 已提交
1043
		const model = this.groupService.getStacksModel();
1044 1045 1046
		const lastEditorGroupPosition = model.groups.length - 1;
		this.groupService.focusGroup(lastEditorGroupPosition);
		return TPromise.as(true);
1047 1048
	}
}
S
sj.hwang 已提交
1049 1050 1051 1052

export class NavigateLeftAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateLeft';
1053
	public static LABEL = nls.localize('navigateLeft', "Move to the View on the Left");
S
sj.hwang 已提交
1054 1055 1056 1057 1058 1059 1060 1061 1062

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1063
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1064 1065 1066
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
1067
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1068 1069 1070 1071
			if (isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
S
sj.hwang 已提交
1072
		}
S
sj.hwang 已提交
1073
		return this.navigateAcrossEditorGroup(Direction.Previous)
1074 1075 1076 1077 1078 1079
			.then(didNavigate => {
				if (!didNavigate && isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
S
sj.hwang 已提交
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
	}

	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) {
1094
			return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1095
		}
1096
		return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1097 1098
	}
}
1099 1100 1101 1102

export class NavigateRightAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateRight';
1103
	public static LABEL = nls.localize('navigateRight', "Move to the View on the Right");
1104 1105 1106 1107 1108 1109 1110 1111 1112

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1113
		super(id, label, groupService, panelService, partService, viewletService);
1114 1115 1116
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
1117
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1118 1119 1120 1121
			if (!isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
1122
		}
S
sj.hwang 已提交
1123
		return this.navigateAcrossEditorGroup(Direction.Next)
1124 1125 1126 1127 1128 1129
			.then(didNavigate => {
				if (!didNavigate && !isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
	}

	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) {
1144
			return this.navigateToFirstEditorGroup();
1145
		}
1146
		return this.navigateToLastActiveGroup();
1147 1148
	}
}
S
sj.hwang 已提交
1149 1150 1151 1152

export class NavigateUpAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateUp';
1153
	public static LABEL = nls.localize('navigateUp', "Move to the View Above");
S
sj.hwang 已提交
1154 1155 1156 1157 1158 1159 1160 1161 1162

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1163
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1164 1165 1166 1167 1168 1169
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return TPromise.as(false);
		}
S
sj.hwang 已提交
1170
		return this.navigateAcrossEditorGroup(Direction.Previous);
S
sj.hwang 已提交
1171 1172 1173 1174
	}

	protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
1175
			return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1176
		}
1177
		return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1178 1179
	}
}
S
sj.hwang 已提交
1180 1181 1182 1183

export class NavigateDownAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateDown';
1184
	public static LABEL = nls.localize('navigateDown', "Move to the View Below");
S
sj.hwang 已提交
1185 1186 1187 1188 1189 1190 1191 1192 1193

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1194
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1195 1196 1197 1198 1199 1200
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return this.navigateToPanel();
		}
S
sj.hwang 已提交
1201
		return this.navigateAcrossEditorGroup(Direction.Next)
1202 1203 1204 1205 1206 1207
			.then(didNavigate => {
				if (didNavigate) {
					return TPromise.as(true);
				}
				return this.navigateToPanel();
			});
S
sj.hwang 已提交
1208 1209
	}
}
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229

// 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 已提交
1230
		let part: Parts;
1231
		if (isSidebarFocus) {
B
Benjamin Pasero 已提交
1232 1233 1234 1235 1236
			part = Parts.SIDEBAR_PART;
		} else if (isPanelFocus) {
			part = Parts.PANEL_PART;
		} else if (isEditorFocus) {
			part = Parts.EDITOR_PART;
1237
		}
B
Benjamin Pasero 已提交
1238 1239 1240

		if (part) {
			this.partService.resizePart(part, sizeChange);
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 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
		}
	}
}

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