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

J
Joao Moreno 已提交
6
import 'vs/css!./media/extensionActions';
J
Joao Moreno 已提交
7
import { localize } from 'vs/nls';
J
Joao Moreno 已提交
8
import { TPromise } from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
9
import { Action } from 'vs/base/common/actions';
10
import severity from 'vs/base/common/severity';
11
import paths = require('vs/base/common/paths');
J
Joao Moreno 已提交
12
import Event from 'vs/base/common/event';
J
Joao Moreno 已提交
13
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
J
Joao Moreno 已提交
14
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
15
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, ConfigurationKey } from './extensions';
J
Joao Moreno 已提交
16
import { LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement';
17
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
18
import { IMessageService, LaterAction } from 'vs/platform/message/common/message';
19
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
20 21 22
import { ToggleViewletAction } from 'vs/workbench/browser/viewlet';
import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Joao Moreno 已提交
23
import { Query } from '../common/extensionQuery';
J
Joao Moreno 已提交
24
import { shell, remote } from 'electron';
S
Sandeep Somavarapu 已提交
25
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate';
J
Joao Moreno 已提交
26 27 28
import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
J
Joao Moreno 已提交
29 30

const dialog = remote.dialog;
J
Joao Moreno 已提交
31

32 33
export class InstallAction extends Action {

J
Joao Moreno 已提交
34 35
	private static InstallLabel = localize('installAction', "Install");
	private static InstallingLabel = localize('installing', "Installing");
J
Joao Moreno 已提交
36 37 38 39

	private static Class = 'extension-action install';
	private static InstallingClass = 'extension-action install installing';

J
Joao Moreno 已提交
40
	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
41 42 43
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }
44

45 46 47
	constructor(
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
J
Joao Moreno 已提交
48
		super('extensions.install', InstallAction.InstallLabel, InstallAction.Class, false);
49

50
		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
J
Joao Moreno 已提交
51
		this.update();
52 53
	}

J
Joao Moreno 已提交
54
	private update(): void {
J
Joao Moreno 已提交
55
		if (!this.extension || this.extension.type === LocalExtensionType.System) {
J
Joao Moreno 已提交
56
			this.enabled = false;
J
Joao Moreno 已提交
57
			this.class = InstallAction.Class;
J
Joao Moreno 已提交
58 59 60 61
			this.label = InstallAction.InstallLabel;
			return;
		}

62
		this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && this.extension.state === ExtensionState.Uninstalled;
J
Joao Moreno 已提交
63 64 65 66 67 68 69 70

		if (this.extension.state === ExtensionState.Installing) {
			this.label = InstallAction.InstallingLabel;
			this.class = InstallAction.InstallingClass;
		} else {
			this.label = InstallAction.InstallLabel;
			this.class = InstallAction.Class;
		}
71 72
	}

J
Joao Moreno 已提交
73
	run(): TPromise<any> {
74
		return this.extensionsWorkbenchService.install(this.extension);
75 76
	}

J
Joao Moreno 已提交
77 78 79
	dispose(): void {
		super.dispose();
		this.disposables = dispose(this.disposables);
80 81
	}
}
J
Joao Moreno 已提交
82

J
Joao Moreno 已提交
83
export class UninstallAction extends Action {
J
Joao Moreno 已提交
84

J
Joao Moreno 已提交
85
	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
86 87 88
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }
J
Joao Moreno 已提交
89

90
	constructor(
91 92 93
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IMessageService private messageService: IMessageService,
		@IInstantiationService private instantiationService: IInstantiationService
94
	) {
J
Joao Moreno 已提交
95
		super('extensions.uninstall', localize('uninstall', "Uninstall"), 'extension-action uninstall', false);
J
Joao Moreno 已提交
96

97
		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.onChange()));
J
Joao Moreno 已提交
98
		this.update();
J
Joao Moreno 已提交
99
	}
J
Joao Moreno 已提交
100

101 102 103 104 105
	private onChange() {
		const local = this.extensionsWorkbenchService.local.filter(e => e.identifier === this.extension.identifier);
		this.extension = local.length ? local[0] : this.extension;
	}

