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

'use strict';

8 9
import 'vs/css!./media/actions';

10
import URI from 'vs/base/common/uri';
11
import * as collections from 'vs/base/common/collections';
J
Johannes Rieken 已提交
12 13
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
14
import { IWindowService, IWindowsService, MenuBarVisibility } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
15
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
E
Erich Gamma 已提交
16
import nls = require('vs/nls');
17 18
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
B
Benjamin Pasero 已提交
19
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
20
import { IMessageService, Severity } from 'vs/platform/message/common/message';
21
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
22
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
23
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
24
import { IExtensionManagementService, LocalExtensionType, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
J
Johannes Rieken 已提交
25
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
B
Benjamin Pasero 已提交
26
import paths = require('vs/base/common/paths');
B
Benjamin Pasero 已提交
27
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
28
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
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';
B
Benjamin Pasero 已提交
37
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
B
Benjamin Pasero 已提交
38
import * as os from 'os';
39
import { webFrame } from 'electron';
B
Benjamin Pasero 已提交
40
import { getPathLabel, getBaseLabel } from 'vs/base/common/labels';
B
Benjamin Pasero 已提交
41 42
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IPanel } from 'vs/workbench/common/panel';
B
Benjamin Pasero 已提交
43
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
B
Benjamin Pasero 已提交
44
import { FileKind, IFileService } from 'vs/platform/files/common/files';
B
Benjamin Pasero 已提交
45
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
46
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
47
import { getEntries } from 'vs/base/common/performance';
B
Benjamin Pasero 已提交
48
import { IEditor } from 'vs/platform/editor/common/editor';
E
Erich Gamma 已提交
49

50 51
// --- actions

E
Erich Gamma 已提交
52 53
export class CloseEditorAction extends Action {

M
Matt Bierner 已提交
54 55
	public static readonly ID = 'workbench.action.closeActiveEditor';
	public static readonly LABEL = nls.localize('closeActiveEditor', "Close Editor");
E
Erich Gamma 已提交
56 57 58 59

	constructor(
		id: string,
		label: string,
60
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
E
Erich Gamma 已提交
61 62 63 64
	) {
		super(id, label);
	}

B
Benjamin Pasero 已提交
65
	public run(): TPromise<void> {
B
Benjamin Pasero 已提交
66
		const activeEditor = this.editorService.getActiveEditor();
E
Erich Gamma 已提交
67
		if (activeEditor) {
68
			return this.editorService.closeEditor(activeEditor.position, activeEditor.input);
E
Erich Gamma 已提交
69 70
		}

B
Benjamin Pasero 已提交
71
		return TPromise.as(null);
E
Erich Gamma 已提交
72 73 74
	}
}

75
export class CloseCurrentWindowAction extends Action {
E
Erich Gamma 已提交
76

M
Matt Bierner 已提交
77 78
	public static readonly ID = 'workbench.action.closeWindow';
	public static readonly LABEL = nls.localize('closeWindow', "Close Window");
E
Erich Gamma 已提交
79

80
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
81 82 83
		super(id, label);
	}

84
	public run(): TPromise<boolean> {
85
		this.windowService.closeWindow();
E
Erich Gamma 已提交
86

A
Alex Dima 已提交
87
		return TPromise.as(true);
E
Erich Gamma 已提交
88 89 90
	}
}

91
export class CloseWorkspaceAction extends Action {
E
Erich Gamma 已提交
92

J
Joao Moreno 已提交
93
	static ID = 'workbench.action.closeFolder';
94
	static LABEL = nls.localize('closeWorkspace', "Close Workspace");
E
Erich Gamma 已提交
95 96 97 98 99

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
B
Benjamin Pasero 已提交
100
		@IMessageService private messageService: IMessageService,
J
Joao Moreno 已提交
101
		@IWindowService private windowService: IWindowService
E
Erich Gamma 已提交
102 103 104 105
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
106
	run(): TPromise<void> {
107
		if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
108 109
			this.messageService.show(Severity.Info, nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close."));

J
Joao Moreno 已提交
110
			return TPromise.as(null);
E
Erich Gamma 已提交
111 112
		}

113
		return this.windowService.closeWorkspace();
E
Erich Gamma 已提交
114 115 116 117 118
	}
}

export class NewWindowAction extends Action {

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

B
Benjamin Pasero 已提交
122 123 124
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
125
		@IWindowsService private windowsService: IWindowsService
B
Benjamin Pasero 已提交
126
	) {
E
Erich Gamma 已提交
127 128 129
		super(id, label);
	}

J
Joao Moreno 已提交
130 131
	run(): TPromise<void> {
		return this.windowsService.openNewWindow();
E
Erich Gamma 已提交
132 133 134 135 136
	}
}

export class ToggleFullScreenAction extends Action {

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

J
Joao Moreno 已提交
140
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
141 142 143
		super(id, label);
	}

J
Joao Moreno 已提交
144 145
	run(): TPromise<void> {
		return this.windowService.toggleFullScreen();
E
Erich Gamma 已提交
146 147 148
	}
}

149 150
export class ToggleMenuBarAction extends Action {

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

154
	private static readonly menuBarVisibilityKey = 'window.menuBarVisibility';
155 156 157 158

	constructor(
		id: string,
		label: string,
159
		@IConfigurationService private configurationService: IConfigurationService
160
	) {
161 162 163
		super(id, label);
	}

B
Benjamin Pasero 已提交
164
	public run(): TPromise<void> {
165
		let currentVisibilityValue = this.configurationService.getValue<MenuBarVisibility>(ToggleMenuBarAction.menuBarVisibilityKey);
166 167
		if (typeof currentVisibilityValue !== 'string') {
			currentVisibilityValue = 'default';
168 169 170
		}

		let newVisibilityValue: string;
171
		if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') {
172 173
			newVisibilityValue = 'toggle';
		} else {
174
			newVisibilityValue = 'default';
175 176
		}

177
		this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER);
178 179

		return TPromise.as(null);
180 181 182
	}
}

E
Erich Gamma 已提交
183 184
export class ToggleDevToolsAction extends Action {

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

J
Joao Moreno 已提交
188
	constructor(id: string, label: string, @IWindowService private windowsService: IWindowService) {
E
Erich Gamma 已提交
189 190 191
		super(id, label);
	}

B
Benjamin Pasero 已提交
192
	public run(): TPromise<void> {
J
Joao Moreno 已提交
193
		return this.windowsService.toggleDevTools();
E
Erich Gamma 已提交
194 195 196
	}
}

