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

'use strict';

8
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
9
import { TPromise } from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
10
import timer = require('vs/base/common/timer');
J
Johannes Rieken 已提交
11
import { Action } from 'vs/base/common/actions';
J
Joao Moreno 已提交
12
import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService';
13
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
14 15 16
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorInput } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
E
Erich Gamma 已提交
17
import nls = require('vs/nls');
B
Benjamin Pasero 已提交
18 19
import product from 'vs/platform/product';
import pkg from 'vs/platform/package';
B
Benjamin Pasero 已提交
20
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
21 22 23 24 25 26 27 28
import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { IExtensionManagementService, LocalExtensionType, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
B
Benjamin Pasero 已提交
29
import paths = require('vs/base/common/paths');
J
Johannes Rieken 已提交
30 31 32 33
import { isMacintosh } from 'vs/base/common/platform';
import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry, ISeparator } from 'vs/workbench/services/quickopen/common/quickOpenService';
import { KeyMod } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
34
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
35
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
E
Erich Gamma 已提交
36

B
Benjamin Pasero 已提交
37
import * as os from 'os';
B
Benjamin Pasero 已提交
38
import { ipcRenderer as ipc, webFrame, remote } from 'electron';
E
Erich Gamma 已提交
39

40 41
// --- actions

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

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

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

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

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

export class CloseWindowAction extends Action {

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

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

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

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

81
export class SwitchWindow extends Action {
82

83 84
	public static ID = 'workbench.action.switchWindow';
	public static LABEL = nls.localize('switchWindow', "Switch Window");
85 86 87 88

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

	public run(): TPromise<boolean> {
96 97
		const id = this.windowService.getWindowId();
		ipc.send('vscode:switchWindow', id);
98
		ipc.once('vscode:switchWindow', (event, workspaces) => {
99 100
			const picks: IPickOpenEntry[] = workspaces.map(w => {
				return {
101 102
					label: w.title,
					description: (id === w.id) ? nls.localize('current', "Current Window") : void 0,
103 104 105 106 107
					run: () => {
						ipc.send('vscode:showWindow', w.id);
					}
				};
			});
B
Benjamin Pasero 已提交
108
			this.quickOpenService.pick(picks, { placeHolder: nls.localize('switchWindowPlaceHolder', "Select a window") });
109 110 111 112 113 114
		});

		return TPromise.as(true);
	}
}

E
Erich Gamma 已提交
115 116
export class CloseFolderAction extends Action {

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

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

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

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

export class NewWindowAction extends Action {

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

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

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

export class ToggleFullScreenAction extends Action {

	public static ID = 'workbench.action.toggleFullScreen';
	public static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen");

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

167
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
168 169
		ipc.send('vscode:toggleFullScreen', this.windowService.getWindowId());

A
Alex Dima 已提交
170
		return TPromise.as(true);
E
Erich Gamma 已提交
171 172 173
	}
}

174 175 176 177 178
export class ToggleMenuBarAction extends Action {

	public static ID = 'workbench.action.toggleMenuBar';
	public static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar");

J
Joao Moreno 已提交
179
	constructor(id: string, label: string, @IWindowIPCService private windowService: IWindowIPCService) {
180 181 182
		super(id, label);
	}

183
	public run(): TPromise<boolean> {
184 185
		ipc.send('vscode:toggleMenuBar', this.windowService.getWindowId());

A
Alex Dima 已提交
186
		return TPromise.as(true);
187 188 189
	}
}

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

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

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

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

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

	constructor(
		id: string,
		label: string,
		@IMessageService private messageService: IMessageService,
		@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;
		}

B
Benjamin Pasero 已提交
223
		const applyZoom = () => {
224 225
			webFrame.setZoomLevel(level);
			browser.setZoomLevel(level); // Ensure others can listen to zoom level changes
226 227
		};

B
Benjamin Pasero 已提交
228
		this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom());
229 230 231 232
	}
}

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

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

237 238 239 240 241 242 243 244
	constructor(
		id: string,
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
	) {
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
245 246
	}

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

A
Alex Dima 已提交
250
		return TPromise.as(true);
E
Erich Gamma 已提交
251 252 253
	}
}

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

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

259 260
	constructor(
		id: string,
261 262 263 264
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
265
	) {
266
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
267 268
	}

269
	public run(): TPromise<boolean> {
270
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
271

272
		return TPromise.as(true);
E
Erich Gamma 已提交
273 274 275
	}
}

276
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
277 278 279 280

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

281 282 283
	constructor(
		id: string,
		label: string,
284 285 286
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
287
	) {
288
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
289 290
	}

291
	public run(): TPromise<boolean> {
292
		this.setConfiguredZoomLevel(0);
293

294
		return TPromise.as(true);
E
Erich Gamma 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
	}
}