J
Joao Moreno 已提交
106 107 108 109 110 111
	private update(): void {
		if (!this.extension) {
			this.enabled = false;
			return;
		}

J
Joao Moreno 已提交
112 113 114 115 116
		if (this.extension.type !== LocalExtensionType.User) {
			this.enabled = false;
			return;
		}

117
		this.enabled = this.extension.state === ExtensionState.Installed || this.extension.state === ExtensionState.Disabled;
J
Joao Moreno 已提交
118
	}
J
Joao Moreno 已提交
119

J
Joao Moreno 已提交
120
	run(): TPromise<any> {
J
Joao Moreno 已提交
121
		if (!window.confirm(localize('deleteSure', "Are you sure you want to uninstall '{0}'?", this.extension.displayName))) {
J
Joao Moreno 已提交
122 123
			return TPromise.as(null);
		}
J
Joao Moreno 已提交
124

125 126 127
		return this.extensionsWorkbenchService.uninstall(this.extension).then(() => {
			this.messageService.show(severity.Info, {
				message: localize('postUninstallMessage', "{0} was successfully uninstalled. Restart to deactivate it.", this.extension.displayName),
128
				actions: [this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, localize('restartNow', "Restart Now")), LaterAction]
129 130
			});
		});
J
Joao Moreno 已提交
131
	}
J
Joao Moreno 已提交
132

J
Joao Moreno 已提交
133 134 135 136 137
	dispose(): void {
		super.dispose();
		this.disposables = dispose(this.disposables);
	}
}
J
Joao Moreno 已提交
138 139 140

export class CombinedInstallAction extends Action {

J
Joao Moreno 已提交
141
	private static NoExtensionClass = 'extension-action install no-extension';
J
Joao Moreno 已提交
142 143 144
	private installAction: InstallAction;
	private uninstallAction: UninstallAction;
	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
145 146 147 148 149 150 151
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) {
		this._extension = extension;
		this.installAction.extension = extension;
		this.uninstallAction.extension = extension;
	}
J
Joao Moreno 已提交
152

153 154 155
	constructor(
		@IInstantiationService instantiationService: IInstantiationService
	) {
J
Joao Moreno 已提交
156 157
		super('extensions.combinedInstall', '', '', false);

J
Joao Moreno 已提交
158 159
		this.installAction = instantiationService.createInstance(InstallAction);
		this.uninstallAction = instantiationService.createInstance(UninstallAction);
J
Joao Moreno 已提交
160 161
		this.disposables.push(this.installAction, this.uninstallAction);

162
		this.installAction.onDidChange(this.update, this, this.disposables);
163
		this.uninstallAction.onDidChange(this.update, this, this.disposables);
J
Joao Moreno 已提交
164 165 166 167
		this.update();
	}

	private update(): void {
J
Joao Moreno 已提交
168
		if (!this.extension || this.extension.type === LocalExtensionType.System) {
J
Joao Moreno 已提交
169 170 171
			this.enabled = false;
			this.class = CombinedInstallAction.NoExtensionClass;
		} else if (this.installAction.enabled) {
J
Joao Moreno 已提交
172 173 174 175 176 177 178
			this.enabled = true;
			this.label = this.installAction.label;
			this.class = this.installAction.class;
		} else if (this.uninstallAction.enabled) {
			this.enabled = true;
			this.label = this.uninstallAction.label;
			this.class = this.uninstallAction.class;
J
Joao Moreno 已提交
179 180 181 182
		} else if (this.extension.state === ExtensionState.Installing) {
			this.enabled = false;
			this.label = this.installAction.label;
			this.class = this.installAction.class;
J
Joao Moreno 已提交
183 184
		} else {
			this.enabled = false;
J
Joao Moreno 已提交
185 186
			this.label = this.installAction.label;
			this.class = this.installAction.class;
J
Joao Moreno 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199
		}
	}

	run(): TPromise<any> {
		if (this.installAction.enabled) {
			return this.installAction.run();
		} else if (this.uninstallAction.enabled) {
			return this.uninstallAction.run();
		}

		return TPromise.as(null);
	}

J
Joao Moreno 已提交
200 201 202 203 204 205 206 207
	dispose(): void {
		super.dispose();
		this.disposables = dispose(this.disposables);
	}
}