197
export abstract class BaseZoomAction extends Action {
198
	private static readonly SETTING_KEY = 'window.zoomLevel';
199 200 201 202

	constructor(
		id: string,
		label: string,
203
		@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService
204 205 206 207 208
	) {
		super(id, label);
	}

	protected setConfiguredZoomLevel(level: number): void {
209 210
		level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels

B
Benjamin Pasero 已提交
211
		const applyZoom = () => {
212
			webFrame.setZoomLevel(level);
B
Benjamin Pasero 已提交
213
			browser.setZoomFactor(webFrame.getZoomFactor());
214 215 216 217
			// See https://github.com/Microsoft/vscode/issues/26151
			// Cannot be trusted because the webFrame might take some time
			// until it really applies the new zoom level
			browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
218 219
		};

220
		this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level).done(() => applyZoom());
221 222 223 224
	}
}

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

M
Matt Bierner 已提交
226 227
	public static readonly ID = 'workbench.action.zoomIn';
	public static readonly LABEL = nls.localize('zoomIn', "Zoom In");
E
Erich Gamma 已提交
228

229 230 231
	constructor(
		id: string,
		label: string,
232
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService
233
	) {
234
		super(id, label, configurationService);
E
Erich Gamma 已提交
235 236
	}

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

A
Alex Dima 已提交
240
		return TPromise.as(true);
E
Erich Gamma 已提交
241 242 243
	}
}

244
export class ZoomOutAction extends BaseZoomAction {
E
Erich Gamma 已提交
245

M
Matt Bierner 已提交
246 247
	public static readonly ID = 'workbench.action.zoomOut';
	public static readonly LABEL = nls.localize('zoomOut', "Zoom Out");
E
Erich Gamma 已提交
248

249 250
	constructor(
		id: string,
251
		label: string,
252
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService
253
	) {
254
		super(id, label, configurationService);
E
Erich Gamma 已提交
255 256
	}

257
	public run(): TPromise<boolean> {
258
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
259

260
		return TPromise.as(true);
E
Erich Gamma 已提交
261 262 263
	}
}

264
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
265

M
Matt Bierner 已提交
266 267
	public static readonly ID = 'workbench.action.zoomReset';
	public static readonly LABEL = nls.localize('zoomReset', "Reset Zoom");
E
Erich Gamma 已提交
268

269 270 271
	constructor(
		id: string,
		label: string,
272
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService
273
	) {
274
		super(id, label, configurationService);
E
Erich Gamma 已提交
275 276
	}

277
	public run(): TPromise<boolean> {
278
		this.setConfiguredZoomLevel(0);
279

280
		return TPromise.as(true);
E
Erich Gamma 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
	}
}

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

E
Erich Gamma 已提交
302 303 304 305 306
interface ILoaderEvent {
	type: LoaderEventType;
	timestamp: number;
	detail: string;
}
307

