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 12 13 14 15
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/workbench/services/window/electron-browser/windowService';
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 已提交
16
import nls = require('vs/nls');
B
Benjamin Pasero 已提交
17 18
import product from 'vs/platform/product';
import pkg from 'vs/platform/package';
B
Benjamin Pasero 已提交
19
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
20 21 22 23 24 25 26 27
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 已提交
28
import paths = require('vs/base/common/paths');
J
Johannes Rieken 已提交
29 30 31 32
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';
33
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
34
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
E
Erich Gamma 已提交
35

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

39 40
// --- actions

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

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

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

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

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

export class CloseWindowAction extends Action {

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

	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
		super(id, label);
	}

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

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

80
export class SwitchWindow extends Action {
81

82 83
	public static ID = 'workbench.action.switchWindow';
	public static LABEL = nls.localize('switchWindow', "Switch Window");
84 85 86 87 88 89 90 91 92 93 94

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

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

		return TPromise.as(true);
	}
}

E
Erich Gamma 已提交
114 115 116 117 118 119 120 121 122
export class CloseFolderAction extends Action {

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

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

129
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
130
		if (this.contextService.getWorkspace()) {
B
Benjamin Pasero 已提交
131
			ipc.send('vscode:closeFolder', this.windowService.getWindowId()); // handled from browser process
E
Erich Gamma 已提交
132 133 134 135
		} else {
			this.messageService.show(Severity.Info, nls.localize('noFolderOpened', "There is currently no folder opened in this instance to close."));
		}

A
Alex Dima 已提交
136
		return TPromise.as(true);
E
Erich Gamma 已提交
137 138 139 140 141 142 143 144
	}
}

export class NewWindowAction extends Action {

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

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

153
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
154 155
		this.windowService.getWindow().openNew();

A
Alex Dima 已提交
156
		return TPromise.as(true);
E
Erich Gamma 已提交
157 158 159 160 161 162 163 164 165 166 167 168
	}
}

export class ToggleFullScreenAction extends Action {

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

	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
		super(id, label);
	}

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

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

176 177 178 179 180 181 182 183 184
export class ToggleMenuBarAction extends Action {

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

	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
		super(id, label);
	}

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

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

E
Erich Gamma 已提交
192 193 194 195 196
export class ToggleDevToolsAction extends Action {

	public static ID = 'workbench.action.toggleDevTools';
	public static LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools");

197
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
198 199 200
		super(id, label);
	}

201
	public run(): TPromise<boolean> {
202
		ipc.send('vscode:toggleDevTools', this.windowService.getWindowId());
E
Erich Gamma 已提交
203

A
Alex Dima 已提交
204
		return TPromise.as(true);
E
Erich Gamma 已提交
205 206 207
	}
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
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 已提交
227
		const applyZoom = () => {
228 229
			webFrame.setZoomLevel(level);
			browser.setZoomLevel(level); // Ensure others can listen to zoom level changes
230 231
		};

B
Benjamin Pasero 已提交
232
		this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom());
233 234 235 236
	}
}

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

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

241 242 243 244 245 246 247 248
	constructor(
		id: string,
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
	) {
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
249 250
	}

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

A
Alex Dima 已提交
254
		return TPromise.as(true);
E
Erich Gamma 已提交
255 256 257
	}
}

258
export class ZoomOutAction extends BaseZoomAction {
E
Erich Gamma 已提交
259 260

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

263 264
	constructor(
		id: string,
265 266 267 268
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
269
	) {
270
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
271 272
	}

273
	public run(): TPromise<boolean> {
274
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
275

276
		return TPromise.as(true);
E
Erich Gamma 已提交
277 278 279
	}
}

280
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
281 282 283 284

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

285 286 287
	constructor(
		id: string,
		label: string,
288 289 290
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
291
	) {
292
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
293 294
	}

295
	public run(): TPromise<boolean> {
296
		this.setConfiguredZoomLevel(0);
297

298
		return TPromise.as(true);
E
Erich Gamma 已提交
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 325 326 327 328
	}
}