export class UpdateAction extends Action {

J
Joao Moreno 已提交
208
	private static EnabledClass = 'extension-action update';
J
Johannes Rieken 已提交
209
	private static DisabledClass = `${UpdateAction.EnabledClass} disabled`;
J
Joao Moreno 已提交
210 211

	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
212 213 214
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }
J
Joao Moreno 已提交
215

216 217 218
	constructor(
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
J
Joao Moreno 已提交
219
		super('extensions.update', localize('updateAction', "Update"), UpdateAction.DisabledClass, false);
J
Joao Moreno 已提交
220

J
Joao Moreno 已提交
221 222
		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
		this.update();
J
Joao Moreno 已提交
223 224
	}

J
Joao Moreno 已提交
225 226 227 228 229 230 231
	private update(): void {
		if (!this.extension) {
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
			return;
		}

J
Joao Moreno 已提交
232 233 234 235 236 237
		if (this.extension.type !== LocalExtensionType.User) {
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
			return;
		}

238
		const canInstall = this.extensionsWorkbenchService.canInstall(this.extension);
J
Joao Moreno 已提交
239
		const isInstalled = this.extension.state === ExtensionState.Installed
240
			|| this.extension.state === ExtensionState.Disabled;
J
Joao Moreno 已提交
241

242
		this.enabled = canInstall && isInstalled && this.extension.outdated;
243 244 245
		this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass;
	}

J
Joao Moreno 已提交
246
	run(): TPromise<any> {
247
		return this.extensionsWorkbenchService.install(this.extension);
J
Joao Moreno 已提交
248 249
	}

J
Joao Moreno 已提交
250 251 252 253 254 255 256 257 258
	dispose(): void {
		super.dispose();
		this.disposables = dispose(this.disposables);
	}
}

export class EnableAction extends Action {

	private static EnabledClass = 'extension-action enable';
J
Johannes Rieken 已提交
259
	private static DisabledClass = `${EnableAction.EnabledClass} disabled`;
J
Joao Moreno 已提交
260 261

	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
262 263 264
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }
J
Joao Moreno 已提交
265 266

	constructor(
267
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
J
Joao Moreno 已提交
268 269 270
	) {
		super('extensions.enable', localize('enableAction', "Enable"), EnableAction.DisabledClass, false);

J
Joao Moreno 已提交
271 272
		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
		this.update();
J
Joao Moreno 已提交
273 274
	}

J
Joao Moreno 已提交
275 276 277 278 279 280 281
	private update(): void {
		if (!this.extension) {
			this.enabled = false;
			this.class = EnableAction.DisabledClass;
			return;
		}

282
		this.enabled = this.extension.state === ExtensionState.Disabled;
J
Joao Moreno 已提交
283 284 285 286
		this.class = this.enabled ? EnableAction.EnabledClass : EnableAction.DisabledClass;
	}

	run(): TPromise<any> {
287 288 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
		return this.extensionsWorkbenchService.setEnablement(this.extension, true);
	}
}

export class DisableAction extends Action {

	private static EnabledClass = 'extension-action disable';
	private static DisabledClass = `${DisableAction.EnabledClass} disabled`;

	private disposables: IDisposable[] = [];
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }

	constructor(
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
	) {
		super('extensions.disable', localize('disableAction', "Disable"), DisableAction.DisabledClass, false);

		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
		this.update();
	}

	private update(): void {
		if (!this.extension) {
			this.enabled = false;
			this.class = DisableAction.DisabledClass;
			return;
J
Joao Moreno 已提交
315 316
		}

317 318
		this.enabled = this.extension.state === ExtensionState.Installed;
		this.class = this.enabled ? DisableAction.EnabledClass : DisableAction.DisabledClass;
J
Joao Moreno 已提交
319 320
	}

321 322
	run(): TPromise<any> {
		return this.extensionsWorkbenchService.setEnablement(this.extension, false);
J
Joao Moreno 已提交
323
	}
324
}
J
Joao Moreno 已提交
325 326 327

export class UpdateAllAction extends Action {

J
Joao Moreno 已提交
328
	static ID = 'workbench.extensions.action.updateAllExtensions';
329 330
	static LABEL = localize('updateAll', "Update All Extensions");

J
Joao Moreno 已提交
331 332 333
	private disposables: IDisposable[] = [];

