actions.ts 38.9 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 200 201 202 203 204
		}

		this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMenuBarAction.menuBarVisibilityKey, value: newVisibilityValue }).then(null, error => {
			this.messageService.show(Severity.Error, error);
		});

		return TPromise.as(null);
205 206 207
	}
}

E
Erich Gamma 已提交
208 209
export class ToggleDevToolsAction extends Action {

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

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

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

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

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

B
Benjamin Pasero 已提交
242
		const applyZoom = () => {
243
			webFrame.setZoomLevel(level);
B
Benjamin Pasero 已提交
244
			browser.setZoomFactor(webFrame.getZoomFactor());
245
			browser.setZoomLevel(level); // Ensure others can listen to zoom level changes
246 247
		};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	public run(): TPromise<boolean> {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

export class ReloadWindowAction extends Action {

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

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

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

export class OpenRecentAction extends Action {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Steps to Reproduce:

1.
2.`
		);

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

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

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

B
Benjamin Pasero 已提交
733 734 735 736 737
		return `

${tableHeader}\n${table};

`;
738
	}
B
Benjamin Pasero 已提交
739 740
}

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
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);
	}

756
	public run(appendix?: string): TPromise<boolean> {
757
		return this.integrityService.isPure().then(res => {
758
			const issueUrl = this.generatePerformanceIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, appendix);
759 760 761 762 763 764 765

			window.open(issueUrl);

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

766 767 768 769 770 771 772 773 774
	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.`;
		}

775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
		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>
791
- VM: <code>${metrics.isVMLikelyhood}%</code>
792
- Initial Startup: <code>${metrics.initialStartup ? 'yes' : 'no'}</code>
793
- Screen Reader: <code>${metrics.hasAccessibilitySupport ? 'yes' : 'no'}</code>
794 795 796 797 798 799 800
- Empty Workspace: <code>${metrics.emptyWorkbench ? 'yes' : 'no'}</code>
- Timings:

${this.generatePerformanceTable(nodeModuleLoadTime)}

---

801
${appendix}`
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
		);

		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 => {
828
			return `|${e.component}|${e.task}|${e.time}|`;
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 854 855 856 857 858 859 860
		}).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;
	}
}

861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
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 已提交
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
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;
	}
}

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
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;
	}
922
}
923

924 925 926 927 928 929 930 931 932 933 934 935
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();
	}
936 937
}

S
sj.hwang 已提交
938 939 940 941
enum Direction {
	Next,
	Previous,
}
942

S
sj.hwang 已提交
943
export abstract class BaseNavigationAction extends Action {
944

945
	constructor(
S
sj.hwang 已提交
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
		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);
966 967
		}

S
sj.hwang 已提交
968 969
		if (isPanelFocus) {
			return this.navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft);
970 971
		}

S
sj.hwang 已提交
972 973
		if (isSidebarFocus) {
			return this.navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft);
974 975
		}

S
sj.hwang 已提交
976
		return TPromise.as(false);
977 978
	}

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

S
sj.hwang 已提交
983 984
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
		return TPromise.as(true);
985 986
	}

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

S
sj.hwang 已提交
991 992 993
	protected navigateToPanel(): TPromise<any> {
		if (!this.partService.isVisible(Parts.PANEL_PART)) {
			return TPromise.as(false);
994 995
		}

S
sj.hwang 已提交
996 997
		const activePanelId = this.panelService.getActivePanel().getId();
		return this.panelService.openPanel(activePanelId, true);
998 999
	}

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

S
sj.hwang 已提交
1005 1006
		const activeViewletId = this.viewletService.getActiveViewlet().getId();
		return this.viewletService.openViewlet(activeViewletId, true);
1007 1008
	}

S
sj.hwang 已提交
1009
	protected navigateAcrossEditorGroup(direction): TPromise<any> {
1010 1011
		const model = this.groupService.getStacksModel();
		const currentPosition = model.positionOfGroup(model.activeGroup);
S
sj.hwang 已提交
1012
		const nextPosition = direction === Direction.Next ? currentPosition + 1 : currentPosition - 1;
1013 1014 1015 1016 1017 1018 1019 1020 1021

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

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

1022
	protected navigateToLastActiveGroup(): TPromise<any> {
S
sj.hwang 已提交
1023
		const model = this.groupService.getStacksModel();
1024 1025 1026
		const lastActiveGroup = model.activeGroup;
		this.groupService.focusGroup(lastActiveGroup);
		return TPromise.as(true);
1027 1028
	}

1029 1030 1031
	protected navigateToFirstEditorGroup(): TPromise<any> {
		this.groupService.focusGroup(0);
		return TPromise.as(true);
1032 1033
	}

1034
	protected navigateToLastEditorGroup(): TPromise<any> {
S
sj.hwang 已提交
1035
		const model = this.groupService.getStacksModel();
1036 1037 1038
		const lastEditorGroupPosition = model.groups.length - 1;
		this.groupService.focusGroup(lastEditorGroupPosition);
		return TPromise.as(true);
1039 1040
	}
}
S
sj.hwang 已提交
1041 1042 1043 1044

export class NavigateLeftAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateLeft';
S
sj.hwang 已提交
1045
	public static LABEL = nls.localize('navigateLeft', "Move to the View Part on the Left");
S
sj.hwang 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1055
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1056 1057 1058
	}

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

	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) {
1086
			return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1087
		}
1088
		return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1089 1090
	}
}
1091 1092 1093 1094

export class NavigateRightAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateRight';
S
sj.hwang 已提交
1095
	public static LABEL = nls.localize('navigateRight', "Move to the View Part on the Right");
1096 1097 1098 1099 1100 1101 1102 1103 1104

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1105
		super(id, label, groupService, panelService, partService, viewletService);
1106 1107 1108
	}

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

	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) {
1136
			return this.navigateToFirstEditorGroup();
1137
		}
1138
		return this.navigateToLastActiveGroup();
1139 1140
	}
}
S
sj.hwang 已提交
1141 1142 1143 1144

export class NavigateUpAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateUp';
S
sj.hwang 已提交
1145
	public static LABEL = nls.localize('navigateUp', "Move to the View Part Above");
S
sj.hwang 已提交
1146 1147 1148 1149 1150 1151 1152 1153 1154

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1155
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1156 1157 1158 1159 1160 1161
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return TPromise.as(false);
		}
S
sj.hwang 已提交
1162
		return this.navigateAcrossEditorGroup(Direction.Previous);
S
sj.hwang 已提交
1163 1164 1165 1166
	}

	protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
1167
			return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1168
		}
1169
		return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1170 1171
	}
}
S
sj.hwang 已提交
1172 1173 1174 1175

export class NavigateDownAction extends BaseNavigationAction {

	public static ID = 'workbench.action.navigateDown';
S
sj.hwang 已提交
1176
	public static LABEL = nls.localize('navigateDown', "Move to the View Part Below");
S
sj.hwang 已提交
1177 1178 1179 1180 1181 1182 1183 1184 1185

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1186
		super(id, label, groupService, panelService, partService, viewletService);
S
sj.hwang 已提交
1187 1188 1189 1190 1191 1192
	}

	protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
		if (isEditorGroupVertical) {
			return this.navigateToPanel();
		}
S
sj.hwang 已提交
1193
		return this.navigateAcrossEditorGroup(Direction.Next)
1194 1195 1196 1197 1198 1199
			.then(didNavigate => {
				if (didNavigate) {
					return TPromise.as(true);
				}
				return this.navigateToPanel();
			});
S
sj.hwang 已提交
1200 1201
	}
}