actions.ts 18.6 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
import { isMacintosh } from 'vs/base/common/platform';
J
Joao Moreno 已提交
31
import { IQuickOpenService, IFilePickOpenEntry, ISeparator } from 'vs/workbench/services/quickopen/common/quickOpenService';
J
Johannes Rieken 已提交
32 33
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';
J
Joao Moreno 已提交
38
import { 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

J
Joao Moreno 已提交
83 84
	static ID = 'workbench.action.switchWindow';
	static LABEL = nls.localize('switchWindow', "Switch Window");
85 86 87 88

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

J
Joao Moreno 已提交
96 97
	run(): TPromise<void> {
		const currentWindowId = this.windowService.getCurrentWindowId();
98

J
Joao Moreno 已提交
99 100 101 102 103 104 105 106 107 108
		return this.windowsService.getWindows().then(workspaces => {
			const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window");
			const picks = workspaces.map(w => ({
				label: w.title,
				description: (currentWindowId === w.id) ? nls.localize('current', "Current Window") : void 0,
				run: () => this.windowsService.showWindow(w.id)
			}));

			this.quickOpenService.pick(picks, { placeHolder });
		});
109 110 111
	}
}

E
Erich Gamma 已提交
112 113
export class CloseFolderAction extends Action {

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

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

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

J
Joao Moreno 已提交
133
		return this.windowService.closeFolder();
E
Erich Gamma 已提交
134 135 136 137 138
	}
}

export class NewWindowAction extends Action {

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

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

J
Joao Moreno 已提交
150 151
	run(): TPromise<void> {
		return this.windowsService.openNewWindow();
E
Erich Gamma 已提交
152 153 154 155 156
	}
}

export class ToggleFullScreenAction extends Action {

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

J
Joao Moreno 已提交
160
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
E
Erich Gamma 已提交
161 162 163
		super(id, label);
	}

J
Joao Moreno 已提交
164 165
	run(): TPromise<void> {
		return this.windowService.toggleFullScreen();
E
Erich Gamma 已提交
166 167 168
	}
}

169 170
export class ToggleMenuBarAction extends Action {

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

J
Joao Moreno 已提交
174
	constructor(id: string, label: string, @IWindowService private windowService: IWindowService) {
175 176 177
		super(id, label);
	}

J
Joao Moreno 已提交
178 179
	run(): TPromise<void> {
		return this.windowService.toggleMenuBar();
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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
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 已提交
216
		const applyZoom = () => {
217
			webFrame.setZoomLevel(level);
B
Benjamin Pasero 已提交
218
			browser.setZoomFactor(webFrame.getZoomFactor());
219
			browser.setZoomLevel(level); // Ensure others can listen to zoom level changes
220 221
		};

B
Benjamin Pasero 已提交
222
		this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom());
223 224 225 226
	}
}

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

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

231 232 233 234 235 236 237 238
	constructor(
		id: string,
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
	) {
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
239 240
	}

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

A
Alex Dima 已提交
244
		return TPromise.as(true);
E
Erich Gamma 已提交
245 246 247
	}
}

248
export class ZoomOutAction extends BaseZoomAction {
E
Erich Gamma 已提交
249 250

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

253 254
	constructor(
		id: string,
255 256 257 258
		label: string,
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
259
	) {
260
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
261 262
	}

263
	public run(): TPromise<boolean> {
264
		this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1);
265

266
		return TPromise.as(true);
E
Erich Gamma 已提交
267 268 269
	}
}

270
export class ZoomResetAction extends BaseZoomAction {
E
Erich Gamma 已提交
271 272 273 274

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

275 276 277
	constructor(
		id: string,
		label: string,
278 279 280
		@IMessageService messageService: IMessageService,
		@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
		@IConfigurationEditingService configurationEditingService: IConfigurationEditingService
281
	) {
282
		super(id, label, messageService, configurationService, configurationEditingService);
E
Erich Gamma 已提交
283 284
	}

285
	public run(): TPromise<boolean> {
286
		this.setConfiguredZoomLevel(0);
287

288
		return TPromise.as(true);
E
Erich Gamma 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	}
}

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