	constructor(
334 335
		id = UpdateAllAction.ID,
		label = UpdateAllAction.LABEL,
J
Joao Moreno 已提交
336 337
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
338
		super(id, label, '', false);
J
Joao Moreno 已提交
339 340 341 342 343

		this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
		this.update();
	}

344 345
	private get outdated(): IExtension[] {
		return this.extensionsWorkbenchService.local.filter(
J
Joao Moreno 已提交
346
			e => this.extensionsWorkbenchService.canInstall(e)
347
				&& e.type === LocalExtensionType.User
348
				&& (e.state === ExtensionState.Installed || e.state === ExtensionState.Disabled)
349
				&& e.outdated
J
Joao Moreno 已提交
350
		);
J
Joao Moreno 已提交
351 352 353
	}

	private update(): void {
354
		this.enabled = this.outdated.length > 0;
J
Joao Moreno 已提交
355 356
	}

J
Johannes Rieken 已提交
357
	run(promptToInstallDependencies: boolean = true, ): TPromise<any> {
358
		return TPromise.join(this.outdated.map(e => this.extensionsWorkbenchService.install(e, promptToInstallDependencies)));
J
Joao Moreno 已提交
359 360 361 362 363 364 365
	}

	dispose(): void {
		super.dispose();
		this.disposables = dispose(this.disposables);
	}
}
366 367 368

export class OpenExtensionsViewletAction extends ToggleViewletAction {

J
Joao Moreno 已提交
369
	static ID = VIEWLET_ID;
370 371 372 373 374 375 376 377 378 379 380 381
	static LABEL = localize('toggleExtensionsViewlet', "Show Extensions");

	constructor(
		id: string,
		label: string,
		@IViewletService viewletService: IViewletService,
		@IWorkbenchEditorService editorService: IWorkbenchEditorService
	) {
		super(id, label, VIEWLET_ID, viewletService, editorService);
	}
}

I
isidor 已提交
382 383 384 385 386
export class InstallExtensionsAction extends OpenExtensionsViewletAction {
	static ID = 'workbench.extensions.action.installExtensions';
	static LABEL = localize('installExtensions', "Install Extensions");
}

J
Joao Moreno 已提交
387
export class ShowInstalledExtensionsAction extends Action {
388

J
Joao Moreno 已提交
389 390
	static ID = 'workbench.extensions.action.showInstalledExtensions';
	static LABEL = localize('showInstalledExtensions', "Show Installed Extensions");
391 392 393 394

	constructor(
		id: string,
		label: string,
395 396
		@IViewletService private viewletService: IViewletService,
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
397
	) {
398
		super(id, label, 'clear-extensions', true);
399 400 401 402 403 404
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
405
				viewlet.search('');
406 407 408 409 410
				viewlet.focus();
			});
	}
}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
export class ShowDisabledExtensionsAction extends Action {

	static ID = 'workbench.extensions.action.showDisabledExtensions';
	static LABEL = localize('showDisabledExtensions', "Show Disabled Extensions");

	constructor(
		id: string,
		label: string,
		@IViewletService private viewletService: IViewletService,
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
		super(id, label, 'null', true);
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@disabled ');
				viewlet.focus();
			});
	}
}

J
Joao Moreno 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
export class ClearExtensionsInputAction extends ShowInstalledExtensionsAction {

	static ID = 'workbench.extensions.action.clearExtensionsInput';
	static LABEL = localize('clearExtensionsInput', "Clear Extensions Input");

	private disposables: IDisposable[] = [];

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
		@IViewletService viewletService: IViewletService,
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
		super(id, label, viewletService, extensionsWorkbenchService);
450
		this.enabled = false;
J
Joao Moreno 已提交
451 452 453 454 455 456 457 458 459 460 461 462
		onSearchChange(this.onSearchChange, this, this.disposables);
	}

	private onSearchChange(value: string): void {
		this.enabled = !!value;
	}

	dispose(): void {
		this.disposables = dispose(this.disposables);
	}
}

J
Joao Moreno 已提交
463
export class ShowOutdatedExtensionsAction extends Action {
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479