E
Erich Gamma 已提交
308 309
export class ShowStartupPerformance extends Action {

M
Matt Bierner 已提交
310 311
	public static readonly ID = 'workbench.action.appPerf';
	public static readonly LABEL = nls.localize('appPerf', "Startup Performance");
E
Erich Gamma 已提交
312

313 314 315
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
316
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
317
		@ITimerService private timerService: ITimerService,
318 319
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IExtensionService private extensionService: IExtensionService
320
	) {
E
Erich Gamma 已提交
321
		super(id, label);
322 323 324 325 326 327 328 329 330
	}

	public run(): TPromise<boolean> {

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

		// Print to console
		setTimeout(() => {
331
			(<any>console).group('Startup Performance Measurement');
B
Benjamin Pasero 已提交
332 333 334 335 336
			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)`);
337
			console.log(`VM (likelyhood): ${metrics.isVMLikelyhood}%`);
B
Benjamin Pasero 已提交
338 339 340
			console.log(`Initial Startup: ${metrics.initialStartup}`);
			console.log(`Screen Reader Active: ${metrics.hasAccessibilitySupport}`);
			console.log(`Empty Workspace: ${metrics.emptyWorkbench}`);
341 342 343 344 345 346 347

			let nodeModuleLoadTime: number;
			if (this.environmentService.performance) {
				const nodeModuleTimes = this.analyzeNodeModulesLoadTimes();
				nodeModuleLoadTime = nodeModuleTimes.duration;
			}

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

350 351 352 353 354 355 356
			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();
				}
357
			}
358

359
			(<any>console).groupEnd();
360 361 362 363

			(<any>console).group('Extension Activation Stats');
			(<any>console).table(this.extensionService.getExtensionsActivationTimes());
			(<any>console).groupEnd();
364 365 366

			(<any>console).group('Raw Startup Timers (CSV)');
			let value = `Name\tStart\tDuration\n`;
367 368 369 370
			const entries = getEntries('measure');
			let offset = entries[0].startTime;
			for (const entry of entries) {
				value += `${entry.name}\t${entry.startTime - offset}\t${entry.duration}\n`;
371 372 373
			}
			console.log(value);
			(<any>console).groupEnd();
374
		}, 1000);
375

376
		return TPromise.as(true);
E
Erich Gamma 已提交
377 378
	}

B
Benjamin Pasero 已提交
379
	private getStartupMetricsTable(nodeModuleLoadTime?: number): any[] {
380
		const table: any[] = [];
B
Benjamin Pasero 已提交
381
		const metrics: IStartupMetrics = this.timerService.startupMetrics;
382

B
Benjamin Pasero 已提交
383
		if (metrics.initialStartup) {
384 385
			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 已提交
386
		}
387

B
Benjamin Pasero 已提交
388 389
		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 });
390 391 392 393 394

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

B
Benjamin Pasero 已提交
395 396 397 398
		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 });
399
		table.push({ Topic: '------------------------------------------------------' });
B
Benjamin Pasero 已提交
400 401
		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 已提交
402

403
		return table;
E
Erich Gamma 已提交
404 405
	}

406
	private analyzeNodeModulesLoadTimes(): { table: any[], duration: number } {
407 408 409 410 411 412 413 414 415
		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 = {};
416
					const dur = (stats[i].timestamp - stats[i - 1].timestamp);
417
					entry['Event'] = 'nodeRequire ' + stats[i].detail;
418 419 420 421
					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);
422 423 424 425 426 427
					result.push(entry);
				}
			}
		}

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

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

438
		return { table: result, duration: Math.round(total) };
E
Erich Gamma 已提交
439
	}
440 441

	private analyzeLoaderStats(): { [type: string]: any[] } {
M
Matt Bierner 已提交
442
		const stats = <ILoaderEvent[]>(<any>require).getStats().slice(0).sort((a: ILoaderEvent, b: ILoaderEvent) => {
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
			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 已提交
548 549 550 551
}

export class ReloadWindowAction extends Action {

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

555 556 557
	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
558
		@IWindowService private windowService: IWindowService
559
	) {
E
Erich Gamma 已提交
560 561 562
		super(id, label);
	}

563 564
	run(): TPromise<boolean> {
		return this.windowService.reloadWindow().then(() => true);
E
Erich Gamma 已提交
565 566 567
	}
}

B
Benjamin Pasero 已提交
568
export abstract class BaseSwitchWindow extends Action {
569
	private closeWindowAction: CloseWindowAction;
E
Erich Gamma 已提交
570

B
Benjamin Pasero 已提交
571 572 573 574 575 576
	constructor(
		id: string,
		label: string,
		private windowsService: IWindowsService,
		private windowService: IWindowService,
		private quickOpenService: IQuickOpenService,
577 578
		private keybindingService: IKeybindingService,
		private instantiationService: IInstantiationService
B
Benjamin Pasero 已提交
579 580
	) {
		super(id, label);
581 582

		this.closeWindowAction = this.instantiationService.createInstance(CloseWindowAction);
B
Benjamin Pasero 已提交
583 584 585 586 587 588 589
	}

	protected abstract isQuickNavigate(): boolean;

	public run(): TPromise<void> {
		const currentWindowId = this.windowService.getCurrentWindowId();

590
		return this.windowsService.getWindows().then(windows => {
B
Benjamin Pasero 已提交
591
			const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to");
592
			const picks = windows.map(win => ({
593
				payload: win.id,
594
				resource: win.filename ? URI.file(win.filename) : win.folderPath ? URI.file(win.folderPath) : win.workspace ? URI.file(win.workspace.configPath) : void 0,
595
				fileKind: win.filename ? FileKind.FILE : win.workspace ? FileKind.ROOT_FOLDER : win.folderPath ? FileKind.FOLDER : FileKind.FILE,
B
Benjamin Pasero 已提交
596 597 598 599 600 601 602 603
				label: win.title,
				description: (currentWindowId === win.id) ? nls.localize('current', "Current Window") : void 0,
				run: () => {
					setTimeout(() => {
						// Bug: somehow when not running this code in a timeout, it is not possible to use this picker
						// with quick navigate keys (not able to trigger quick navigate once running it once).
						this.windowsService.showWindow(win.id).done(null, errors.onUnexpectedError);
					});
604 605
				},
				action: (!this.isQuickNavigate() && currentWindowId !== win.id) ? this.closeWindowAction : void 0
B
Benjamin Pasero 已提交
606 607 608
			} as IFilePickOpenEntry));

			this.quickOpenService.pick(picks, {
609
				contextKey: 'inWindowsPicker',
B
Benjamin Pasero 已提交
610 611 612 613 614 615
				autoFocus: { autoFocusFirstEntry: true },
				placeHolder,
				quickNavigateConfiguration: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : void 0
			});
		});
	}
616 617 618 619 620 621 622 623 624 625

	public dispose(): void {
		super.dispose();

		this.closeWindowAction.dispose();
	}
}

class CloseWindowAction extends Action implements IPickOpenAction {

M
Matt Bierner 已提交
626 627
	public static readonly ID = 'workbench.action.closeWindow';
	public static readonly LABEL = nls.localize('close', "Close Window");
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

	constructor(
		@IWindowsService private windowsService: IWindowsService
	) {
		super(CloseWindowAction.ID, CloseWindowAction.LABEL);

		this.class = 'action-remove-from-recently-opened';
	}

	public run(item: IPickOpenItem): TPromise<boolean> {
		return this.windowsService.closeWindow(item.getPayload()).then(() => {
			item.remove();

			return true;
		});
	}
B
Benjamin Pasero 已提交
644 645 646 647 648 649
}

export class SwitchWindow extends BaseSwitchWindow {

	static ID = 'workbench.action.switchWindow';
	static LABEL = nls.localize('switchWindow', "Switch Window...");
E
Erich Gamma 已提交
650 651 652 653

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
654 655 656
		@IWindowsService windowsService: IWindowsService,
		@IWindowService windowService: IWindowService,
		@IQuickOpenService quickOpenService: IQuickOpenService,
657 658
		@IKeybindingService keybindingService: IKeybindingService,
		@IInstantiationService instantiationService: IInstantiationService
B
Benjamin Pasero 已提交
659
	) {
660
		super(id, label, windowsService, windowService, quickOpenService, keybindingService, instantiationService);
B
Benjamin Pasero 已提交
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
	}

	protected isQuickNavigate(): boolean {
		return false;
	}
}

export class QuickSwitchWindow extends BaseSwitchWindow {

	static ID = 'workbench.action.quickSwitchWindow';
	static LABEL = nls.localize('quickSwitchWindow', "Quick Switch Window...");

	constructor(
		id: string,
		label: string,
		@IWindowsService windowsService: IWindowsService,
		@IWindowService windowService: IWindowService,
		@IQuickOpenService quickOpenService: IQuickOpenService,
679 680
		@IKeybindingService keybindingService: IKeybindingService,
		@IInstantiationService instantiationService: IInstantiationService
B
Benjamin Pasero 已提交
681
	) {
682
		super(id, label, windowsService, windowService, quickOpenService, keybindingService, instantiationService);
B
Benjamin Pasero 已提交
683 684 685 686 687 688 689
	}

	protected isQuickNavigate(): boolean {
		return true;
	}
}

690 691
export const inRecentFilesPickerContextKey = 'inRecentFilesPicker';

B
Benjamin Pasero 已提交
692
export abstract class BaseOpenRecentAction extends Action {
693
	private removeAction: RemoveFromRecentlyOpened;
B
Benjamin Pasero 已提交
694 695 696 697 698 699 700 701 702

	constructor(
		id: string,
		label: string,
		private windowsService: IWindowsService,
		private windowService: IWindowService,
		private quickOpenService: IQuickOpenService,
		private contextService: IWorkspaceContextService,
		private environmentService: IEnvironmentService,
703 704
		private keybindingService: IKeybindingService,
		instantiationService: IInstantiationService
E
Erich Gamma 已提交
705 706
	) {
		super(id, label);
707 708

		this.removeAction = instantiationService.createInstance(RemoveFromRecentlyOpened);
E
Erich Gamma 已提交
709 710
	}

B
Benjamin Pasero 已提交
711 712
	protected abstract isQuickNavigate(): boolean;

J
Joao Moreno 已提交
713
	public run(): TPromise<void> {
B
Benjamin Pasero 已提交
714
		return this.windowService.getRecentlyOpened()
715
			.then(({ workspaces, files }) => this.openRecent(workspaces, files));
B
Benjamin Pasero 已提交
716 717
	}

718
	private openRecent(recentWorkspaces: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)[], recentFiles: string[]): void {
719

720
		function toPick(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier, separator: ISeparator, fileKind: FileKind, environmentService: IEnvironmentService, removeAction?: RemoveFromRecentlyOpened): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
721 722 723 724 725
			let path: string;
			let label: string;
			let description: string;
			if (isSingleFolderWorkspaceIdentifier(workspace)) {
				path = workspace;
B
Benjamin Pasero 已提交
726
				label = getBaseLabel(path);
B
Benjamin Pasero 已提交
727 728 729
				description = getPathLabel(paths.dirname(path), null, environmentService);
			} else {
				path = workspace.configPath;
B
Benjamin Pasero 已提交
730 731
				label = getWorkspaceLabel(workspace, environmentService);
				description = getPathLabel(paths.dirname(workspace.configPath), null, environmentService);
B
Benjamin Pasero 已提交
732
			}
B
Benjamin Pasero 已提交
733

B
Benjamin Pasero 已提交
734
			return {
B
Benjamin Pasero 已提交
735
				resource: URI.file(path),
736
				fileKind,
737 738
				label,
				description,
B
Benjamin Pasero 已提交
739
				separator,
B
Benjamin Pasero 已提交
740 741 742 743
				run: context => {
					setTimeout(() => {
						// Bug: somehow when not running this code in a timeout, it is not possible to use this picker
						// with quick navigate keys (not able to trigger quick navigate once running it once).
744
						runPick(path, fileKind === FileKind.FILE, context);
B
Benjamin Pasero 已提交
745
					});
746 747
				},
				action: removeAction
B
Benjamin Pasero 已提交
748 749 750
			};
		}

751
		const runPick = (path: string, isFile: boolean, context: IEntryRunContext) => {
752
			const forceNewWindow = context.keymods.ctrlCmd;
753
			this.windowsService.openWindow([path], { forceNewWindow, forceOpenWorkspaceAsFile: isFile });
754
		};
B
Benjamin Pasero 已提交
755

756 757
		const workspacePicks: IFilePickOpenEntry[] = recentWorkspaces.map((workspace, index) => toPick(workspace, index === 0 ? { label: nls.localize('workspaces', "workspaces") } : void 0, isSingleFolderWorkspaceIdentifier(workspace) ? FileKind.FOLDER : FileKind.ROOT_FOLDER, this.environmentService, !this.isQuickNavigate() ? this.removeAction : void 0));
		const filePicks: IFilePickOpenEntry[] = recentFiles.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('files', "files"), border: true } : void 0, FileKind.FILE, this.environmentService, !this.isQuickNavigate() ? this.removeAction : void 0));
B
Benjamin Pasero 已提交
758

759 760 761
		// focus second entry if the first recent workspace is the current workspace
		let autoFocusSecondEntry: boolean = recentWorkspaces[0] && this.contextService.isCurrentWorkspace(recentWorkspaces[0]);

762
		this.quickOpenService.pick([...workspacePicks, ...filePicks], {
763
			contextKey: inRecentFilesPickerContextKey,
764
			autoFocus: { autoFocusFirstEntry: !autoFocusSecondEntry, autoFocusSecondEntry: autoFocusSecondEntry },
B
Benjamin Pasero 已提交
765
			placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to open in new window)"),
B
Benjamin Pasero 已提交
766 767
			matchOnDescription: true,
			quickNavigateConfiguration: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : void 0
B
Benjamin Pasero 已提交
768
		}).done(null, errors.onUnexpectedError);
E
Erich Gamma 已提交
769
	}
770 771 772 773 774 775 776 777

	public dispose(): void {
		super.dispose();

		this.removeAction.dispose();
	}
}

778
class RemoveFromRecentlyOpened extends Action implements IPickOpenAction {
779

M
Matt Bierner 已提交
780 781
	public static readonly ID = 'workbench.action.removeFromRecentlyOpened';
	public static readonly LABEL = nls.localize('remove', "Remove from Recently Opened");
782 783

	constructor(
784
		@IWindowsService private windowsService: IWindowsService
785 786 787 788 789 790
	) {
		super(RemoveFromRecentlyOpened.ID, RemoveFromRecentlyOpened.LABEL);

		this.class = 'action-remove-from-recently-opened';
	}

791 792 793
	public run(item: IPickOpenItem): TPromise<boolean> {
		return this.windowsService.removeFromRecentlyOpened([item.getResource().fsPath]).then(() => {
			item.remove();
794 795 796 797

			return true;
		});
	}
E
Erich Gamma 已提交
798 799
}

B
Benjamin Pasero 已提交
800 801
export class OpenRecentAction extends BaseOpenRecentAction {

M
Matt Bierner 已提交
802 803
	public static readonly ID = 'workbench.action.openRecent';
	public static readonly LABEL = nls.localize('openRecent', "Open Recent...");
B
Benjamin Pasero 已提交
804 805 806 807 808 809 810 811 812

	constructor(
		id: string,
		label: string,
		@IWindowsService windowsService: IWindowsService,
		@IWindowService windowService: IWindowService,
		@IQuickOpenService quickOpenService: IQuickOpenService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEnvironmentService environmentService: IEnvironmentService,
813 814
		@IKeybindingService keybindingService: IKeybindingService,
		@IInstantiationService instantiationService: IInstantiationService
B
Benjamin Pasero 已提交
815
	) {
816
		super(id, label, windowsService, windowService, quickOpenService, contextService, environmentService, keybindingService, instantiationService);
B
Benjamin Pasero 已提交
817 818 819 820 821 822 823 824 825
	}

	protected isQuickNavigate(): boolean {
		return false;
	}
}

export class QuickOpenRecentAction extends BaseOpenRecentAction {

M
Matt Bierner 已提交
826 827
	public static readonly ID = 'workbench.action.quickOpenRecent';
	public static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent...");
B
Benjamin Pasero 已提交
828 829 830 831 832 833 834 835 836

	constructor(
		id: string,
		label: string,
		@IWindowsService windowsService: IWindowsService,
		@IWindowService windowService: IWindowService,
		@IQuickOpenService quickOpenService: IQuickOpenService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEnvironmentService environmentService: IEnvironmentService,
837 838
		@IKeybindingService keybindingService: IKeybindingService,
		@IInstantiationService instantiationService: IInstantiationService
B
Benjamin Pasero 已提交
839
	) {
840
		super(id, label, windowsService, windowService, quickOpenService, contextService, environmentService, keybindingService, instantiationService);
B
Benjamin Pasero 已提交
841 842 843 844 845 846 847
	}

	protected isQuickNavigate(): boolean {
		return true;
	}
}

E
Erich Gamma 已提交
848 849
export class CloseMessagesAction extends Action {

M
Matt Bierner 已提交
850 851
	public static readonly ID = 'workbench.action.closeMessages';
	public static readonly LABEL = nls.localize('closeMessages', "Close Notification Messages");
E
Erich Gamma 已提交
852 853 854 855 856 857 858 859 860 861

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

862
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
863 864 865 866 867 868 869 870 871 872

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

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

873
		return TPromise.as(true);
E
Erich Gamma 已提交
874
	}
875 876
}

B
Benjamin Pasero 已提交
877 878
export class ReportIssueAction extends Action {

M
Matt Bierner 已提交
879 880
	public static readonly ID = 'workbench.action.reportIssues';
	public static readonly LABEL = nls.localize('reportIssues', "Report Issues");
B
Benjamin Pasero 已提交
881 882 883 884 885

	constructor(
		id: string,
		label: string,
		@IIntegrityService private integrityService: IIntegrityService,
886
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
887
		@IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService,
888
		@IEnvironmentService private environmentService: IEnvironmentService
B
Benjamin Pasero 已提交
889 890 891 892
	) {
		super(id, label);
	}

893 894 895 896 897 898 899 900 901 902 903
	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 已提交
904
	public run(): TPromise<boolean> {
905
		return this._optimisticIsPure().then(isPure => {
B
Benjamin Pasero 已提交
906
			return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
B
Benjamin Pasero 已提交
907
				extensions = extensions.filter(extension => this.extensionEnablementService.isEnabled(extension.identifier));
908
				const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions, this.environmentService.disableExtensions);
B
Benjamin Pasero 已提交
909

B
Benjamin Pasero 已提交
910
				window.open(issueUrl);
B
Benjamin Pasero 已提交
911

B
Benjamin Pasero 已提交
912 913
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
914 915 916
		});
	}

917
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[], areExtensionsDisabled: boolean): string {
C
Christof Marti 已提交
918
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
919 920 921 922 923
		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}
924
- Extensions: ${areExtensionsDisabled ? 'Extensions are disabled' : this.generateExtensionTable(extensions)}
925
---
B
Benjamin Pasero 已提交
926 927 928 929

Steps to Reproduce:

1.
930 931 932 933
2.` + (extensions.length ? `

<!-- Launch with \`code --disable-extensions\` to check. -->
Reproduces without extensions: Yes/No` : '')
B
Benjamin Pasero 已提交
934 935 936 937
		);

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

	private generateExtensionTable(extensions: ILocalExtension[]): string {
940 941 942 943 944 945
		const { nonThemes, themes } = collections.groupBy(extensions, ext => {
			const manifestKeys = ext.manifest.contributes ? Object.keys(ext.manifest.contributes) : [];
			const onlyTheme = !ext.manifest.activationEvents && manifestKeys.length === 1 && manifestKeys[0] === 'themes';
			return onlyTheme ? 'themes' : 'nonThemes';
		});

946 947
		const themeExclusionStr = (themes && themes.length) ? `\n(${themes.length} theme extensions excluded)` : '';
		extensions = nonThemes || [];
948

B
Benjamin Pasero 已提交
949
		if (!extensions.length) {
950
			return 'none' + themeExclusionStr;
B
Benjamin Pasero 已提交
951 952
		}

953
		let tableHeader = `Extension|Author (truncated)|Version
954
---|---|---`;
955
		const table = extensions.map(e => {
956
			return `${e.manifest.name}|${e.manifest.publisher.substr(0, 3)}|${e.manifest.version}`;
957 958
		}).join('\n');

959
		const extensionTable = `
B
Benjamin Pasero 已提交
960

961 962
${tableHeader}
${table}
963
${themeExclusionStr}
B
Benjamin Pasero 已提交
964 965

`;
966

967 968 969
		// 2000 chars is browsers de-facto limit for URLs, 400 chars are allowed for other string parts of the issue URL
		// http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
		if (encodeURIComponent(extensionTable).length > 1600) {
970
			return 'the listing length exceeds browsers\' URL characters limit';
971 972 973
		}

		return extensionTable;
974
	}
B
Benjamin Pasero 已提交
975 976
}