/* 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");

329 330 331 332
	constructor(
		id: string,
		label: string,
		@IWindowService private windowService: IWindowService,
333
		@IEnvironmentService environmentService: IEnvironmentService
334
	) {
E
Erich Gamma 已提交
335
		super(id, label);
336

B
Benjamin Pasero 已提交
337
		this.enabled = environmentService.performance;
E
Erich Gamma 已提交
338 339 340
	}

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

		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 已提交
349
					const entry: any = {};
E
Erich Gamma 已提交
350 351 352 353 354 355 356 357 358 359 360
					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 已提交
361
			const entry: any = {};
E
Erich Gamma 已提交
362 363 364 365 366 367 368 369 370 371
			entry['Event'] = '===nodeRequire TOTAL';
			entry['Took (ms)'] = total;
			entry['Start (ms)'] = '**';
			entry['End (ms)'] = '**';
			result.push(entry);
		}

		return result;
	}

372
	public run(): TPromise<boolean> {
B
Benjamin Pasero 已提交
373
		const table: any[] = [];
E
Erich Gamma 已提交
374 375
		table.push(...this._analyzeLoaderTimes());

J
Joao Moreno 已提交
376
		const start = Math.round(remote.getGlobal('vscodeStart'));
B
Benjamin Pasero 已提交
377
		const windowShowTime = Math.round(remote.getGlobal('windowShow'));
E
Erich Gamma 已提交
378 379

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

				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 已提交
397
		const windowShowEvent: any = {};
E
Erich Gamma 已提交
398 399 400 401
		windowShowEvent['Event'] = 'Show Window at';
		windowShowEvent['Start (ms)'] = windowShowTime - start;
		table.push(windowShowEvent);

B
Benjamin Pasero 已提交
402
		const sum: any = {};
E
Erich Gamma 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415 416
		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 已提交
417
		return TPromise.as(true);
E
Erich Gamma 已提交
418 419 420 421 422 423 424 425
	}
}

export class ReloadWindowAction extends Action {

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

426 427 428 429 430 431
	constructor(
		id: string,
		label: string,
		@IWindowService private windowService: IWindowService,
		@IPartService private partService: IPartService
	) {
E
Erich Gamma 已提交
432 433 434
		super(id, label);
	}

435
	public run(): TPromise<boolean> {
436
		this.partService.setRestoreSidebar(); // we want the same sidebar after a reload restored
437
		this.windowService.getWindow().reload();
E
Erich Gamma 已提交
438

439
		return TPromise.as(true);
E
Erich Gamma 已提交
440 441 442 443 444 445 446 447 448 449 450
	}
}

export class OpenRecentAction extends Action {

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

	constructor(
		id: string,
		label: string,
B
Benjamin Pasero 已提交
451 452 453
		@IWindowService private windowService: IWindowService,
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
E
Erich Gamma 已提交
454 455 456 457
	) {
		super(id, label);
	}

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

B
Benjamin Pasero 已提交
461 462 463 464 465 466 467 468 469 470
		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 已提交
471
		function toPick(path: string, separator: ISeparator, isFolder: boolean): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
472
			return {
B
Benjamin Pasero 已提交
473 474
				resource: URI.file(path),
				isFolder,
B
Benjamin Pasero 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487
				label: paths.basename(path),
				description: paths.dirname(path),
				separator,
				run: (context) => runPick(path, context)
			};
		}

		function runPick(path: string, context): void {
			const newWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;

			ipc.send('vscode:windowOpen', [path], newWindow);
		}

B
Benjamin Pasero 已提交
488 489
		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 已提交
490 491 492 493 494 495 496 497

		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 已提交
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
	}
}

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

515
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
516 517 518 519 520 521 522 523 524 525

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

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

526
		return TPromise.as(true);
E
Erich Gamma 已提交
527
	}
528 529
}

B
Benjamin Pasero 已提交
530 531 532 533 534 535 536 537 538 539
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 已提交
540
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
B
Benjamin Pasero 已提交
541 542 543 544 545 546 547
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
	}

	public run(): TPromise<boolean> {
		return this.integrityService.isPure().then(res => {
B
Benjamin Pasero 已提交
548 549
			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 已提交
550

B
Benjamin Pasero 已提交
551
				shell.openExternal(issueUrl);
B
Benjamin Pasero 已提交
552

B
Benjamin Pasero 已提交
553 554
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
555 556 557
		});
	}

J
Johannes Rieken 已提交
558
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[]): string {
C
Christof Marti 已提交
559
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
560 561 562 563 564
		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}
C
Christof Marti 已提交
565
- Extensions: ${extensions.map(e => e.id).join(', ')}
B
Benjamin Pasero 已提交
566 567 568 569 570 571 572 573 574 575 576

Steps to Reproduce:

1.
2.`
		);

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

577 578
// --- commands

579 580 581 582 583 584
CommandsRegistry.registerCommand('_workbench.ipc', function (accessor: ServicesAccessor, ipcMessage: string, ipcArgs: any[]) {
	if (ipcMessage && Array.isArray(ipcArgs)) {
		ipc.send(ipcMessage, ...ipcArgs);
	} else {
		ipc.send(ipcMessage);
	}
585 586
});

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