	static ID = 'workbench.extensions.action.listOutdatedExtensions';
	static LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions");

	constructor(
		id: string,
		label: string,
		@IViewletService private viewletService: IViewletService
	) {
		super(id, label, null, true);
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
480
				viewlet.search('@outdated ');
481 482 483 484 485 486 487 488
				viewlet.focus();
			});
	}

	protected isEnabled(): boolean {
		return true;
	}
}
J
Joao Moreno 已提交
489 490 491 492 493 494 495 496 497 498 499

export class ShowPopularExtensionsAction extends Action {

	static ID = 'workbench.extensions.action.showPopularExtensions';
	static LABEL = localize('showPopularExtensions', "Show Popular Extensions");

	constructor(
		id: string,
		label: string,
		@IViewletService private viewletService: IViewletService
	) {
500
		super(id, label, null, true);
J
Joao Moreno 已提交
501 502 503 504 505 506
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
507
				viewlet.search('@sort:installs ');
J
Joao Moreno 已提交
508 509 510 511 512 513 514 515 516
				viewlet.focus();
			});
	}

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

J
Joao Moreno 已提交
517
export class ShowRecommendedExtensionsAction extends Action {
J
Joao Moreno 已提交
518

J
Joao Moreno 已提交
519
	static ID = 'workbench.extensions.action.showRecommendedExtensions';
J
Joao Moreno 已提交
520
	static LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions");
J
Joao Moreno 已提交
521 522 523 524 525 526

	constructor(
		id: string,
		label: string,
		@IViewletService private viewletService: IViewletService
	) {
527
		super(id, label, null, true);
J
Joao Moreno 已提交
528 529 530 531 532 533
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
534
				viewlet.search('@recommended ');
J
Joao Moreno 已提交
535 536 537 538
				viewlet.focus();
			});
	}

J
Joao Moreno 已提交
539 540 541 542 543
	protected isEnabled(): boolean {
		return true;
	}
}

S
Sandeep Somavarapu 已提交
544 545 546 547 548 549 550 551
export class ShowWorkspaceRecommendedExtensionsAction extends Action {

	static ID = 'workbench.extensions.action.showWorkspaceRecommendedExtensions';
	static LABEL = localize('showWorkspaceRecommendedExtensions', "Show Workspace Recommended Extensions");

	constructor(
		id: string,
		label: string,
S
Sandeep Somavarapu 已提交
552
		@IWorkspaceContextService contextService: IWorkspaceContextService,
S
Sandeep Somavarapu 已提交
553 554
		@IViewletService private viewletService: IViewletService
	) {
S
Sandeep Somavarapu 已提交
555
		super(id, label, null, !!contextService.getWorkspace());
S
Sandeep Somavarapu 已提交
556 557 558 559 560 561
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
562
				viewlet.search('@recommended:workspace ');
S
Sandeep Somavarapu 已提交
563 564 565 566 567 568 569 570 571
				viewlet.focus();
			});
	}

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

J
Joao Moreno 已提交
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
export class ChangeSortAction extends Action {

	private query: Query;
	private disposables: IDisposable[] = [];

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
		private sortBy: string,
		private sortOrder: string,
		@IViewletService private viewletService: IViewletService
	) {
		super(id, label, null, true);

J
Joao Moreno 已提交
587
		if (sortBy === undefined && sortOrder === undefined) {
J
Joao Moreno 已提交
588 589 590 591
			throw new Error('bad arguments');
		}

		this.query = Query.parse('');
592
		this.enabled = false;
J
Joao Moreno 已提交
593 594 595 596 597 598
		onSearchChange(this.onSearchChange, this, this.disposables);
	}

	private onSearchChange(value: string): void {
		const query = Query.parse(value);
		this.query = new Query(query.value, this.sortBy || query.sortBy, this.sortOrder || query.sortOrder);
599
		this.enabled = value && this.query.isValid() && !this.query.equals(query);
J
Joao Moreno 已提交
600 601 602 603 604 605 606 607 608 609 610
	}

	run(): TPromise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search(this.query.toString());
				viewlet.focus();
			});
	}

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
	protected isEnabled(): boolean {
		return true;
	}
}

export class OpenExtensionsFolderAction extends Action {