977 978
export class ReportPerformanceIssueAction extends Action {

M
Matt Bierner 已提交
979 980
	public static readonly ID = 'workbench.action.reportPerformanceIssue';
	public static readonly LABEL = nls.localize('reportPerformanceIssue', "Report Performance Issue");
981 982 983 984 985 986 987 988 989 990 991

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

992
	public run(appendix?: string): TPromise<boolean> {
993
		return this.integrityService.isPure().then(res => {
994
			const issueUrl = this.generatePerformanceIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, appendix);
995 996 997 998 999 1000 1001

			window.open(issueUrl);

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

1002 1003 1004 1005 1006 1007 1008 1009 1010
	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.`;
		}

1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
		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>
1027
- VM: <code>${metrics.isVMLikelyhood}%</code>
1028
- Initial Startup: <code>${metrics.initialStartup ? 'yes' : 'no'}</code>
1029
- Screen Reader: <code>${metrics.hasAccessibilitySupport ? 'yes' : 'no'}</code>
1030 1031 1032 1033 1034 1035 1036
- Empty Workspace: <code>${metrics.emptyWorkbench ? 'yes' : 'no'}</code>
- Timings:

${this.generatePerformanceTable(nodeModuleLoadTime)}

---

1037
${appendix}`
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
		);

		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 => {
1064
			return `|${e.component}|${e.task}|${e.time}|`;
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
		}).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;
	}
}