319 320 321
	constructor(
		id: string,
		label: string,
J
Joao Moreno 已提交
322
		@IWindowService private windowService: IWindowService,
323
		@IEnvironmentService environmentService: IEnvironmentService
324
	) {
E
Erich Gamma 已提交
325
		super(id, label);
326

B
Benjamin Pasero 已提交
327
		this.enabled = environmentService.performance;
E
Erich Gamma 已提交
328 329 330
	}

	private _analyzeLoaderTimes(): any[] {
B
Benjamin Pasero 已提交
331 332
		const stats = <ILoaderEvent[]>(<any>require).getStats();
		const result = [];
E
Erich Gamma 已提交
333 334 335 336 337 338

		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 已提交
339
					const entry: any = {};
E
Erich Gamma 已提交
340 341 342 343 344 345 346 347 348 349 350
					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 已提交
351
			const entry: any = {};
E
Erich Gamma 已提交
352 353 354 355 356 357 358 359 360 361
			entry['Event'] = '===nodeRequire TOTAL';
			entry['Took (ms)'] = total;
			entry['Start (ms)'] = '**';
			entry['End (ms)'] = '**';
			result.push(entry);
		}

		return result;
	}

362
	public run(): TPromise<boolean> {
B
Benjamin Pasero 已提交
363
		const table: any[] = [];
E
Erich Gamma 已提交
364 365
		table.push(...this._analyzeLoaderTimes());

J
Joao Moreno 已提交
366
		const start = Math.round(remote.getGlobal('vscodeStart'));
B
Benjamin Pasero 已提交
367
		const windowShowTime = Math.round(remote.getGlobal('windowShow'));
E
Erich Gamma 已提交
368 369

		let lastEvent: timer.ITimerEvent;
B
Benjamin Pasero 已提交
370
		const events = timer.getTimeKeeper().getCollectedEvents();
E
Erich Gamma 已提交
371 372 373
		events.forEach((e) => {
			if (e.topic === 'Startup') {
				lastEvent = e;
B
Benjamin Pasero 已提交
374
				const entry: any = {};
E
Erich Gamma 已提交
375 376 377 378 379 380 381 382 383 384 385 386

				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 已提交
387
		const windowShowEvent: any = {};
E
Erich Gamma 已提交
388 389 390 391
		windowShowEvent['Event'] = 'Show Window at';
		windowShowEvent['Start (ms)'] = windowShowTime - start;
		table.push(windowShowEvent);

B
Benjamin Pasero 已提交
392
		const sum: any = {};
E
Erich Gamma 已提交
393 394 395 396 397
		sum['Event'] = 'Total';
		sum['Took (ms)'] = lastEvent.stopTime.getTime() - start;
		table.push(sum);

		// Show dev tools
J
Joao Moreno 已提交
398
		this.windowService.openDevTools();
E
Erich Gamma 已提交
399 400 401 402 403 404 405

		// 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 已提交
406
		return TPromise.as(true);
E
Erich Gamma 已提交
407 408 409 410 411
	}
}

export class ReloadWindowAction extends Action {

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

415 416 417
	constructor(
		id: string,
		label: string,
418
		@IWindowService private windowService: IWindowService,
419 420
		@IPartService private partService: IPartService
	) {
E
Erich Gamma 已提交
421 422 423
		super(id, label);
	}

424 425 426
	run(): TPromise<boolean> {
		this.partService.setRestoreSidebar(); // we want the same sidebar after a reload restored
		return this.windowService.reloadWindow().then(() => true);
E
Erich Gamma 已提交
427 428 429 430 431 432 433 434 435 436 437
	}
}

export class OpenRecentAction extends Action {

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

	constructor(
		id: string,
		label: string,
438
		@IWindowsService private windowsService: IWindowsService,
J
Joao Moreno 已提交
439
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
440 441
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService
E
Erich Gamma 已提交
442 443 444 445
	) {
		super(id, label);
	}

J
Joao Moreno 已提交
446 447 448
	public run(): TPromise<void> {
		return this.windowService.getRecentlyOpen()
			.then(({ files, folders }) => this.openRecent(files, folders));
B
Benjamin Pasero 已提交
449 450 451
	}

	private openRecent(recentFiles: string[], recentFolders: string[]): void {
B
Benjamin Pasero 已提交
452
		function toPick(path: string, separator: ISeparator, isFolder: boolean): IFilePickOpenEntry {
B
Benjamin Pasero 已提交
453
			return {
B
Benjamin Pasero 已提交
454 455
				resource: URI.file(path),
				isFolder,
B
Benjamin Pasero 已提交
456 457 458 459 460 461 462
				label: paths.basename(path),
				description: paths.dirname(path),
				separator,
				run: (context) => runPick(path, context)
			};
		}

463
		const runPick = (path: string, context) => {
B
Benjamin Pasero 已提交
464
			const newWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0;
465 466
			this.windowsService.windowOpen([path], newWindow);
		};
B
Benjamin Pasero 已提交
467

B
Benjamin Pasero 已提交
468 469
		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 已提交
470 471 472 473 474 475 476 477

		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 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
	}
}

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

495
	public run(): TPromise<boolean> {
E
Erich Gamma 已提交
496 497 498 499 500 501 502 503 504 505

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

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

506
		return TPromise.as(true);
E
Erich Gamma 已提交
507
	}
508 509
}

B
Benjamin Pasero 已提交
510 511 512 513 514 515 516 517 518 519
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 已提交
520
		@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
B
Benjamin Pasero 已提交
521 522 523 524 525 526 527
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
	) {
		super(id, label);
	}

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