	static ID = 'workbench.extensions.action.openExtensionsFolder';
	static LABEL = localize('openExtensionsFolder', "Open Extensions Folder");

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

	run(): TPromise<any> {
		const extensionsHome = this.environmentService.extensionsPath;
		shell.showItemInFolder(paths.normalize(extensionsHome, true));

		return TPromise.as(true);
	}

J
Joao Moreno 已提交
636 637 638
	protected isEnabled(): boolean {
		return true;
	}
S
Sandeep Somavarapu 已提交
639 640
}

S
Sandeep Somavarapu 已提交
641
export class ConfigureWorkspaceRecommendedExtensionsAction extends Action {
J
Joao Moreno 已提交
642

S
Sandeep Somavarapu 已提交
643
	static ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions';
644
	static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)");
S
Sandeep Somavarapu 已提交
645

J
Joao Moreno 已提交
646 647 648 649 650 651 652 653 654
	constructor(
		id: string,
		label: string,
		@IFileService private fileService: IFileService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IExtensionsWorkbenchService private extensionsService: IExtensionsWorkbenchService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IMessageService private messageService: IMessageService
	) {
S
Sandeep Somavarapu 已提交
655
		super(id, label, null, !!contextService.getWorkspace());
S
Sandeep Somavarapu 已提交
656 657 658
	}

	public run(event: any): TPromise<any> {
J
Joao Moreno 已提交
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
		return this.openExtensionsFile();
	}

	private openExtensionsFile(): TPromise<any> {
		if (!this.contextService.getWorkspace()) {
			this.messageService.show(severity.Info, localize('ConfigureWorkspaceRecommendations.noWorkspace', 'Recommendations are only available on a workspace folder.'));
			return TPromise.as(undefined);
		}

		return this.getOrCreateExtensionsFile().then(value => {
			return this.editorService.openEditor({
				resource: value.extensionsFileResource,
				options: {
					forceOpen: true,
					pinned: value.created
				},
			});
		}, (error) => TPromise.wrapError(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error))));
	}

	private getOrCreateExtensionsFile(): TPromise<{ created: boolean, extensionsFileResource: URI }> {
J
Johannes Rieken 已提交
680
		const extensionsFileResource = URI.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode', `${ConfigurationKey}.json`));
J
Joao Moreno 已提交
681 682 683 684

		return this.fileService.resolveContent(extensionsFileResource).then(content => {
			return { created: false, extensionsFileResource };
		}, err => {
685
			return this.fileService.updateContent(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
J
Joao Moreno 已提交
686 687 688
				return { created: true, extensionsFileResource };
			});
		});
S
Sandeep Somavarapu 已提交
689
	}
J
Joao Moreno 已提交
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
}

export class InstallVSIXAction extends Action {

	static ID = 'workbench.extensions.action.installVSIX';
	static LABEL = localize('installVSIX', "Install from VSIX...");

	constructor(
		id = InstallVSIXAction.ID,
		label = InstallVSIXAction.LABEL,
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
	) {
		super(id, label, 'extension-action install-vsix', true);
	}

	run(): TPromise<any> {
		const result = dialog.showOpenDialog(remote.getCurrentWindow(), {
			filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
			properties: ['openFile']
		});

		if (!result) {
			return TPromise.as(null);
		}

		return TPromise.join(result.map(vsix => this.extensionsWorkbenchService.install(vsix)));
	}
J
Joao Moreno 已提交
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
}

export class BuiltinStatusLabelAction extends Action {

	private static Class = 'extension-action built-in-status';

	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }

	constructor() {
		super('extensions.install', localize('builtin', "Built-in"), '', false);
	}

	private update(): void {
		if (this.extension && this.extension.type === LocalExtensionType.System) {
J
Johannes Rieken 已提交
733
			this.class = `${BuiltinStatusLabelAction.Class} system`;
J
Joao Moreno 已提交
734
		} else {
J
Johannes Rieken 已提交
735
			this.class = `${BuiltinStatusLabelAction.Class} user`;
J
Joao Moreno 已提交
736 737 738 739 740 741 742
		}
	}

	run(): TPromise<any> {
		return TPromise.as(null);
	}
}