1097 1098
export class KeybindingsReferenceAction extends Action {

M
Matt Bierner 已提交
1099 1100
	public static readonly ID = 'workbench.action.keybindingsReference';
	public static readonly LABEL = nls.localize('keybindingsReference', "Keyboard Shortcuts Reference");
1101

1102
	private static readonly URL = isLinux ? product.keyboardShortcutsUrlLinux : isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin;
M
Matt Bierner 已提交
1103
	public static readonly AVAILABLE = !!KeybindingsReferenceAction.URL;
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117

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

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

C
Christof Marti 已提交
1118 1119
export class OpenDocumentationUrlAction extends Action {

M
Matt Bierner 已提交
1120 1121
	public static readonly ID = 'workbench.action.openDocumentationUrl';
	public static readonly LABEL = nls.localize('openDocumentationUrl', "Documentation");
C
Christof Marti 已提交
1122

1123
	private static readonly URL = product.documentationUrl;
M
Matt Bierner 已提交
1124
	public static readonly AVAILABLE = !!OpenDocumentationUrlAction.URL;
C
Christof Marti 已提交
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

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

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

1139 1140
export class OpenIntroductoryVideosUrlAction extends Action {

M
Matt Bierner 已提交
1141 1142
	public static readonly ID = 'workbench.action.openIntroductoryVideosUrl';
	public static readonly LABEL = nls.localize('openIntroductoryVideosUrl', "Introductory Videos");
1143

1144
	private static readonly URL = product.introductoryVideosUrl;
M
Matt Bierner 已提交
1145
	public static readonly AVAILABLE = !!OpenIntroductoryVideosUrlAction.URL;
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157

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

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

1160 1161
export class OpenTipsAndTricksUrlAction extends Action {

M
Matt Bierner 已提交
1162 1163
	public static readonly ID = 'workbench.action.openTipsAndTricksUrl';
	public static readonly LABEL = nls.localize('openTipsAndTricksUrl', "Tips and Tricks");
1164

1165
	private static readonly URL = product.tipsAndTricksUrl;
M
Matt Bierner 已提交
1166
	public static readonly AVAILABLE = !!OpenTipsAndTricksUrlAction.URL;
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180

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

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

1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
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();
	}
1193 1194
}

1195
export enum Direction {
S
sj.hwang 已提交
1196 1197 1198
	Next,
	Previous,
}
1199

S
sj.hwang 已提交
1200
export abstract class BaseNavigationAction extends Action {
1201

1202
	constructor(
S
sj.hwang 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
		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);
1223 1224
		}

S
sj.hwang 已提交
1225 1226
		if (isPanelFocus) {
			return this.navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft);
1227 1228
		}

S
sj.hwang 已提交
1229 1230
		if (isSidebarFocus) {
			return this.navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft);
1231 1232
		}