/* 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
}
interface ILoaderEvent {
	type: LoaderEventType;
	timestamp: number;
	detail: string;
}
export class ShowStartupPerformance extends Action {

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

325 326 327
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
328
		@IWindowIPCService private windowService: IWindowIPCService,
329
		@IEnvironmentService environmentService: IEnvironmentService
330
	) {
E
Erich Gamma 已提交
331
		super(id, label);
332

B
Benjamin Pasero 已提交
333
		this.enabled = environmentService.performance;
E
Erich Gamma 已提交
334 335 336
	}

	private _analyzeLoaderTimes(): any[] {
B
Benjamin Pasero 已提交
337 338
		const stats = <ILoaderEvent[]>(<any>require).getStats();
		const result = [];
E
Erich Gamma 已提交
339 340 341 342 343 344

		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) {
B
Benjamin Pasero 已提交
345
					const entry: any = {};
E
Erich Gamma 已提交
346 347 348 349 350 351 352 353 354 355 356
					entry['Event'] = 'nodeRequire ' + stats[i].detail;
					entry['Took (ms)'] = (stats[i].timestamp - stats[i - 1].timestamp);
					total += (stats[i].timestamp - stats[i - 1].timestamp);
					entry['Start (ms)'] = '**' + stats[i - 1].timestamp;
					entry['End (ms)'] = '**' + stats[i - 1].timestamp;
					result.push(entry);
				}
			}
		}

		if (total > 0) {
B
Benjamin Pasero 已提交
357
			const entry: any = {};
E
Erich Gamma 已提交
358 359 360 361 362 363 364 365 366 367
			entry['Event'] = '===nodeRequire TOTAL';
			entry['Took (ms)'] = total;
			entry['Start (ms)'] = '**';
			entry['End (ms)'] = '**';
			result.push(entry);
		}

		return result;
	}

368
	public run(): TPromise<boolean> {
B
Benjamin Pasero 已提交
369
		const table: any[] = [];
E
Erich Gamma 已提交
370 371
		table.push(...this._analyzeLoaderTimes());

J
Joao Moreno 已提交
372
		const start = Math.round(remote.getGlobal('vscodeStart'));
B
Benjamin Pasero 已提交
373
		const windowShowTime = Math.round(remote.getGlobal('windowShow'));
E
Erich Gamma 已提交
374 375

		let lastEvent: timer.ITimerEvent;
B
Benjamin Pasero 已提交
376
		const events = timer.getTimeKeeper().getCollectedEvents();
E
Erich Gamma 已提交
377 378 379
		events.forEach((e) => {
			if (e.topic === 'Startup') {
				lastEvent = e;
B
Benjamin Pasero 已提交
380
				const entry: any = {};
E
Erich Gamma 已提交
381 382 383 384 385 386 387 388 389 390 391 392

				entry['Event'] = e.name;
				entry['Took (ms)'] = e.stopTime.getTime() - e.startTime.getTime();
				entry['Start (ms)'] = Math.max(e.startTime.getTime() - start, 0);
				entry['End (ms)'] = e.stopTime.getTime() - start;

				table.push(entry);
			}
		});

		table.push({ Event: '---------------------------' });

B
Benjamin Pasero 已提交
393
		const windowShowEvent: any = {};
E
Erich Gamma 已提交
394 395 396 397
		windowShowEvent['Event'] = 'Show Window at';
		windowShowEvent['Start (ms)'] = windowShowTime - start;
		table.push(windowShowEvent);

B
Benjamin Pasero 已提交
398
		const sum: any = {};
E
Erich Gamma 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412
		sum['Event'] = 'Total';
		sum['Took (ms)'] = lastEvent.stopTime.getTime() - start;
		table.push(sum);


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

		// Print to console
		setTimeout(() => {
			console.warn('Run the action again if you do not see the numbers!');
			(<any>console).table(table);
		}, 1000);

A
Alex Dima 已提交
413
		return TPromise.as(true);
E
Erich Gamma 已提交
414 415 416 417 418
	}
}

export class ReloadWindowAction extends Action {

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

422 423 424
	constructor(
		id: string,
		label: string,
425
		@IWindowService private windowService: IWindowService,
426 427
		@IPartService private partService: IPartService
	) {
E
Erich Gamma 已提交
428 429 430
		super(id, label);
	}

431 432 433
	run(): TPromise<boolean> {
		this.partService.setRestoreSidebar(); // we want the same sidebar after a reload restored
		return this.windowService.reloadWindow().then(() => true);
E
Erich Gamma 已提交
434 435 436 437 438 439 440 441 442 443 444
	}
}

export class OpenRecentAction extends Action {

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

	constructor(
		id: string,
		label: string,
445
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
446
		@IWindowIPCService private windowService: IWindowIPCService,
B
Benjamin Pasero 已提交
447 448
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
E
Erich Gamma 已提交
449 450 451 452
	) {
		super(id, label);
	}

453
	public run(): TPromise<boolean> {
454
		ipc.send('vscode:openRecent', this.windowService.getWindowId());
E
Erich Gamma 已提交
455

B
Benjamin Pasero 已提交
456 457 458 459 460 461 462 463 464 465
		return new TPromise<boolean>((c, e, p) => {
			ipc.once('vscode:openRecent', (event, files: string[], folders: string[]) => {
				this.openRecent(files, folders);

				c(true);
			});
		});
	}

	private openRecent(recentFiles: string[], recentFolders: string[]): void {
B
Benjamin Pasero 已提交
466
		function toPick(path: string, separator: ISeparator, isFolder: boolean): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
467
			return {
B
Benjamin Pasero 已提交
468 469
				resource: URI.file(path),
				isFolder,
B
Benjamin Pasero 已提交
470 471 472 473 474 475 476
				label: paths.basename(path),
				description: paths.dirname(path),
				separator,
				run: (context) => runPick(path, context)
			};
		}

477
		const runPick = (path: string, context) => {
B
Benjamin Pasero 已提交
478
			const newWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;
479 480
			this.windowsService.windowOpen([path], newWindow);
		};
B
Benjamin Pasero 已提交
481

B
Benjamin Pasero 已提交
482 483
		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 已提交
484 485 486 487 488 489 490 491

		const hasWorkspace = !!this.contextService.getWorkspace();

		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 已提交
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
	}
}

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

509
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
510 511 512 513 514 515 516 517 518 519

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

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

520
		return TPromise.as(true);
E
Erich Gamma 已提交
521
	}
522 523
}

B
Benjamin Pasero 已提交
524 525 526 527 528 529 530 531 532 533
export class ReportIssueAction extends Action {

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

	constructor(
		id: string,
		label: string,
		@IMessageService private messageService: IMessageService,
		@IIntegrityService private integrityService: IIntegrityService,
B
Benjamin Pasero 已提交
534
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
B
Benjamin Pasero 已提交
535 536 537 538 539 540 541
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
	}

	public run(): TPromise<boolean> {
		return this.integrityService.isPure().then(res => {
B
Benjamin Pasero 已提交
542 543
			return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
				const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, extensions);
B
Benjamin Pasero 已提交
544

B
Benjamin Pasero 已提交
545
				window.open(issueUrl);
B
Benjamin Pasero 已提交
546

B
Benjamin Pasero 已提交
547 548
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
549 550 551
		});
	}

J
Johannes Rieken 已提交
552
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[]): string {
C
Christof Marti 已提交
553
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
554 555 556 557 558
		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}
559 560 561 562 563
- Extensions:

${this.generateExtensionTable(extensions)}

---
B
Benjamin Pasero 已提交
564 565 566 567 568 569 570 571 572

Steps to Reproduce:

1.
2.`
		);

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

	private generateExtensionTable(extensions: ILocalExtension[]): string {
575 576
		let tableHeader = `|Extension|Author|Version|
|---|---|---|`;
577
		const table = extensions.map(e => {
578
			return `|${e.manifest.name}|${e.manifest.publisher}|${e.manifest.version}|`;
579 580 581 582
		}).join('\n');

		return tableHeader + '\n' + table;
	}
B
Benjamin Pasero 已提交
583 584
}

585 586
// --- commands

587 588 589
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string]) {
	const editorService = accessor.get(IWorkbenchEditorService);
	let [left, right, label] = args;
590

591 592 593
	if (!label) {
		label = nls.localize('diffLeftRightLabel', "{0} ⟷ {1}", left.toString(true), right.toString(true));
	}
594

595 596
	return TPromise.join([editorService.createInput({ resource: left }), editorService.createInput({ resource: right })]).then(inputs => {
		const [left, right] = inputs;
597

B
💄  
Benjamin Pasero 已提交
598
		const diff = new DiffEditorInput(label, void 0, <EditorInput>left, <EditorInput>right);
599 600 601 602
		return editorService.openEditor(diff);
	}).then(() => {
		return void 0;
	});
603 604
});

605 606
CommandsRegistry.registerCommand('_workbench.open', function (accessor: ServicesAccessor, args: [URI, number]) {
	const editorService = accessor.get(IWorkbenchEditorService);
B
Benjamin Pasero 已提交
607
	const [resource, column] = args;
608

609 610 611
	return editorService.openEditor({ resource }, column).then(() => {
		return void 0;
	});
612
});