B
Benjamin Pasero 已提交
531
				window.open(issueUrl);
B
Benjamin Pasero 已提交
532

B
Benjamin Pasero 已提交
533 534
				return TPromise.as(true);
			});
B
Benjamin Pasero 已提交
535 536 537
		});
	}

J
Johannes Rieken 已提交
538
	private generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string, isPure: boolean, extensions: ILocalExtension[]): string {
C
Christof Marti 已提交
539
		// Avoid backticks, these can trigger XSS detectors. (https://github.com/Microsoft/vscode/issues/13098)
B
Benjamin Pasero 已提交
540 541 542 543 544
		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}
545 546 547 548 549
- Extensions:

${this.generateExtensionTable(extensions)}

---
B
Benjamin Pasero 已提交
550 551 552 553 554 555 556 557 558

Steps to Reproduce:

1.
2.`
		);

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

	private generateExtensionTable(extensions: ILocalExtension[]): string {
561 562
		let tableHeader = `|Extension|Author|Version|
|---|---|---|`;
563
		const table = extensions.map(e => {
564
			return `|${e.manifest.name}|${e.manifest.publisher}|${e.manifest.version}|`;
565 566 567 568
		}).join('\n');

		return tableHeader + '\n' + table;
	}
B
Benjamin Pasero 已提交
569 570
}

571 572
// --- commands

573 574 575
CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string]) {
	const editorService = accessor.get(IWorkbenchEditorService);
	let [left, right, label] = args;
576

577 578 579
	if (!label) {
		label = nls.localize('diffLeftRightLabel', "{0} ⟷ {1}", left.toString(true), right.toString(true));
	}
580

581 582
	return TPromise.join([editorService.createInput({ resource: left }), editorService.createInput({ resource: right })]).then(inputs => {
		const [left, right] = inputs;
583

B
💄  
Benjamin Pasero 已提交
584
		const diff = new DiffEditorInput(label, void 0, <EditorInput>left, <EditorInput>right);
585 586 587 588
		return editorService.openEditor(diff);
	}).then(() => {
		return void 0;
	});
589 590
});

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

595 596 597
	return editorService.openEditor({ resource }, column).then(() => {
		return void 0;
	});
598
});