S
sj.hwang 已提交
1233
		return TPromise.as(false);
1234 1235
	}

B
Benjamin Pasero 已提交
1236
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet | IPanel> {
S
sj.hwang 已提交
1237
		return TPromise.as(true);
1238 1239
	}

B
Benjamin Pasero 已提交
1240
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IPanel> {
S
sj.hwang 已提交
1241
		return TPromise.as(true);
1242 1243
	}

B
Benjamin Pasero 已提交
1244
	protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet> {
S
sj.hwang 已提交
1245
		return TPromise.as(true);
1246 1247
	}

B
Benjamin Pasero 已提交
1248
	protected navigateToPanel(): TPromise<IPanel | boolean> {
S
sj.hwang 已提交
1249 1250
		if (!this.partService.isVisible(Parts.PANEL_PART)) {
			return TPromise.as(false);
1251 1252
		}

S
sj.hwang 已提交
1253
		const activePanelId = this.panelService.getActivePanel().getId();
B
Benjamin Pasero 已提交
1254

S
sj.hwang 已提交
1255
		return this.panelService.openPanel(activePanelId, true);
1256 1257
	}

B
Benjamin Pasero 已提交
1258
	protected navigateToSidebar(): TPromise<IViewlet | boolean> {
S
sj.hwang 已提交
1259 1260
		if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
			return TPromise.as(false);
1261 1262
		}

S
sj.hwang 已提交
1263
		const activeViewletId = this.viewletService.getActiveViewlet().getId();
B
Benjamin Pasero 已提交
1264

S
sj.hwang 已提交
1265
		return this.viewletService.openViewlet(activeViewletId, true);
1266 1267
	}

1268
	protected navigateAcrossEditorGroup(direction: Direction): TPromise<boolean> {
1269 1270
		const model = this.groupService.getStacksModel();
		const currentPosition = model.positionOfGroup(model.activeGroup);
S
sj.hwang 已提交
1271
		const nextPosition = direction === Direction.Next ? currentPosition + 1 : currentPosition - 1;
1272 1273 1274 1275 1276 1277

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

		this.groupService.focusGroup(nextPosition);
B
Benjamin Pasero 已提交
1278

1279 1280 1281
		return TPromise.as(true);
	}

B
Benjamin Pasero 已提交
1282
	protected navigateToLastActiveGroup(): TPromise<boolean> {
S
sj.hwang 已提交
1283
		const model = this.groupService.getStacksModel();
1284 1285
		const lastActiveGroup = model.activeGroup;
		this.groupService.focusGroup(lastActiveGroup);
B
Benjamin Pasero 已提交
1286

1287
		return TPromise.as(true);
1288 1289
	}

