actions.ts 41.0 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');

733 734 735 736 737 738
		// 2000 chars is browsers de-facto limit for URLs, 250 chars is 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 (tableHeader.length + table.length > 1750) {
			return 'the listing exceeds the lower minimum of browsers\' URL characters limit';
		}

B
Benjamin Pasero 已提交
739 740 741 742 743
		return `

${tableHeader}\n${table};

`;
744
	}
B
Benjamin Pasero 已提交
745 746
}

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

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

			window.open(issueUrl);

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

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

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

${this.generatePerformanceTable(nodeModuleLoadTime)}

---

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

		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 => {
834
			return `|${e.component}|${e.task}|${e.time}|`;
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 861 862 863 864 865 866
		}).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;
	}
}

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

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

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

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

S
sj.hwang 已提交
949
export abstract class BaseNavigationAction extends Action {
950

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

export class NavigateLeftAction extends BaseNavigationAction {

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

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

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

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

export class NavigateRightAction extends BaseNavigationAction {

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

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

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

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

export class NavigateUpAction extends BaseNavigationAction {

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

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

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

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

export class NavigateDownAction extends BaseNavigationAction {

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

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

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

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

		if (part) {
			this.partService.resizePart(part, sizeChange);
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
		}
	}
}

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