B
Benjamin Pasero 已提交
1290
	protected navigateToFirstEditorGroup(): TPromise<boolean> {
1291
		this.groupService.focusGroup(0);
B
Benjamin Pasero 已提交
1292

1293
		return TPromise.as(true);
1294 1295
	}

B
Benjamin Pasero 已提交
1296
	protected navigateToLastEditorGroup(): TPromise<boolean> {
S
sj.hwang 已提交
1297
		const model = this.groupService.getStacksModel();
1298 1299
		const lastEditorGroupPosition = model.groups.length - 1;
		this.groupService.focusGroup(lastEditorGroupPosition);
B
Benjamin Pasero 已提交
1300

1301
		return TPromise.as(true);
1302 1303
	}
}
S
sj.hwang 已提交
1304 1305 1306

export class NavigateLeftAction extends BaseNavigationAction {

M
Matt Bierner 已提交
1307 1308
	public static readonly ID = 'workbench.action.navigateLeft';
	public static readonly LABEL = nls.localize('navigateLeft', "Navigate to the View on the Left");
S
sj.hwang 已提交
1309 1310 1311 1312 1313 1314 1315 1316 1317

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

1321
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet> {
1322
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1323 1324 1325 1326
			if (isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
S
sj.hwang 已提交
1327
		}
S
sj.hwang 已提交
1328
		return this.navigateAcrossEditorGroup(Direction.Previous)
1329 1330 1331 1332 1333 1334
			.then(didNavigate => {
				if (!didNavigate && isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
S
sj.hwang 已提交
1335 1336
	}

1337
	protected navigateOnPanelFocus(isEditorGroupVertica: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet> {
S
sj.hwang 已提交
1338 1339 1340
		if (isSidebarPositionLeft) {
			return this.navigateToSidebar();
		}
B
Benjamin Pasero 已提交
1341

S
sj.hwang 已提交
1342 1343 1344
		return TPromise.as(false);
	}

1345
	protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
S
sj.hwang 已提交
1346 1347 1348
		if (isSidebarPositionLeft) {
			return TPromise.as(false);
		}
B
Benjamin Pasero 已提交
1349

S
sj.hwang 已提交
1350
		if (isEditorGroupVertical) {
1351
			return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1352
		}
B
Benjamin Pasero 已提交
1353

1354
		return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1355 1356
	}
}
1357 1358 1359

export class NavigateRightAction extends BaseNavigationAction {

M
Matt Bierner 已提交
1360 1361
	public static readonly ID = 'workbench.action.navigateRight';
	public static readonly LABEL = nls.localize('navigateRight', "Navigate to the View on the Right");
1362 1363 1364 1365 1366 1367 1368 1369 1370

	constructor(
		id: string,
		label: string,
		@IEditorGroupService groupService: IEditorGroupService,
		@IPanelService panelService: IPanelService,
		@IPartService partService: IPartService,
		@IViewletService viewletService: IViewletService
	) {
1371
		super(id, label, groupService, panelService, partService, viewletService);
1372 1373
	}

1374
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet> {
1375
		if (!isEditorGroupVertical) {
S
sj.hwang 已提交
1376 1377 1378 1379
			if (!isSidebarPositionLeft) {
				return this.navigateToSidebar();
			}
			return TPromise.as(false);
1380
		}
B
Benjamin Pasero 已提交
1381

S
sj.hwang 已提交
1382
		return this.navigateAcrossEditorGroup(Direction.Next)
1383 1384 1385 1386 1387 1388
			.then(didNavigate => {
				if (!didNavigate && !isSidebarPositionLeft) {
					return this.navigateToSidebar();
				}
				return TPromise.as(true);
			});
1389 1390
	}

1391
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IViewlet> {
1392 1393 1394
		if (!isSidebarPositionLeft) {
			return this.navigateToSidebar();
		}
B
Benjamin Pasero 已提交
1395

1396 1397 1398
		return TPromise.as(false);
	}

1399
	protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
1400 1401 1402
		if (!isSidebarPositionLeft) {
			return TPromise.as(false);
		}
B
Benjamin Pasero 已提交
1403

1404
		if (isEditorGroupVertical) {
1405
			return this.navigateToFirstEditorGroup();
1406
		}
B
Benjamin Pasero 已提交
1407

1408
		return this.navigateToLastActiveGroup();
1409 1410
	}
}
S
sj.hwang 已提交
1411 1412 1413

export class NavigateUpAction extends BaseNavigationAction {

M
Matt Bierner 已提交
1414 1415
	public static readonly ID = 'workbench.action.navigateUp';
	public static readonly LABEL = nls.localize('navigateUp', "Navigate to the View Above");
S
sj.hwang 已提交
1416 1417 1418 1419 1420 1421 1422 1423 1424

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

1428
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
S
sj.hwang 已提交
1429 1430 1431
		if (isEditorGroupVertical) {
			return TPromise.as(false);
		}
S
sj.hwang 已提交
1432
		return this.navigateAcrossEditorGroup(Direction.Previous);
S
sj.hwang 已提交
1433 1434
	}

1435
	protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
S
sj.hwang 已提交
1436
		if (isEditorGroupVertical) {
1437
			return this.navigateToLastActiveGroup();
S
sj.hwang 已提交
1438
		}
1439
		return this.navigateToLastEditorGroup();
S
sj.hwang 已提交
1440 1441
	}
}
S
sj.hwang 已提交
1442 1443 1444

export class NavigateDownAction extends BaseNavigationAction {

M
Matt Bierner 已提交
1445 1446
	public static readonly ID = 'workbench.action.navigateDown';
	public static readonly LABEL = nls.localize('navigateDown', "Navigate to the View Below");
S
sj.hwang 已提交
1447 1448 1449 1450 1451 1452 1453 1454 1455

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

1459
	protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean | IPanel> {
S
sj.hwang 已提交
1460 1461 1462
		if (isEditorGroupVertical) {
			return this.navigateToPanel();
		}
B
Benjamin Pasero 已提交
1463

S
sj.hwang 已提交
1464
		return this.navigateAcrossEditorGroup(Direction.Next)
1465 1466 1467 1468 1469 1470
			.then(didNavigate => {
				if (didNavigate) {
					return TPromise.as(true);
				}
				return this.navigateToPanel();
			});
S
sj.hwang 已提交
1471 1472
	}
}
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492

// 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 已提交
1493
		let part: Parts;
1494
		if (isSidebarFocus) {
B
Benjamin Pasero 已提交
1495 1496 1497 1498 1499
			part = Parts.SIDEBAR_PART;
		} else if (isPanelFocus) {
			part = Parts.PANEL_PART;
		} else if (isEditorFocus) {
			part = Parts.EDITOR_PART;
1500
		}
B
Benjamin Pasero 已提交
1501 1502 1503

		if (part) {
			this.partService.resizePart(part, sizeChange);
1504 1505 1506 1507 1508 1509
		}
	}
}

export class IncreaseViewSizeAction extends BaseResizeViewAction {

M
Matt Bierner 已提交
1510 1511
	public static readonly ID = 'workbench.action.increaseViewSize';
	public static readonly LABEL = nls.localize('increaseViewSize', "Increase Current View Size");
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528

	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 {

M
Matt Bierner 已提交
1529 1530
	public static readonly ID = 'workbench.action.decreaseViewSize';
	public static readonly LABEL = nls.localize('decreaseViewSize', "Decrease Current View Size");
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544

	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);
	}
1545 1546 1547 1548
}

export class ShowPreviousWindowTab extends Action {

M
Matt Bierner 已提交
1549 1550
	public static readonly ID = 'workbench.action.showPreviousWindowTab';
	public static readonly LABEL = nls.localize('showPreviousTab', "Show Previous Window Tab");
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566

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

	public run(): TPromise<boolean> {
		return this.windowsService.showPreviousWindowTab().then(() => true);
	}
}

export class ShowNextWindowTab extends Action {

M
Matt Bierner 已提交
1567 1568
	public static readonly ID = 'workbench.action.showNextWindowTab';
	public static readonly LABEL = nls.localize('showNextWindowTab', "Show Next Window Tab");
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584

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

	public run(): TPromise<boolean> {
		return this.windowsService.showNextWindowTab().then(() => true);
	}
}

export class MoveWindowTabToNewWindow extends Action {

M
Matt Bierner 已提交
1585 1586
	public static readonly ID = 'workbench.action.moveWindowTabToNewWindow';
	public static readonly LABEL = nls.localize('moveWindowTabToNewWindow', "Move Window Tab to New Window");
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602

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

	public run(): TPromise<boolean> {
		return this.windowsService.moveWindowTabToNewWindow().then(() => true);
	}
}

export class MergeAllWindowTabs extends Action {

M
Matt Bierner 已提交
1603 1604
	public static readonly ID = 'workbench.action.mergeAllWindowTabs';
	public static readonly LABEL = nls.localize('mergeAllWindowTabs', "Merge All Windows");
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620

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

	public run(): TPromise<boolean> {
		return this.windowsService.mergeAllWindowTabs().then(() => true);
	}
}

export class ToggleWindowTabsBar extends Action {

M
Matt Bierner 已提交
1621 1622
	public static readonly ID = 'workbench.action.toggleWindowTabsBar';
	public static readonly LABEL = nls.localize('toggleWindowTabsBar', "Toggle Window Tabs Bar");
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634

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

	public run(): TPromise<boolean> {
		return this.windowsService.toggleWindowTabsBar().then(() => true);
	}
1635
}
B
Benjamin Pasero 已提交
1636 1637

export class ConfigureLocaleAction extends Action {
M
Matt Bierner 已提交
1638 1639
	public static readonly ID = 'workbench.action.configureLocale';
	public static readonly LABEL = nls.localize('configureLocale', "Configure Language");
B
Benjamin Pasero 已提交
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676

	private static DEFAULT_CONTENT: string = [
		'{',
		`\t// ${nls.localize('displayLanguage', 'Defines VSCode\'s display language.')}`,
		`\t// ${nls.localize('doc', 'See {0} for a list of supported languages.', 'https://go.microsoft.com/fwlink/?LinkId=761051')}`,
		`\t// ${nls.localize('restart', 'Changing the value requires restarting VSCode.')}`,
		`\t"locale":"${language}"`,
		'}'
	].join('\n');

	constructor(id: string, label: string,
		@IFileService private fileService: IFileService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
	}

	public run(event?: any): TPromise<IEditor> {
		const file = URI.file(paths.join(this.environmentService.appSettingsHome, 'locale.json'));
		return this.fileService.resolveFile(file).then(null, (error) => {
			return this.fileService.createFile(file, ConfigureLocaleAction.DEFAULT_CONTENT);
		}).then((stat) => {
			if (!stat) {
				return undefined;
			}
			return this.editorService.openEditor({
				resource: stat.resource,
				options: {
					forceOpen: true
				}
			});
		}, (error) => {
			throw new Error(nls.localize('fail.createSettings', "Unable to create '{0}' ({1}).", getPathLabel(file, this.contextService), error));
		});
	}
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
}

export class OpenLogsFlderAction extends Action {

	static ID = 'workbench.action.openLogsFolder';
	static LABEL = nls.localize('openLogsFolder', "Open Logs Folder");

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

	public run(): TPromise<void> {
		return this.windowsService.showItemInFolder(paths.join(this.environmentService.logsPath, 'main.log'));
	}
}

export class ShowLogsAction extends Action {

	static ID = 'workbench.action.showLogs';
	static LABEL = nls.localize('showLogs', "Show Logs...");

	constructor(id: string, label: string,
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IWindowService private windowService: IWindowService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IQuickOpenService private quickOpenService: IQuickOpenService
	) {
		super(id, label);
	}

	public run(): TPromise<void> {
		const entries: IPickOpenEntry[] = [
			{ id: 'main', label: nls.localize('mainProcess', "Main"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, 'main.log')) }) },
			{ id: 'shared', label: nls.localize('sharedProcess', "Shared"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, 'sharedprocess.log')) }) },
			{ id: 'renderer', label: nls.localize('rendererProcess', "Renderer"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, `renderer${this.windowService.getCurrentWindowId()}.log`)) }) },
			{ id: 'extenshionHost', label: nls.localize('extensionHost', "Extension Host"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, `exthost${this.windowService.getCurrentWindowId()}.log`)) }) }
		];
		return this.quickOpenService.pick(entries, { placeHolder: nls.localize('selectProcess', "Select process") })
			.then(entry => {
				if (entry) {
					entry.run(null);
				}
			});
	}
B
Benjamin Pasero 已提交
1724
}