extensionsActions.ts 137.1 KB
Newer Older
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.
 *--------------------------------------------------------------------------------------------*/

6
import 'vs/css!./media/extensionActions';
7 8
import { localize } from 'vs/nls';
import { IAction, Action } from 'vs/base/common/actions';
9
import { Delayer } from 'vs/base/common/async';
10
import * as DOM from 'vs/base/browser/dom';
11
import { Event } from 'vs/base/common/event';
12
import * as json from 'vs/base/common/json';
13
import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
14
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
M
Matt Bierner 已提交
15
import { dispose, Disposable } from 'vs/base/common/lifecycle';
16
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG } from 'vs/workbench/contrib/extensions/common/extensions';
17
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
18
import { ExtensionsLabel, IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
S
Sandeep Somavarapu 已提交
19
import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation, IExtensionsConfigContent, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
20
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
21
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
22
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
B
Benjamin Pasero 已提交
23
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
B
Benjamin Pasero 已提交
24
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
25
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
B
Benjamin Pasero 已提交
26
import { IFileService, IFileContent } from 'vs/platform/files/common/files';
S
Sandeep Somavarapu 已提交
27
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
J
Joao Moreno 已提交
28
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
29
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
30
import { URI } from 'vs/base/common/uri';
S
Sandeep Somavarapu 已提交
31
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
S
Sandeep Somavarapu 已提交
32
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
33 34 35
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, registerColor, foreground } from 'vs/platform/theme/common/colorRegistry';
import { Color } from 'vs/base/common/color';
36 37 38
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { ITextEditorSelection } from 'vs/platform/editor/common/editor';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
39
import { PagedModel } from 'vs/base/common/paging';
S
Sandeep Somavarapu 已提交
40 41 42
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
I
isidor 已提交
43
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
J
Joao Moreno 已提交
44 45 46 47
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
48
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
49
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
50
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
51
import { IQuickPickItem, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
52
import { CancellationToken } from 'vs/base/common/cancellation';
53
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
54
import { alert } from 'vs/base/browser/ui/aria/aria';
M
Matt Bierner 已提交
55
import { coalesce } from 'vs/base/common/arrays';
56
import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
57
import { ILabelService } from 'vs/platform/label/common/label';
A
Alex Dima 已提交
58
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
P
Peng Lyu 已提交
59
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
60
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
A
Alex Dima 已提交
61
import { IProductService } from 'vs/platform/product/common/product';
62
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
63
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
64
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
J
Joao Moreno 已提交
65

S
Sandeep Somavarapu 已提交
66
export function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
S
Sandeep Somavarapu 已提交
67 68 69 70 71
	return {
		identifier: new ExtensionIdentifier(local.identifier.id),
		isBuiltin: local.type === ExtensionType.System,
		isUnderDevelopment: false,
		extensionLocation: local.location,
S
Sandeep Somavarapu 已提交
72 73
		...local.manifest,
		uuid: local.identifier.uuid
S
Sandeep Somavarapu 已提交
74 75 76
	};
}

S
Sandeep Somavarapu 已提交
77 78
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error,
	instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => {
79
	if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.extensionsGallery) {
S
Sandeep Somavarapu 已提交
80 81
		return Promise.reject(error);
	} else {
82
		const downloadUrl = `${productService.extensionsGallery.serviceUrl}/publishers/${extension.publisher}/vsextensions/${extension.name}/${extension.version}/vspackage`;
S
Sandeep Somavarapu 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
		notificationService.prompt(Severity.Error, message, [{
			label: localize('download', "Download Manually"),
			run: () => openerService.open(URI.parse(downloadUrl)).then(() => {
				notificationService.prompt(
					Severity.Info,
					localize('install vsix', 'Once downloaded, please manually install the downloaded VSIX of \'{0}\'.', extension.identifier.id),
					[{
						label: InstallVSIXAction.LABEL,
						run: () => {
							const action = instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL);
							action.run();
							action.dispose();
						}
					}]
				);
			})
		}]);
		return Promise.resolve();
	}
102
};
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
function getRelativeDateLabel(date: Date): string {
	const delta = new Date().getTime() - date.getTime();

	const year = 365 * 24 * 60 * 60 * 1000;
	if (delta > year) {
		const noOfYears = Math.floor(delta / year);
		return noOfYears > 1 ? localize('noOfYearsAgo', "{0} years ago", noOfYears) : localize('one year ago', "1 year ago");
	}

	const month = 30 * 24 * 60 * 60 * 1000;
	if (delta > month) {
		const noOfMonths = Math.floor(delta / month);
		return noOfMonths > 1 ? localize('noOfMonthsAgo', "{0} months ago", noOfMonths) : localize('one month ago', "1 month ago");
	}

	const day = 24 * 60 * 60 * 1000;
	if (delta > day) {
		const noOfDays = Math.floor(delta / day);
		return noOfDays > 1 ? localize('noOfDaysAgo', "{0} days ago", noOfDays) : localize('one day ago', "1 day ago");
	}

	const hour = 60 * 60 * 1000;
	if (delta > hour) {
		const noOfHours = Math.floor(delta / day);
		return noOfHours > 1 ? localize('noOfHoursAgo', "{0} hours ago", noOfHours) : localize('one hour ago', "1 hour ago");
	}

	if (delta > 0) {
		return localize('just now', "Just now");
	}

	return '';
}

S
Sandeep Somavarapu 已提交
138 139 140 141 142
export abstract class ExtensionAction extends Action implements IExtensionContainer {
	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) { this._extension = extension; this.update(); }
	abstract update(): void;
143
}
144

S
Sandeep Somavarapu 已提交
145
export class InstallAction extends ExtensionAction {
146

147 148 149
	private static INSTALL_LABEL = localize('install', "Install");
	private static INSTALLING_LABEL = localize('installing', "Installing");

150 151
	private static readonly Class = 'extension-action prominent install';
	private static readonly InstallingClass = 'extension-action install installing';
152

153 154 155 156 157 158 159

	private _manifest: IExtensionManifest | null;
	set manifest(manifest: IExtensionManifest) {
		this._manifest = manifest;
		this.updateLabel();
	}

160
	constructor(
161 162 163
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@INotificationService private readonly notificationService: INotificationService,
S
Sandeep Somavarapu 已提交
164 165
		@IOpenerService private readonly openerService: IOpenerService,
		@IExtensionService private readonly runtimeExtensionService: IExtensionService,
166 167
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
A
Alex Dima 已提交
168
		@IProductService private readonly productService: IProductService,
169 170
		@ILabelService private readonly labelService: ILabelService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
171
	) {
172
		super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
173
		this.update();
M
Matt Bierner 已提交
174
		this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
175 176
	}

S
Sandeep Somavarapu 已提交
177
	update(): void {
S
Sandeep Somavarapu 已提交
178
		this.enabled = false;
S
Sandeep Somavarapu 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192
		this.class = InstallAction.Class;
		this.label = InstallAction.INSTALL_LABEL;
		if (this.extension && this.extension.type === ExtensionType.User) {
			if (this.extension.state === ExtensionState.Uninstalled && this.extensionsWorkbenchService.canInstall(this.extension)) {
				this.enabled = true;
				this.updateLabel();
				return;
			}
			if (this.extension.state === ExtensionState.Installing) {
				this.enabled = false;
				this.updateLabel();
				this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
				return;
			}
193
		}
194
	}
195

196
	private updateLabel(): void {
197
		if (this.extension.state === ExtensionState.Installing) {
198 199
			this.label = InstallAction.INSTALLING_LABEL;
			this.tooltip = InstallAction.INSTALLING_LABEL;
200
		} else {
201
			if (this._manifest && this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
A
Alex Dima 已提交
202
				if (isUIExtension(this._manifest, this.productService, this.configurationService)) {
S
Sandeep Somavarapu 已提交
203 204
					this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
					this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
205
				} else {
206
					const host = this.extensionManagementServerService.remoteExtensionManagementServer.label;
S
Sandeep Somavarapu 已提交
207 208
					this.label = `${InstallAction.INSTALL_LABEL} on ${host}`;
					this.tooltip = `${InstallAction.INSTALL_LABEL} on ${host}`;
209 210 211 212 213
				}
			} else {
				this.label = InstallAction.INSTALL_LABEL;
				this.tooltip = InstallAction.INSTALL_LABEL;
			}
214 215 216
		}
	}

S
Sandeep Somavarapu 已提交
217
	async run(): Promise<any> {
218
		this.extensionsWorkbenchService.open(this.extension);
J
Joao Moreno 已提交
219

220 221
		alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));

S
Sandeep Somavarapu 已提交
222 223
		const extension = await this.install(this.extension);

224 225
		alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName));

226
		if (extension && extension.local) {
S
Sandeep Somavarapu 已提交
227 228
			const runningExtension = await this.getRunningExtension(extension.local);
			if (runningExtension) {
229 230 231 232
				const colorThemes = await this.workbenchThemeService.getColorThemes();
				const fileIconThemes = await this.workbenchThemeService.getFileIconThemes();
				if (SetColorThemeAction.getColorThemes(colorThemes, this.extension).length) {
					const action = this.instantiationService.createInstance(SetColorThemeAction, colorThemes);
S
Sandeep Somavarapu 已提交
233
					action.extension = extension;
S
Sandeep Somavarapu 已提交
234
					return action.run({ showCurrentTheme: true, ignoreFocusLost: true });
S
Sandeep Somavarapu 已提交
235
				}
236 237
				if (SetFileIconThemeAction.getFileIconThemes(fileIconThemes, this.extension).length) {
					const action = this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes);
S
Sandeep Somavarapu 已提交
238
					action.extension = extension;
S
Sandeep Somavarapu 已提交
239
					return action.run({ showCurrentTheme: true, ignoreFocusLost: true });
S
Sandeep Somavarapu 已提交
240 241
				}
			}
S
Sandeep Somavarapu 已提交
242 243
		}

J
Joao Moreno 已提交
244 245
	}

246
	private install(extension: IExtension): Promise<IExtension | void> {
S
Sandeep Somavarapu 已提交
247 248 249 250 251 252 253 254
		return this.extensionsWorkbenchService.install(extension)
			.then(null, err => {
				if (!extension.gallery) {
					return this.notificationService.error(err);
				}

				console.error(err);

255
				return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
S
Sandeep Somavarapu 已提交
256 257
			});
	}
J
Joao Moreno 已提交
258

S
Sandeep Somavarapu 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	private async getRunningExtension(extension: ILocalExtension): Promise<IExtensionDescription | null> {
		const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id);
		if (runningExtension) {
			return runningExtension;
		}
		if (this.runtimeExtensionService.canAddExtension(toExtensionDescription(extension))) {
			return new Promise<IExtensionDescription | null>((c, e) => {
				const disposable = this.runtimeExtensionService.onDidChangeExtensions(async () => {
					const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id);
					if (runningExtension) {
						disposable.dispose();
						c(runningExtension);
					}
				});
			});
		}
		return null;
276 277 278
	}
}

S
Sandeep Somavarapu 已提交
279
export abstract class InstallInOtherServerAction extends ExtensionAction {
280

S
Sandeep Somavarapu 已提交
281 282
	protected static INSTALL_LABEL = localize('install', "Install");
	protected static INSTALLING_LABEL = localize('installing', "Installing");
283

284
	private static readonly Class = 'extension-action prominent install';
285
	private static readonly InstallingClass = 'extension-action install installing';
286

287
	updateWhenCounterExtensionChanges: boolean = true;
288 289

	constructor(
S
Sandeep Somavarapu 已提交
290 291
		id: string,
		private readonly server: IExtensionManagementServer | null,
292 293
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
	) {
S
Sandeep Somavarapu 已提交
294
		super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false);
295 296 297
		this.update();
	}

298
	update(): void {
299
		this.enabled = false;
S
Sandeep Somavarapu 已提交
300 301 302
		this.class = InstallInOtherServerAction.Class;

		if (
303
			this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed && this.extension.type === ExtensionType.User
S
Sandeep Somavarapu 已提交
304 305
			// disabled by extension kind or it is a language pack extension
			&& (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest))
306
		) {
S
Sandeep Somavarapu 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319
			const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)[0];
			if (extensionInOtherServer) {
				// Getting installed in other server
				if (extensionInOtherServer.state === ExtensionState.Installing && !extensionInOtherServer.local) {
					this.enabled = true;
					this.label = InstallInOtherServerAction.INSTALLING_LABEL;
					this.class = InstallInOtherServerAction.InstallingClass;
				}
			} else {
				// Not installed in other server
				this.enabled = true;
				this.label = this.getInstallLabel();
			}
320 321 322
		}
	}

323
	async run(): Promise<void> {
S
Sandeep Somavarapu 已提交
324
		if (this.server) {
325 326
			this.extensionsWorkbenchService.open(this.extension);
			alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
S
Sandeep Somavarapu 已提交
327 328 329 330 331
			if (this.extension.gallery) {
				await this.server.extensionManagementService.installFromGallery(this.extension.gallery);
			} else {
				const vsix = await this.extension.server!.extensionManagementService.zip(this.extension.local!);
				await this.server.extensionManagementService.install(vsix);
332 333 334
			}
		}
	}
S
Sandeep Somavarapu 已提交
335 336

	protected abstract getInstallLabel(): string;
337 338
}

S
Sandeep Somavarapu 已提交
339
export class RemoteInstallAction extends InstallInOtherServerAction {
340

S
Sandeep Somavarapu 已提交
341 342
	constructor(
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
343
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
S
Sandeep Somavarapu 已提交
344 345 346
	) {
		super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, extensionsWorkbenchService);
	}
347

S
Sandeep Somavarapu 已提交
348
	protected getInstallLabel(): string {
349
		return this.extensionManagementServerService.remoteExtensionManagementServer ? localize('Install on Server', "Install in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label) : InstallInOtherServerAction.INSTALL_LABEL;
S
Sandeep Somavarapu 已提交
350 351
	}

S
Sandeep Somavarapu 已提交
352
}
353

S
Sandeep Somavarapu 已提交
354
export class LocalInstallAction extends InstallInOtherServerAction {
355 356

	constructor(
S
Sandeep Somavarapu 已提交
357 358
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
359
	) {
S
Sandeep Somavarapu 已提交
360
		super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, extensionsWorkbenchService);
361 362
	}

S
Sandeep Somavarapu 已提交
363 364
	protected getInstallLabel(): string {
		return localize('install locally', "Install Locally");
365 366 367 368
	}

}

S
Sandeep Somavarapu 已提交
369
export class UninstallAction extends ExtensionAction {
370

371 372
	private static readonly UninstallLabel = localize('uninstallAction', "Uninstall");
	private static readonly UninstallingLabel = localize('Uninstalling', "Uninstalling");
373

S
Sandeep Somavarapu 已提交
374 375 376
	private static readonly UninstallClass = 'extension-action uninstall';
	private static readonly UnInstallingClass = 'extension-action uninstall uninstalling';

377
	constructor(
S
Sandeep Somavarapu 已提交
378
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
379
	) {
S
Sandeep Somavarapu 已提交
380
		super('extensions.uninstall', UninstallAction.UninstallLabel, UninstallAction.UninstallClass, false);
381 382 383
		this.update();
	}

S
Sandeep Somavarapu 已提交
384
	update(): void {
385 386 387 388 389 390 391 392 393
		if (!this.extension) {
			this.enabled = false;
			return;
		}

		const state = this.extension.state;

		if (state === ExtensionState.Uninstalling) {
			this.label = UninstallAction.UninstallingLabel;
S
Sandeep Somavarapu 已提交
394
			this.class = UninstallAction.UnInstallingClass;
395 396 397 398 399
			this.enabled = false;
			return;
		}

		this.label = UninstallAction.UninstallLabel;
S
Sandeep Somavarapu 已提交
400
		this.class = UninstallAction.UninstallClass;
S
Sandeep Somavarapu 已提交
401
		this.tooltip = UninstallAction.UninstallLabel;
402

S
Sandeep Somavarapu 已提交
403 404 405 406 407
		if (state !== ExtensionState.Installed) {
			this.enabled = false;
			return;
		}

S
cleanup  
Sandeep Somavarapu 已提交
408
		if (this.extension.type !== ExtensionType.User) {
409 410 411 412 413 414 415
			this.enabled = false;
			return;
		}

		this.enabled = true;
	}

S
Sandeep Somavarapu 已提交
416
	run(): Promise<any> {
417 418 419 420 421
		alert(localize('uninstallExtensionStart', "Uninstalling extension {0} started.", this.extension.displayName));

		return this.extensionsWorkbenchService.uninstall(this.extension).then(() => {
			alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension.displayName));
		});
422 423 424
	}
}

S
Sandeep Somavarapu 已提交
425
export class CombinedInstallAction extends ExtensionAction {
426

427
	private static readonly NoExtensionClass = 'extension-action prominent install no-extension';
428 429
	private installAction: InstallAction;
	private uninstallAction: UninstallAction;
430 431

	constructor(
432
		@IInstantiationService instantiationService: IInstantiationService
433 434 435
	) {
		super('extensions.combinedInstall', '', '', false);

M
Matt Bierner 已提交
436 437
		this.installAction = this._register(instantiationService.createInstance(InstallAction));
		this.uninstallAction = this._register(instantiationService.createInstance(UninstallAction));
438 439 440 441

		this.update();
	}

442 443
	set manifest(manifiest: IExtensionManifest) { this.installAction.manifest = manifiest; this.update(); }

S
Sandeep Somavarapu 已提交
444 445 446 447 448 449
	update(): void {
		this.installAction.extension = this.extension;
		this.uninstallAction.extension = this.extension;
		this.installAction.update();
		this.uninstallAction.update();

450
		if (!this.extension || this.extension.type === ExtensionType.System) {
451 452
			this.enabled = false;
			this.class = CombinedInstallAction.NoExtensionClass;
S
Sandeep Somavarapu 已提交
453 454
		} else if (this.extension.state === ExtensionState.Installing) {
			this.enabled = false;
455 456
			this.label = this.installAction.label;
			this.class = this.installAction.class;
S
Sandeep Somavarapu 已提交
457
			this.tooltip = this.installAction.tooltip;
S
Sandeep Somavarapu 已提交
458 459
		} else if (this.extension.state === ExtensionState.Uninstalling) {
			this.enabled = false;
460 461
			this.label = this.uninstallAction.label;
			this.class = this.uninstallAction.class;
S
Sandeep Somavarapu 已提交
462
			this.tooltip = this.uninstallAction.tooltip;
S
Sandeep Somavarapu 已提交
463 464
		} else if (this.installAction.enabled) {
			this.enabled = true;
465 466
			this.label = this.installAction.label;
			this.class = this.installAction.class;
S
Sandeep Somavarapu 已提交
467
			this.tooltip = this.installAction.tooltip;
S
Sandeep Somavarapu 已提交
468 469
		} else if (this.uninstallAction.enabled) {
			this.enabled = true;
470 471
			this.label = this.uninstallAction.label;
			this.class = this.uninstallAction.class;
S
Sandeep Somavarapu 已提交
472
			this.tooltip = this.uninstallAction.tooltip;
473 474 475 476
		} else {
			this.enabled = false;
			this.label = this.installAction.label;
			this.class = this.installAction.class;
S
Sandeep Somavarapu 已提交
477
			this.tooltip = this.installAction.tooltip;
478 479 480
		}
	}

S
Sandeep Somavarapu 已提交
481
	run(): Promise<any> {
482 483 484 485 486 487
		if (this.installAction.enabled) {
			return this.installAction.run();
		} else if (this.uninstallAction.enabled) {
			return this.uninstallAction.run();
		}

488
		return Promise.resolve();
489 490 491
	}
}

S
Sandeep Somavarapu 已提交
492
export class UpdateAction extends ExtensionAction {
493

494 495
	private static readonly EnabledClass = 'extension-action prominent update';
	private static readonly DisabledClass = `${UpdateAction.EnabledClass} disabled`;
496 497

	constructor(
498 499 500
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@INotificationService private readonly notificationService: INotificationService,
501 502
		@IOpenerService private readonly openerService: IOpenerService,
		@IProductService private readonly productService: IProductService
503
	) {
504
		super(`extensions.update`, '', UpdateAction.DisabledClass, false);
505 506 507
		this.update();
	}

S
Sandeep Somavarapu 已提交
508
	update(): void {
509 510 511
		if (!this.extension) {
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
512
			this.label = this.getUpdateLabel();
513 514 515
			return;
		}

516
		if (this.extension.type !== ExtensionType.User) {
517 518
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
519
			this.label = this.getUpdateLabel();
520 521 522 523 524 525 526 527
			return;
		}

		const canInstall = this.extensionsWorkbenchService.canInstall(this.extension);
		const isInstalled = this.extension.state === ExtensionState.Installed;

		this.enabled = canInstall && isInstalled && this.extension.outdated;
		this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass;
528
		this.label = this.extension.outdated ? this.getUpdateLabel(this.extension.latestVersion) : this.getUpdateLabel();
529 530
	}

S
Sandeep Somavarapu 已提交
531
	run(): Promise<any> {
532
		alert(localize('updateExtensionStart', "Updating extension {0} to version {1} started.", this.extension.displayName, this.extension.latestVersion));
J
Joao Moreno 已提交
533 534 535
		return this.install(this.extension);
	}

S
Sandeep Somavarapu 已提交
536
	private install(extension: IExtension): Promise<void> {
537 538 539
		return this.extensionsWorkbenchService.install(extension).then(() => {
			alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", this.extension.displayName, this.extension.latestVersion));
		}, err => {
540
			if (!extension.gallery) {
J
Joao Moreno 已提交
541 542 543 544
				return this.notificationService.error(err);
			}

			console.error(err);
545

546
			return promptDownloadManually(extension.gallery, localize('failedToUpdate', "Failed to update \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
J
Joao Moreno 已提交
547
		});
548 549
	}

550
	private getUpdateLabel(version?: string): string {
551
		return version ? localize('updateTo', "Update to {0}", version) : localize('updateAction', "Update");
552
	}
553 554
}

555
interface IExtensionActionViewItemOptions extends IActionViewItemOptions {
556 557 558
	tabOnlyOnFocus?: boolean;
}

559
export class ExtensionActionViewItem extends ActionViewItem {
560

561
	protected options: IExtensionActionViewItemOptions;
562

563
	constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) {
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
		super(context, action, options);
	}

	updateEnabled(): void {
		super.updateEnabled();

		if (this.options.tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) {
			DOM.removeTabIndexAndUpdateFocus(this.label);
		}
	}

	private _hasFocus: boolean;
	setFocus(value: boolean): void {
		if (!this.options.tabOnlyOnFocus || this._hasFocus === value) {
			return;
		}
		this._hasFocus = value;
		if (this.getAction().enabled) {
			if (this._hasFocus) {
				this.label.tabIndex = 0;
			} else {
				DOM.removeTabIndexAndUpdateFocus(this.label);
			}
		}
	}
}

S
Sandeep Somavarapu 已提交
591
export abstract class ExtensionDropDownAction extends ExtensionAction {
S
Explore  
Sandeep Somavarapu 已提交
592 593 594 595 596 597 598

	constructor(
		id: string,
		label: string,
		cssClass: string,
		enabled: boolean,
		private readonly tabOnlyOnFocus: boolean,
S
Sandeep Somavarapu 已提交
599
		@IInstantiationService protected instantiationService: IInstantiationService
S
Explore  
Sandeep Somavarapu 已提交
600 601 602 603
	) {
		super(id, label, cssClass, enabled);
	}

604 605 606 607
	private _actionViewItem: DropDownMenuActionViewItem;
	createActionViewItem(): DropDownMenuActionViewItem {
		this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus);
		return this._actionViewItem;
S
Explore  
Sandeep Somavarapu 已提交
608 609
	}

J
Johannes Rieken 已提交
610
	public run({ actionGroups, disposeActionsOnHide }: { actionGroups: IAction[][], disposeActionsOnHide: boolean }): Promise<any> {
611 612
		if (this._actionViewItem) {
			this._actionViewItem.showMenu(actionGroups, disposeActionsOnHide);
S
Explore  
Sandeep Somavarapu 已提交
613
		}
614
		return Promise.resolve();
S
Explore  
Sandeep Somavarapu 已提交
615 616 617
	}
}

618
export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
619

S
Sandeep Somavarapu 已提交
620
	constructor(action: ExtensionDropDownAction,
621
		tabOnlyOnFocus: boolean,
622
		@IContextMenuService private readonly contextMenuService: IContextMenuService
S
Sandeep Somavarapu 已提交
623
	) {
624
		super(null, action, { icon: true, label: true, tabOnlyOnFocus });
625 626
	}

S
Sandeep Somavarapu 已提交
627
	public showMenu(menuActionGroups: IAction[][], disposeActionsOnHide: boolean): void {
628 629 630 631 632 633 634 635 636 637 638
		if (this.element) {
			const actions = this.getActions(menuActionGroups);
			let elementPosition = DOM.getDomNodePagePosition(this.element);
			const anchor = { x: elementPosition.left, y: elementPosition.top + elementPosition.height + 10 };
			this.contextMenuService.showContextMenu({
				getAnchor: () => anchor,
				getActions: () => actions,
				actionRunner: this.actionRunner,
				onHide: () => { if (disposeActionsOnHide) { dispose(actions); } }
			});
		}
639 640
	}

S
Sandeep Somavarapu 已提交
641
	private getActions(menuActionGroups: IAction[][]): IAction[] {
B
Benjamin Pasero 已提交
642
		let actions: IAction[] = [];
S
Sandeep Somavarapu 已提交
643
		for (const menuActions of menuActionGroups) {
S
Sandeep Somavarapu 已提交
644
			actions = [...actions, ...menuActions, new Separator()];
645 646 647 648 649
		}
		return actions.length ? actions.slice(0, actions.length - 1) : actions;
	}
}

S
Sandeep Somavarapu 已提交
650
export class ManageExtensionAction extends ExtensionDropDownAction {
651

652
	static readonly ID = 'extensions.manage';
653 654
	private static readonly Class = 'extension-action manage';
	private static readonly HideManageExtensionClass = `${ManageExtensionAction.Class} hide`;
655 656

	constructor(
S
Sandeep Somavarapu 已提交
657
		@IInstantiationService instantiationService: IInstantiationService,
658 659
		@IExtensionService private readonly extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
660
	) {
S
Sandeep Somavarapu 已提交
661 662

		super(ManageExtensionAction.ID, '', '', true, true, instantiationService);
663

S
Sandeep Somavarapu 已提交
664
		this.tooltip = localize('manage', "Manage");
665 666 667 668

		this.update();
	}

669
	getActionGroups(runningExtensions: IExtensionDescription[], colorThemes: IColorTheme[], fileIconThemes: IFileIconTheme[]): IAction[][] {
S
Sandeep Somavarapu 已提交
670
		const groups: ExtensionAction[][] = [];
671 672 673 674 675 676 677 678 679 680 681 682 683 684
		if (this.extension) {
			const extensionColorThemes = SetColorThemeAction.getColorThemes(colorThemes, this.extension);
			const extensionFileIconThemes = SetFileIconThemeAction.getFileIconThemes(fileIconThemes, this.extension);
			if (extensionColorThemes.length || extensionFileIconThemes.length) {
				const themesGroup: ExtensionAction[] = [];
				if (extensionColorThemes.length) {
					themesGroup.push(this.instantiationService.createInstance(SetColorThemeAction, colorThemes));
				}
				if (extensionFileIconThemes.length) {
					themesGroup.push(this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes));
				}
				groups.push(themesGroup);
			}
		}
S
Sandeep Somavarapu 已提交
685
		groups.push([
S
Sandeep Somavarapu 已提交
686
			this.instantiationService.createInstance(EnableGloballyAction),
687
			this.instantiationService.createInstance(EnableForWorkspaceAction)
S
Sandeep Somavarapu 已提交
688 689
		]);
		groups.push([
S
Sandeep Somavarapu 已提交
690 691
			this.instantiationService.createInstance(DisableGloballyAction, runningExtensions),
			this.instantiationService.createInstance(DisableForWorkspaceAction, runningExtensions)
S
Sandeep Somavarapu 已提交
692
		]);
S
Sandeep Somavarapu 已提交
693 694
		groups.push([this.instantiationService.createInstance(UninstallAction)]);
		groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]);
P
Peng Lyu 已提交
695 696 697 698 699 700 701

		const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction)];
		if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) {
			extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction));
		}

		groups.push(extensionActions);
S
Sandeep Somavarapu 已提交
702 703

		groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension));
S
Sandeep Somavarapu 已提交
704 705 706 707

		return groups;
	}

708 709 710 711 712
	async run(): Promise<any> {
		const runtimeExtensions = await this.extensionService.getExtensions();
		const colorThemes = await this.workbenchThemeService.getColorThemes();
		const fileIconThemes = await this.workbenchThemeService.getFileIconThemes();
		return super.run({ actionGroups: this.getActionGroups(runtimeExtensions, colorThemes, fileIconThemes), disposeActionsOnHide: true });
S
Sandeep Somavarapu 已提交
713 714
	}

S
Sandeep Somavarapu 已提交
715
	update(): void {
S
Sandeep Somavarapu 已提交
716
		this.class = ManageExtensionAction.HideManageExtensionClass;
717
		this.enabled = false;
S
Sandeep Somavarapu 已提交
718
		if (this.extension) {
719 720
			const state = this.extension.state;
			this.enabled = state === ExtensionState.Installed;
S
Sandeep Somavarapu 已提交
721
			this.class = this.enabled || state === ExtensionState.Uninstalling ? ManageExtensionAction.Class : ManageExtensionAction.HideManageExtensionClass;
722 723 724 725 726
			this.tooltip = state === ExtensionState.Uninstalling ? localize('ManageExtensionAction.uninstallingTooltip', "Uninstalling") : '';
		}
	}
}

S
Sandeep Somavarapu 已提交
727
export class InstallAnotherVersionAction extends ExtensionAction {
728

729 730
	static readonly ID = 'workbench.extensions.action.install.anotherVersion';
	static LABEL = localize('install another version', "Install Another Version...");
731

S
Sandeep Somavarapu 已提交
732
	constructor(
733 734 735 736 737
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@INotificationService private readonly notificationService: INotificationService,
738 739
		@IOpenerService private readonly openerService: IOpenerService,
		@IProductService private readonly productService: IProductService
740 741
	) {
		super(InstallAnotherVersionAction.ID, InstallAnotherVersionAction.LABEL);
S
Sandeep Somavarapu 已提交
742 743 744 745
		this.update();
	}

	update(): void {
S
Sandeep Somavarapu 已提交
746
		this.enabled = this.extension && !!this.extension.gallery;
747 748
	}

J
Johannes Rieken 已提交
749
	run(): Promise<any> {
750 751 752
		if (!this.enabled) {
			return Promise.resolve();
		}
S
Sandeep Somavarapu 已提交
753
		return this.quickInputService.pick(this.getVersionEntries(), { placeHolder: localize('selectVersion', "Select Version to Install"), matchOnDetail: true })
754 755
			.then(pick => {
				if (pick) {
S
Sandeep Somavarapu 已提交
756 757 758
					if (this.extension.version === pick.id) {
						return Promise.resolve();
					}
S
Sandeep Somavarapu 已提交
759 760 761
					const promise: Promise<any> = pick.latest ? this.extensionsWorkbenchService.install(this.extension) : this.extensionsWorkbenchService.installVersion(this.extension, pick.id);
					return promise
						.then(null, err => {
762 763 764 765 766
							if (!this.extension.gallery) {
								return this.notificationService.error(err);
							}

							console.error(err);
767

768
							return promptDownloadManually(this.extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", this.extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
769 770 771 772 773
						});
				}
				return null;
			});
	}
S
Sandeep Somavarapu 已提交
774

775 776
	private getVersionEntries(): Promise<(IQuickPickItem & { latest: boolean, id: string })[]> {
		return this.extensionGalleryService.getAllVersions(this.extension.gallery!, true)
777
			.then(allVersions => allVersions.map((v, i) => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === this.extension.version ? ` (${localize('current', "Current")})` : ''}`, latest: i === 0 })));
S
Sandeep Somavarapu 已提交
778
	}
779 780
}

S
Sandeep Somavarapu 已提交
781
export class ExtensionInfoAction extends ExtensionAction {
782

S
Sandeep Somavarapu 已提交
783 784
	static readonly ID = 'extensions.extensionInfo';
	static readonly LABEL = localize('extensionInfoAction', "Copy Extension Information");
785

786 787 788
	constructor(
		@IClipboardService private readonly clipboardService: IClipboardService
	) {
789
		super(ExtensionInfoAction.ID, ExtensionInfoAction.LABEL);
S
Sandeep Somavarapu 已提交
790 791 792 793 794
		this.update();
	}

	update(): void {
		this.enabled = !!this.extension;
795 796 797 798
	}

	run(): Promise<any> {

S
Sandeep Somavarapu 已提交
799 800 801 802 803 804
		const name = localize('extensionInfoName', 'Name: {0}', this.extension.displayName);
		const id = localize('extensionInfoId', 'Id: {0}', this.extension.identifier.id);
		const description = localize('extensionInfoDescription', 'Description: {0}', this.extension.description);
		const verision = localize('extensionInfoVersion', 'Version: {0}', this.extension.version);
		const publisher = localize('extensionInfoPublisher', 'Publisher: {0}', this.extension.publisherDisplayName);
		const link = this.extension.url ? localize('extensionInfoVSMarketplaceLink', 'VS Marketplace Link: {0}', this.extension.url.toString()) : null;
805

S
Sandeep Somavarapu 已提交
806
		const clipboardStr = `${name}\n${id}\n${description}\n${verision}\n${publisher}${link ? '\n' + link : ''}`;
807

808
		return this.clipboardService.writeText(clipboardStr);
809 810 811
	}
}

P
Peng Lyu 已提交
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
export class ExtensionSettingsAction extends ExtensionAction {

	static readonly ID = 'extensions.extensionSettings';
	static readonly LABEL = localize('extensionSettingsAction', "Configure Extension Settings");

	constructor(
		@IPreferencesService private readonly preferencesService: IPreferencesService
	) {
		super(ExtensionSettingsAction.ID, ExtensionSettingsAction.LABEL);
		this.update();
	}

	update(): void {
		this.enabled = !!this.extension;
	}
	run(): Promise<any> {
		this.preferencesService.openSettings(false, `@ext:${this.extension.identifier.id}`);
		return Promise.resolve();
	}
}

S
Sandeep Somavarapu 已提交
833
export class EnableForWorkspaceAction extends ExtensionAction {
834

835
	static readonly ID = 'extensions.enableForWorkspace';
S
Sandeep Somavarapu 已提交
836
	static LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)");
837

S
Sandeep Somavarapu 已提交
838
	constructor(
839 840
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
841
	) {
S
Explore  
Sandeep Somavarapu 已提交
842
		super(EnableForWorkspaceAction.ID, EnableForWorkspaceAction.LABEL);
843 844 845
		this.update();
	}

S
Sandeep Somavarapu 已提交
846
	update(): void {
847
		this.enabled = false;
848 849
		if (this.extension && this.extension.local) {
			this.enabled = this.extension.state === ExtensionState.Installed
850
				&& !this.extensionEnablementService.isEnabled(this.extension.local)
851
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
852 853 854
		}
	}

S
Sandeep Somavarapu 已提交
855
	run(): Promise<any> {
856
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledWorkspace);
857 858 859
	}
}

S
Sandeep Somavarapu 已提交
860
export class EnableGloballyAction extends ExtensionAction {
861

862
	static readonly ID = 'extensions.enableGlobally';
S
Sandeep Somavarapu 已提交
863
	static LABEL = localize('enableGloballyAction', "Enable");
864

S
Sandeep Somavarapu 已提交
865
	constructor(
866
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
867
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
868
	) {
S
Sandeep Somavarapu 已提交
869
		super(EnableGloballyAction.ID, EnableGloballyAction.LABEL);
870 871 872
		this.update();
	}

S
Sandeep Somavarapu 已提交
873
	update(): void {
874
		this.enabled = false;
875
		if (this.extension && this.extension.local) {
876
			this.enabled = this.extension.state === ExtensionState.Installed
877
				&& this.extension.enablementState === EnablementState.DisabledGlobally
878
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
879 880 881
		}
	}

S
Sandeep Somavarapu 已提交
882
	run(): Promise<any> {
883
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledGlobally);
884 885 886
	}
}

S
Sandeep Somavarapu 已提交
887
export class DisableForWorkspaceAction extends ExtensionAction {
888

889
	static readonly ID = 'extensions.disableForWorkspace';
S
Sandeep Somavarapu 已提交
890
	static LABEL = localize('disableForWorkspaceAction', "Disable (Workspace)");
891

S
Sandeep Somavarapu 已提交
892
	constructor(readonly runningExtensions: IExtensionDescription[],
893 894 895
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
896
	) {
S
Sandeep Somavarapu 已提交
897
		super(DisableForWorkspaceAction.ID, DisableForWorkspaceAction.LABEL);
898 899 900
		this.update();
	}

S
Sandeep Somavarapu 已提交
901
	update(): void {
902
		this.enabled = false;
903 904
		if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) {
			this.enabled = this.extension.state === ExtensionState.Installed
905
				&& (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace)
906
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
907 908 909
		}
	}

S
Sandeep Somavarapu 已提交
910
	run(): Promise<any> {
911
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledWorkspace);
912 913 914
	}
}

S
Sandeep Somavarapu 已提交
915
export class DisableGloballyAction extends ExtensionAction {
916

917
	static readonly ID = 'extensions.disableGlobally';
S
Sandeep Somavarapu 已提交
918
	static LABEL = localize('disableGloballyAction', "Disable");
919

S
Sandeep Somavarapu 已提交
920
	constructor(readonly runningExtensions: IExtensionDescription[],
921 922
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
923
	) {
S
Sandeep Somavarapu 已提交
924
		super(DisableGloballyAction.ID, DisableGloballyAction.LABEL);
925 926 927
		this.update();
	}

S
Sandeep Somavarapu 已提交
928
	update(): void {
929
		this.enabled = false;
930 931
		if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))) {
			this.enabled = this.extension.state === ExtensionState.Installed
932
				&& (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace)
933
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
934 935 936
		}
	}

S
Sandeep Somavarapu 已提交
937
	run(): Promise<any> {
938
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledGlobally);
939 940 941
	}
}

S
Sandeep Somavarapu 已提交
942
export abstract class ExtensionEditorDropDownAction extends ExtensionDropDownAction {
943

S
Sandeep Somavarapu 已提交
944 945 946
	private static readonly EnabledClass = 'extension-action extension-editor-dropdown-action';
	private static readonly EnabledDropDownClass = 'extension-action extension-editor-dropdown-action dropdown enable';
	private static readonly DisabledClass = `${ExtensionEditorDropDownAction.EnabledClass} disabled`;
947 948

	constructor(
S
Sandeep Somavarapu 已提交
949 950 951
		id: string, private readonly initialLabel: string,
		readonly actions: ExtensionAction[],
		@IInstantiationService instantiationService: IInstantiationService
952
	) {
S
Sandeep Somavarapu 已提交
953
		super(id, initialLabel, ExtensionEditorDropDownAction.DisabledClass, false, false, instantiationService);
954 955 956
		this.update();
	}

S
Sandeep Somavarapu 已提交
957 958 959
	update(): void {
		this.actions.forEach(a => a.extension = this.extension);
		this.actions.forEach(a => a.update());
S
Sandeep Somavarapu 已提交
960
		const enabledActions = this.actions.filter(a => a.enabled);
961 962 963 964
		this.enabled = enabledActions.length > 0;
		if (this.enabled) {
			if (enabledActions.length === 1) {
				this.label = enabledActions[0].label;
S
Sandeep Somavarapu 已提交
965
				this.class = ExtensionEditorDropDownAction.EnabledClass;
966
			} else {
S
Sandeep Somavarapu 已提交
967
				this.label = this.initialLabel;
S
Sandeep Somavarapu 已提交
968
				this.class = ExtensionEditorDropDownAction.EnabledDropDownClass;
969 970
			}
		} else {
S
Sandeep Somavarapu 已提交
971
			this.class = ExtensionEditorDropDownAction.DisabledClass;
972 973 974
		}
	}

J
Johannes Rieken 已提交
975
	public run(): Promise<any> {
S
Sandeep Somavarapu 已提交
976
		const enabledActions = this.actions.filter(a => a.enabled);
977 978 979
		if (enabledActions.length === 1) {
			enabledActions[0].run();
		} else {
S
Sandeep Somavarapu 已提交
980
			return super.run({ actionGroups: [this.actions], disposeActionsOnHide: false });
981
		}
982
		return Promise.resolve();
983
	}
S
Sandeep Somavarapu 已提交
984
}
985

S
Sandeep Somavarapu 已提交
986 987 988
export class EnableDropDownAction extends ExtensionEditorDropDownAction {

	constructor(
S
Sandeep Somavarapu 已提交
989
		@IInstantiationService instantiationService: IInstantiationService
S
Sandeep Somavarapu 已提交
990
	) {
S
Sandeep Somavarapu 已提交
991 992
		super('extensions.enable', localize('enableAction', "Enable"), [
			instantiationService.createInstance(EnableGloballyAction),
993
			instantiationService.createInstance(EnableForWorkspaceAction)
S
Sandeep Somavarapu 已提交
994
		], instantiationService);
S
Sandeep Somavarapu 已提交
995 996 997 998 999 1000
	}
}

export class DisableDropDownAction extends ExtensionEditorDropDownAction {

	constructor(
S
Sandeep Somavarapu 已提交
1001 1002
		runningExtensions: IExtensionDescription[],
		@IInstantiationService instantiationService: IInstantiationService
S
Sandeep Somavarapu 已提交
1003
	) {
S
Sandeep Somavarapu 已提交
1004 1005 1006 1007
		super('extensions.disable', localize('disableAction', "Disable"), [
			instantiationService.createInstance(DisableGloballyAction, runningExtensions),
			instantiationService.createInstance(DisableForWorkspaceAction, runningExtensions)
		], instantiationService);
1008 1009 1010
	}
}

J
Joao Moreno 已提交
1011 1012
export class CheckForUpdatesAction extends Action {

1013
	static readonly ID = 'workbench.extensions.action.checkForUpdates';
1014
	static LABEL = localize('checkForUpdates', "Check for Extension Updates");
J
Joao Moreno 已提交
1015 1016

	constructor(
1017 1018
		id = CheckForUpdatesAction.ID,
		label = CheckForUpdatesAction.LABEL,
1019
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
1020
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
1021 1022
		@IViewletService private readonly viewletService: IViewletService,
		@INotificationService private readonly notificationService: INotificationService
J
Joao Moreno 已提交
1023 1024 1025 1026
	) {
		super(id, label, '', true);
	}

1027
	private checkUpdatesAndNotify(): void {
1028 1029
		const outdated = this.extensionsWorkbenchService.outdated;
		if (!outdated.length) {
R
Rob Lourens 已提交
1030
			this.notificationService.info(localize('noUpdatesAvailable', "All extensions are up to date."));
1031 1032
			return;
		}
1033

1034
		let msgAvailableExtensions = outdated.length === 1 ? localize('singleUpdateAvailable', "An extension update is available.") : localize('updatesAvailable', "{0} extension updates are available.", outdated.length);
1035

1036
		const disabledExtensionsCount = outdated.filter(ext => ext.local && !this.extensionEnablementService.isEnabled(ext.local)).length;
1037 1038 1039 1040 1041 1042 1043 1044 1045
		if (disabledExtensionsCount) {
			if (outdated.length === 1) {
				msgAvailableExtensions = localize('singleDisabledUpdateAvailable', "An update to an extension which is disabled is available.");
			} else if (disabledExtensionsCount === 1) {
				msgAvailableExtensions = localize('updatesAvailableOneDisabled', "{0} extension updates are available. One of them is for a disabled extension.", outdated.length);
			} else if (disabledExtensionsCount === outdated.length) {
				msgAvailableExtensions = localize('updatesAvailableAllDisabled', "{0} extension updates are available. All of them are for disabled extensions.", outdated.length);
			} else {
				msgAvailableExtensions = localize('updatesAvailableIncludingDisabled', "{0} extension updates are available. {1} of them are for disabled extensions.", outdated.length, disabledExtensionsCount);
1046
			}
1047 1048 1049 1050 1051 1052 1053
		}

		this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => viewlet.search(''));

		this.notificationService.info(msgAvailableExtensions);
1054 1055
	}

S
Sandeep Somavarapu 已提交
1056
	run(): Promise<any> {
1057
		return this.extensionsWorkbenchService.checkForUpdates().then(() => this.checkUpdatesAndNotify());
J
Joao Moreno 已提交
1058 1059 1060
	}
}

S
Sandeep Somavarapu 已提交
1061 1062 1063 1064 1065 1066
export class ToggleAutoUpdateAction extends Action {

	constructor(
		id: string,
		label: string,
		private autoUpdateValue: boolean,
1067
		@IConfigurationService private readonly configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1068 1069 1070
	) {
		super(id, label, '', true);
		this.updateEnablement();
1071
		configurationService.onDidChangeConfiguration(() => this.updateEnablement());
S
Sandeep Somavarapu 已提交
1072 1073 1074
	}

	private updateEnablement(): void {
1075
		this.enabled = this.configurationService.getValue(AutoUpdateConfigurationKey) !== this.autoUpdateValue;
S
Sandeep Somavarapu 已提交
1076 1077
	}

S
Sandeep Somavarapu 已提交
1078
	run(): Promise<any> {
1079
		return this.configurationService.updateValue(AutoUpdateConfigurationKey, this.autoUpdateValue);
S
Sandeep Somavarapu 已提交
1080 1081 1082 1083 1084
	}
}

export class EnableAutoUpdateAction extends ToggleAutoUpdateAction {

1085
	static readonly ID = 'workbench.extensions.action.enableAutoUpdate';
S
Sandeep Somavarapu 已提交
1086 1087 1088 1089 1090
	static LABEL = localize('enableAutoUpdate', "Enable Auto Updating Extensions");

	constructor(
		id = EnableAutoUpdateAction.ID,
		label = EnableAutoUpdateAction.LABEL,
1091
		@IConfigurationService configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1092
	) {
1093
		super(id, label, true, configurationService);
S
Sandeep Somavarapu 已提交
1094 1095 1096 1097 1098
	}
}

export class DisableAutoUpdateAction extends ToggleAutoUpdateAction {

1099
	static readonly ID = 'workbench.extensions.action.disableAutoUpdate';
S
Sandeep Somavarapu 已提交
1100 1101 1102 1103 1104
	static LABEL = localize('disableAutoUpdate', "Disable Auto Updating Extensions");

	constructor(
		id = EnableAutoUpdateAction.ID,
		label = EnableAutoUpdateAction.LABEL,
1105
		@IConfigurationService configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1106
	) {
1107
		super(id, label, false, configurationService);
S
Sandeep Somavarapu 已提交
1108 1109 1110
	}
}

1111 1112
export class UpdateAllAction extends Action {

1113
	static readonly ID = 'workbench.extensions.action.updateAllExtensions';
1114 1115 1116 1117 1118
	static LABEL = localize('updateAll', "Update All Extensions");

	constructor(
		id = UpdateAllAction.ID,
		label = UpdateAllAction.LABEL,
1119 1120 1121
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@INotificationService private readonly notificationService: INotificationService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
1122 1123
		@IOpenerService private readonly openerService: IOpenerService,
		@IProductService private readonly productService: IProductService
1124 1125 1126
	) {
		super(id, label, '', false);

M
Matt Bierner 已提交
1127
		this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
1128 1129 1130 1131
		this.update();
	}

	private update(): void {
1132
		this.enabled = this.extensionsWorkbenchService.outdated.length > 0;
1133 1134
	}

S
Sandeep Somavarapu 已提交
1135
	run(): Promise<any> {
1136
		return Promise.all(this.extensionsWorkbenchService.outdated.map(e => this.install(e)));
J
Joao Moreno 已提交
1137 1138
	}

J
Johannes Rieken 已提交
1139
	private install(extension: IExtension): Promise<any> {
R
Rob Lourens 已提交
1140
		return this.extensionsWorkbenchService.install(extension).then(undefined, err => {
1141
			if (!extension.gallery) {
J
Joao Moreno 已提交
1142 1143 1144 1145
				return this.notificationService.error(err);
			}

			console.error(err);
1146

1147
			return promptDownloadManually(extension.gallery, localize('failedToUpdate', "Failed to update \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
J
Joao Moreno 已提交
1148
		});
1149 1150 1151
	}
}

S
Sandeep Somavarapu 已提交
1152
export class ReloadAction extends ExtensionAction {
1153

1154 1155
	private static readonly EnabledClass = 'extension-action reload';
	private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
1156

1157
	updateWhenCounterExtensionChanges: boolean = true;
1158
	private _runningExtensions: IExtensionDescription[] | null = null;
1159 1160

	constructor(
1161 1162 1163
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IWindowService private readonly windowService: IWindowService,
		@IExtensionService private readonly extensionService: IExtensionService,
1164
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
S
Sandeep Somavarapu 已提交
1165
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
1166 1167
	) {
		super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
M
Matt Bierner 已提交
1168
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
1169
		this.updateRunningExtensions();
1170 1171
	}

1172
	private updateRunningExtensions(): void {
1173
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
1174 1175 1176 1177 1178
	}

	update(): void {
		this.enabled = false;
		this.tooltip = '';
1179
		if (!this.extension || !this._runningExtensions) {
1180 1181 1182 1183 1184 1185
			return;
		}
		const state = this.extension.state;
		if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) {
			return;
		}
1186
		if (this.extension.local && this.extension.local.manifest && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.localizations && this.extension.local.manifest.contributes.localizations.length > 0) {
1187 1188
			return;
		}
1189
		this.computeReloadState();
1190
		this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
1191 1192
	}

1193
	private computeReloadState(): void {
1194 1195 1196
		if (!this._runningExtensions) {
			return;
		}
1197
		const isUninstalled = this.extension.state === ExtensionState.Uninstalled;
S
Sandeep Somavarapu 已提交
1198
		const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0];
S
Sandeep Somavarapu 已提交
1199
		const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
1200

1201
		if (isUninstalled) {
S
Sandeep Somavarapu 已提交
1202
			if (isSameExtensionRunning && !this.extensionService.canRemoveExtension(runningExtension)) {
1203 1204 1205 1206 1207 1208 1209
				this.enabled = true;
				this.label = localize('reloadRequired', "Reload Required");
				this.tooltip = localize('postUninstallTooltip', "Please reload Visual Studio Code to complete the uninstallation of this extension.");
				alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension.displayName));
			}
			return;
		}
1210 1211
		if (this.extension.local) {
			const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
S
Sandeep Somavarapu 已提交
1212 1213

			// Extension is runningÎ
1214
			if (runningExtension) {
1215
				if (isEnabled) {
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
					if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
						if (isSameExtensionRunning) {
							if (this.extension.version !== runningExtension.version) {
								this.enabled = true;
								this.label = localize('reloadRequired', "Reload Required");
								this.tooltip = localize('postUpdateTooltip', "Please reload Visual Studio Code to enable the updated extension.");
							}
						} else {
							this.enabled = true;
							this.label = localize('reloadRequired', "Reload Required");
							this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
						}
1228 1229 1230 1231 1232 1233
					}
				} else {
					if (isSameExtensionRunning) {
						this.enabled = true;
						this.label = localize('reloadRequired', "Reload Required");
						this.tooltip = localize('postDisableTooltip', "Please reload Visual Studio Code to disable this extension.");
S
Sandeep Somavarapu 已提交
1234
					}
1235
				}
1236
				return;
S
Sandeep Somavarapu 已提交
1237 1238 1239 1240
			}

			// Extension is not running
			else {
1241
				if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
1242
					this.enabled = true;
S
Sandeep Somavarapu 已提交
1243
					this.label = localize('reloadRequired', "Reload Required");
1244
					this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
1245
					return;
1246
				}
S
Sandeep Somavarapu 已提交
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

				const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null;
				if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) {
					const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === otherServer)[0];
					// Same extension in other server exists and
					if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) {
						this.enabled = true;
						this.label = localize('reloadRequired', "Reload Required");
						this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
						alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName));
						return;
S
Explore  
Sandeep Somavarapu 已提交
1258
					}
1259
				}
1260 1261 1262 1263
			}
		}
	}

S
Sandeep Somavarapu 已提交
1264 1265
	run(): Promise<any> {
		return Promise.resolve(this.windowService.reloadWindow());
1266 1267 1268
	}
}

S
Sandeep Somavarapu 已提交
1269 1270
export class SetColorThemeAction extends ExtensionAction {

1271
	static getColorThemes(colorThemes: IColorTheme[], extension: IExtension): IColorTheme[] {
1272
		return colorThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id));
1273 1274
	}

S
Sandeep Somavarapu 已提交
1275 1276 1277 1278 1279
	private static readonly EnabledClass = 'extension-action theme';
	private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`;


	constructor(
1280
		private readonly colorThemes: IColorTheme[],
S
Sandeep Somavarapu 已提交
1281 1282 1283 1284 1285 1286
		@IExtensionService extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@IConfigurationService private readonly configurationService: IConfigurationService
	) {
		super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false);
M
Matt Bierner 已提交
1287
		this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this));
S
Sandeep Somavarapu 已提交
1288 1289 1290
		this.update();
	}

1291
	update(): void {
S
Sandeep Somavarapu 已提交
1292 1293 1294 1295
		this.enabled = false;
		if (this.extension) {
			const isInstalled = this.extension.state === ExtensionState.Installed;
			if (isInstalled) {
1296 1297
				const extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension);
				this.enabled = extensionThemes.length > 0;
S
Sandeep Somavarapu 已提交
1298 1299 1300 1301 1302
			}
		}
		this.class = this.enabled ? SetColorThemeAction.EnabledClass : SetColorThemeAction.DisabledClass;
	}

S
Sandeep Somavarapu 已提交
1303
	async run({ showCurrentTheme, ignoreFocusLost }: { showCurrentTheme: boolean, ignoreFocusLost: boolean } = { showCurrentTheme: false, ignoreFocusLost: false }): Promise<any> {
1304
		this.update();
S
Sandeep Somavarapu 已提交
1305 1306 1307
		if (!this.enabled) {
			return;
		}
1308 1309 1310
		let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension);
		const currentTheme = this.colorThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0];
		showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id);
S
Sandeep Somavarapu 已提交
1311
		if (showCurrentTheme) {
1312
			extensionThemes = extensionThemes.filter(t => t.id !== currentTheme.id);
S
Sandeep Somavarapu 已提交
1313 1314 1315 1316
		}

		const delayer = new Delayer<any>(100);
		const picks: (IQuickPickItem | IQuickPickSeparator)[] = [];
1317
		picks.push(...extensionThemes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id })));
S
Sandeep Somavarapu 已提交
1318 1319 1320 1321 1322 1323 1324 1325
		if (showCurrentTheme) {
			picks.push(<IQuickPickSeparator>{ type: 'separator', label: localize('current', "Current") });
			picks.push(<IQuickPickItem>{ label: currentTheme.label, id: currentTheme.id });
		}
		const pickedTheme = await this.quickInputService.pick(
			picks,
			{
				placeHolder: localize('select color theme', "Select Color Theme"),
S
Sandeep Somavarapu 已提交
1326 1327
				onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, undefined)),
				ignoreFocusLost
S
Sandeep Somavarapu 已提交
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
			});
		let confValue = this.configurationService.inspect(COLOR_THEME_SETTING);
		const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
		return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
	}
}

export class SetFileIconThemeAction extends ExtensionAction {

	private static readonly EnabledClass = 'extension-action theme';
	private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`;


1341 1342 1343 1344
	static getFileIconThemes(fileIconThemes: IFileIconTheme[], extension: IExtension): IFileIconTheme[] {
		return fileIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id));
	}

S
Sandeep Somavarapu 已提交
1345
	constructor(
1346
		private readonly fileIconThemes: IFileIconTheme[],
S
Sandeep Somavarapu 已提交
1347 1348 1349 1350 1351 1352
		@IExtensionService extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@IConfigurationService private readonly configurationService: IConfigurationService
	) {
		super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false);
M
Matt Bierner 已提交
1353
		this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this));
S
Sandeep Somavarapu 已提交
1354 1355 1356
		this.update();
	}

1357
	update(): void {
S
Sandeep Somavarapu 已提交
1358 1359 1360 1361
		this.enabled = false;
		if (this.extension) {
			const isInstalled = this.extension.state === ExtensionState.Installed;
			if (isInstalled) {
1362 1363
				const extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension);
				this.enabled = extensionThemes.length > 0;
S
Sandeep Somavarapu 已提交
1364 1365 1366 1367 1368
			}
		}
		this.class = this.enabled ? SetFileIconThemeAction.EnabledClass : SetFileIconThemeAction.DisabledClass;
	}

S
Sandeep Somavarapu 已提交
1369
	async run({ showCurrentTheme, ignoreFocusLost }: { showCurrentTheme: boolean, ignoreFocusLost: boolean } = { showCurrentTheme: false, ignoreFocusLost: false }): Promise<any> {
S
Sandeep Somavarapu 已提交
1370 1371 1372 1373
		await this.update();
		if (!this.enabled) {
			return;
		}
1374 1375 1376
		let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension);
		const currentTheme = this.fileIconThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme();
		showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id);
S
Sandeep Somavarapu 已提交
1377
		if (showCurrentTheme) {
1378
			extensionThemes = extensionThemes.filter(t => t.id !== currentTheme.id);
S
Sandeep Somavarapu 已提交
1379 1380 1381 1382
		}

		const delayer = new Delayer<any>(100);
		const picks: (IQuickPickItem | IQuickPickSeparator)[] = [];
1383
		picks.push(...extensionThemes.map(theme => (<IQuickPickItem>{ label: theme.label, id: theme.id })));
1384
		if (showCurrentTheme && currentTheme.label) {
S
Sandeep Somavarapu 已提交
1385 1386 1387 1388 1389 1390 1391
			picks.push(<IQuickPickSeparator>{ type: 'separator', label: localize('current', "Current") });
			picks.push(<IQuickPickItem>{ label: currentTheme.label, id: currentTheme.id });
		}
		const pickedTheme = await this.quickInputService.pick(
			picks,
			{
				placeHolder: localize('select file icon theme', "Select File Icon Theme"),
S
Sandeep Somavarapu 已提交
1392 1393
				onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setFileIconTheme(item.id, undefined)),
				ignoreFocusLost
S
Sandeep Somavarapu 已提交
1394
			});
1395
		let confValue = this.configurationService.inspect(ICON_THEME_SETTING);
S
Sandeep Somavarapu 已提交
1396 1397 1398 1399 1400
		const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
		return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
	}
}

B
Benjamin Pasero 已提交
1401
export class OpenExtensionsViewletAction extends ShowViewletAction {
1402 1403 1404 1405 1406 1407 1408 1409

	static ID = VIEWLET_ID;
	static LABEL = localize('toggleExtensionsViewlet', "Show Extensions");

	constructor(
		id: string,
		label: string,
		@IViewletService viewletService: IViewletService,
B
Benjamin Pasero 已提交
1410
		@IEditorGroupsService editorGroupService: IEditorGroupsService,
1411
		@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
1412
	) {
1413
		super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService);
1414 1415 1416 1417 1418 1419 1420 1421
	}
}

export class InstallExtensionsAction extends OpenExtensionsViewletAction {
	static ID = 'workbench.extensions.action.installExtensions';
	static LABEL = localize('installExtensions', "Install Extensions");
}

1422 1423
export class ShowEnabledExtensionsAction extends Action {

1424
	static readonly ID = 'workbench.extensions.action.showEnabledExtensions';
1425
	static LABEL = localize('showEnabledExtensions', "Show Enabled Extensions");
1426 1427 1428 1429

	constructor(
		id: string,
		label: string,
1430
		@IViewletService private readonly viewletService: IViewletService
1431
	) {
R
Rob Lourens 已提交
1432
		super(id, label, undefined, true);
1433 1434
	}

J
Johannes Rieken 已提交
1435
	run(): Promise<void> {
1436 1437 1438
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
1439
				viewlet.search('@enabled ');
1440 1441 1442 1443 1444
				viewlet.focus();
			});
	}
}

1445 1446
export class ShowInstalledExtensionsAction extends Action {

1447
	static readonly ID = 'workbench.extensions.action.showInstalledExtensions';
1448 1449 1450 1451 1452
	static LABEL = localize('showInstalledExtensions', "Show Installed Extensions");

	constructor(
		id: string,
		label: string,
1453
		@IViewletService private readonly viewletService: IViewletService
1454
	) {
R
Rob Lourens 已提交
1455
		super(id, label, undefined, true);
1456 1457
	}

J
Johannes Rieken 已提交
1458
	run(): Promise<void> {
1459 1460 1461
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
1462
				viewlet.search('@installed ');
1463 1464 1465 1466 1467 1468 1469
				viewlet.focus();
			});
	}
}

export class ShowDisabledExtensionsAction extends Action {

1470
	static readonly ID = 'workbench.extensions.action.showDisabledExtensions';
1471 1472 1473 1474 1475
	static LABEL = localize('showDisabledExtensions', "Show Disabled Extensions");

	constructor(
		id: string,
		label: string,
1476
		@IViewletService private readonly viewletService: IViewletService
1477 1478 1479 1480
	) {
		super(id, label, 'null', true);
	}

J
Johannes Rieken 已提交
1481
	run(): Promise<void> {
1482 1483 1484 1485 1486 1487 1488 1489 1490
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@disabled ');
				viewlet.focus();
			});
	}
}

S
Sandeep Somavarapu 已提交
1491
export class ClearExtensionsInputAction extends Action {
1492

1493
	static readonly ID = 'workbench.extensions.action.clearExtensionsInput';
1494 1495 1496 1497 1498 1499
	static LABEL = localize('clearExtensionsInput', "Clear Extensions Input");

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
1500
		value: string,
1501
		@IViewletService private readonly viewletService: IViewletService
1502
	) {
S
Sandeep Somavarapu 已提交
1503
		super(id, label, 'clear-extensions', true);
1504
		this.onSearchChange(value);
M
Matt Bierner 已提交
1505
		this._register(onSearchChange(this.onSearchChange, this));
1506 1507 1508 1509 1510 1511
	}

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

J
Johannes Rieken 已提交
1512
	run(): Promise<void> {
S
Sandeep Somavarapu 已提交
1513 1514 1515 1516 1517 1518 1519
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('');
				viewlet.focus();
			});
	}
1520 1521
}

S
Sandeep Somavarapu 已提交
1522 1523 1524 1525 1526 1527 1528 1529
export class ShowBuiltInExtensionsAction extends Action {

	static readonly ID = 'workbench.extensions.action.listBuiltInExtensions';
	static LABEL = localize('showBuiltInExtensions', "Show Built-in Extensions");

	constructor(
		id: string,
		label: string,
1530
		@IViewletService private readonly viewletService: IViewletService
S
Sandeep Somavarapu 已提交
1531
	) {
R
Rob Lourens 已提交
1532
		super(id, label, undefined, true);
S
Sandeep Somavarapu 已提交
1533 1534
	}

J
Johannes Rieken 已提交
1535
	run(): Promise<void> {
S
Sandeep Somavarapu 已提交
1536 1537 1538 1539 1540 1541 1542 1543 1544
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@builtin ');
				viewlet.focus();
			});
	}
}

1545 1546
export class ShowOutdatedExtensionsAction extends Action {

1547
	static readonly ID = 'workbench.extensions.action.listOutdatedExtensions';
1548 1549 1550 1551 1552
	static LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions");

	constructor(
		id: string,
		label: string,
1553
		@IViewletService private readonly viewletService: IViewletService
1554
	) {
R
Rob Lourens 已提交
1555
		super(id, label, undefined, true);
1556 1557
	}

J
Johannes Rieken 已提交
1558
	run(): Promise<void> {
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@outdated ');
				viewlet.focus();
			});
	}
}

export class ShowPopularExtensionsAction extends Action {

1570
	static readonly ID = 'workbench.extensions.action.showPopularExtensions';
1571 1572 1573 1574 1575
	static LABEL = localize('showPopularExtensions', "Show Popular Extensions");

	constructor(
		id: string,
		label: string,
1576
		@IViewletService private readonly viewletService: IViewletService
1577
	) {
R
Rob Lourens 已提交
1578
		super(id, label, undefined, true);
1579 1580
	}

J
Johannes Rieken 已提交
1581
	run(): Promise<void> {
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@sort:installs ');
				viewlet.focus();
			});
	}
}

export class ShowRecommendedExtensionsAction extends Action {

1593
	static readonly ID = 'workbench.extensions.action.showRecommendedExtensions';
1594 1595 1596 1597 1598
	static LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions");

	constructor(
		id: string,
		label: string,
1599
		@IViewletService private readonly viewletService: IViewletService
1600
	) {
R
Rob Lourens 已提交
1601
		super(id, label, undefined, true);
1602 1603
	}

J
Johannes Rieken 已提交
1604
	run(): Promise<void> {
1605 1606 1607 1608 1609 1610 1611 1612 1613
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@recommended ');
				viewlet.focus();
			});
	}
}

1614 1615
export class InstallWorkspaceRecommendedExtensionsAction extends Action {

1616
	static readonly ID = 'workbench.extensions.action.installWorkspaceRecommendedExtensions';
1617 1618
	static LABEL = localize('installWorkspaceRecommendedExtensions', "Install All Workspace Recommended Extensions");

S
Sandeep Somavarapu 已提交
1619 1620 1621 1622
	private _recommendations: IExtensionRecommendation[] = [];
	get recommendations(): IExtensionRecommendation[] { return this._recommendations; }
	set recommendations(recommendations: IExtensionRecommendation[]) { this._recommendations = recommendations; this.enabled = this._recommendations.length > 0; }

1623 1624 1625
	constructor(
		id: string = InstallWorkspaceRecommendedExtensionsAction.ID,
		label: string = InstallWorkspaceRecommendedExtensionsAction.LABEL,
S
Sandeep Somavarapu 已提交
1626
		recommendations: IExtensionRecommendation[],
1627 1628 1629 1630
		@IViewletService private readonly viewletService: IViewletService,
		@INotificationService private readonly notificationService: INotificationService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IOpenerService private readonly openerService: IOpenerService,
1631 1632
		@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
A
Alex Dima 已提交
1633 1634
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IProductService private readonly productService: IProductService,
1635 1636
	) {
		super(id, label, 'extension-action');
S
Sandeep Somavarapu 已提交
1637
		this.recommendations = recommendations;
1638 1639
	}

J
Johannes Rieken 已提交
1640
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
1641 1642 1643 1644 1645 1646
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@recommended ');
				viewlet.focus();
				const names = this.recommendations.map(({ extensionId }) => extensionId);
S
Sandeep Somavarapu 已提交
1647
				return this.extensionWorkbenchService.queryGallery({ names, source: 'install-all-workspace-recommendations' }, CancellationToken.None).then(pager => {
J
Johannes Rieken 已提交
1648
					let installPromises: Promise<any>[] = [];
S
Sandeep Somavarapu 已提交
1649 1650
					let model = new PagedModel(pager);
					for (let i = 0; i < pager.total; i++) {
1651
						installPromises.push(model.resolve(i, CancellationToken.None).then(e => this.installExtension(e)));
S
Sandeep Somavarapu 已提交
1652
					}
S
Sandeep Somavarapu 已提交
1653
					return Promise.all(installPromises);
1654
				});
S
Sandeep Somavarapu 已提交
1655
			});
1656
	}
1657 1658 1659 1660

	private async installExtension(extension: IExtension): Promise<void> {
		try {
			if (extension.local && extension.gallery) {
A
Alex Dima 已提交
1661
				if (isUIExtension(extension.local.manifest, this.productService, this.configurationService)) {
1662 1663 1664 1665
					if (this.extensionManagementServerService.localExtensionManagementServer) {
						await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery);
						return;
					}
1666 1667 1668 1669 1670 1671 1672 1673
				} else if (this.extensionManagementServerService.remoteExtensionManagementServer) {
					await this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery);
					return;
				}
			}
			await this.extensionWorkbenchService.install(extension);
		} catch (err) {
			console.error(err);
1674
			return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
1675 1676
		}
	}
1677 1678
}

1679
export class InstallRecommendedExtensionAction extends Action {
1680

1681
	static readonly ID = 'workbench.extensions.action.installRecommendedExtension';
1682 1683 1684 1685 1686
	static LABEL = localize('installRecommendedExtension', "Install Recommended Extension");

	private extensionId: string;

	constructor(
1687
		extensionId: string,
1688 1689 1690 1691
		@IViewletService private readonly viewletService: IViewletService,
		@INotificationService private readonly notificationService: INotificationService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IOpenerService private readonly openerService: IOpenerService,
1692 1693
		@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
		@IProductService private readonly productService: IProductService
1694
	) {
R
Rob Lourens 已提交
1695
		super(InstallRecommendedExtensionAction.ID, InstallRecommendedExtensionAction.LABEL, undefined, false);
1696 1697 1698
		this.extensionId = extensionId;
	}

J
Johannes Rieken 已提交
1699
	run(): Promise<any> {
1700
		return this.viewletService.openViewlet(VIEWLET_ID, true)
1701 1702
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
1703
				viewlet.search(`@id:${this.extensionId}`);
1704
				viewlet.focus();
S
Sandeep Somavarapu 已提交
1705
				return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None)
S
Sandeep Somavarapu 已提交
1706 1707
					.then(pager => {
						if (pager && pager.firstPage && pager.firstPage.length) {
1708 1709 1710 1711
							const extension = pager.firstPage[0];
							return this.extensionWorkbenchService.install(extension)
								.then(() => null, err => {
									console.error(err);
1712
									return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService);
1713
								});
S
Sandeep Somavarapu 已提交
1714
						}
1715
						return null;
S
Sandeep Somavarapu 已提交
1716
					});
1717
			});
1718 1719 1720
	}
}

1721 1722 1723 1724
export class IgnoreExtensionRecommendationAction extends Action {

	static readonly ID = 'extensions.ignore';

1725
	private static readonly Class = 'extension-action ignore';
1726 1727 1728 1729

	extension: IExtension;

	constructor(
1730
		@IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService,
1731
	) {
1732
		super(IgnoreExtensionRecommendationAction.ID, 'Ignore Recommendation');
1733 1734 1735 1736 1737 1738

		this.class = IgnoreExtensionRecommendationAction.Class;
		this.tooltip = localize('ignoreExtensionRecommendation', "Do not recommend this extension again");
		this.enabled = true;
	}

S
Sandeep Somavarapu 已提交
1739
	public run(): Promise<any> {
S
Sandeep Somavarapu 已提交
1740
		this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, true);
1741
		return Promise.resolve();
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
	}
}

export class UndoIgnoreExtensionRecommendationAction extends Action {

	static readonly ID = 'extensions.ignore';

	private static readonly Class = 'extension-action undo-ignore';

	extension: IExtension;

	constructor(
1754
		@IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService,
1755 1756 1757 1758 1759 1760 1761 1762
	) {
		super(UndoIgnoreExtensionRecommendationAction.ID, 'Undo');

		this.class = UndoIgnoreExtensionRecommendationAction.Class;
		this.tooltip = localize('undo', "Undo");
		this.enabled = true;
	}

S
Sandeep Somavarapu 已提交
1763
	public run(): Promise<any> {
S
Sandeep Somavarapu 已提交
1764
		this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, false);
1765
		return Promise.resolve();
1766 1767 1768
	}
}

1769

1770 1771
export class ShowRecommendedKeymapExtensionsAction extends Action {

1772
	static readonly ID = 'workbench.extensions.action.showRecommendedKeymapExtensions';
1773 1774 1775 1776 1777
	static SHORT_LABEL = localize('showRecommendedKeymapExtensionsShort', "Keymaps");

	constructor(
		id: string,
		label: string,
1778
		@IViewletService private readonly viewletService: IViewletService
1779
	) {
R
Rob Lourens 已提交
1780
		super(id, label, undefined, true);
1781 1782
	}

J
Johannes Rieken 已提交
1783
	run(): Promise<void> {
1784 1785 1786 1787 1788 1789 1790 1791 1792
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@recommended:keymaps ');
				viewlet.focus();
			});
	}
}

1793
export class ShowLanguageExtensionsAction extends Action {
1794

1795
	static readonly ID = 'workbench.extensions.action.showLanguageExtensions';
1796
	static SHORT_LABEL = localize('showLanguageExtensionsShort', "Language Extensions");
1797 1798 1799 1800

	constructor(
		id: string,
		label: string,
1801
		@IViewletService private readonly viewletService: IViewletService
1802
	) {
R
Rob Lourens 已提交
1803
		super(id, label, undefined, true);
1804 1805
	}

J
Johannes Rieken 已提交
1806
	run(): Promise<void> {
1807 1808 1809
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
C
Christof Marti 已提交
1810
				viewlet.search('@category:"programming languages" @sort:installs ');
1811 1812 1813 1814 1815
				viewlet.focus();
			});
	}
}

C
Christof Marti 已提交
1816 1817
export class ShowAzureExtensionsAction extends Action {

1818
	static readonly ID = 'workbench.extensions.action.showAzureExtensions';
C
Christof Marti 已提交
1819 1820 1821 1822 1823
	static SHORT_LABEL = localize('showAzureExtensionsShort', "Azure Extensions");

	constructor(
		id: string,
		label: string,
1824
		@IViewletService private readonly viewletService: IViewletService
C
Christof Marti 已提交
1825
	) {
R
Rob Lourens 已提交
1826
		super(id, label, undefined, true);
C
Christof Marti 已提交
1827 1828
	}

J
Johannes Rieken 已提交
1829
	run(): Promise<void> {
C
Christof Marti 已提交
1830 1831 1832 1833 1834 1835 1836 1837 1838
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search('@sort:installs azure ');
				viewlet.focus();
			});
	}
}

1839 1840 1841 1842 1843 1844 1845 1846 1847
export class ChangeSortAction extends Action {

	private query: Query;

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
		private sortBy: string,
1848
		@IViewletService private readonly viewletService: IViewletService
1849
	) {
R
Rob Lourens 已提交
1850
		super(id, label, undefined, true);
1851

J
Joao Moreno 已提交
1852
		if (sortBy === undefined) {
1853 1854 1855 1856 1857
			throw new Error('bad arguments');
		}

		this.query = Query.parse('');
		this.enabled = false;
M
Matt Bierner 已提交
1858
		this._register(onSearchChange(this.onSearchChange, this));
1859 1860 1861 1862
	}

	private onSearchChange(value: string): void {
		const query = Query.parse(value);
1863
		this.query = new Query(query.value, this.sortBy || query.sortBy, query.groupBy);
1864
		this.enabled = !!value && this.query.isValid() && !this.query.equals(query);
1865 1866
	}

J
Johannes Rieken 已提交
1867
	run(): Promise<void> {
1868 1869 1870 1871 1872 1873 1874 1875 1876
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet as IExtensionsViewlet)
			.then(viewlet => {
				viewlet.search(this.query.toString());
				viewlet.focus();
			});
	}
}

S
Sandeep Somavarapu 已提交
1877 1878 1879 1880
export class ConfigureRecommendedExtensionsCommandsContributor extends Disposable implements IWorkbenchContribution {

	private workspaceContextKey = new RawContextKey<boolean>('workspaceRecommendations', true);
	private workspaceFolderContextKey = new RawContextKey<boolean>('workspaceFolderRecommendations', true);
1881 1882
	private addToWorkspaceRecommendationsContextKey = new RawContextKey<boolean>('addToWorkspaceRecommendations', false);
	private addToWorkspaceFolderRecommendationsContextKey = new RawContextKey<boolean>('addToWorkspaceFolderRecommendations', false);
S
Sandeep Somavarapu 已提交
1883 1884 1885

	constructor(
		@IContextKeyService contextKeyService: IContextKeyService,
1886 1887
		@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
		@IEditorService editorService: IEditorService
S
Sandeep Somavarapu 已提交
1888 1889 1890 1891 1892 1893 1894 1895 1896 1897
	) {
		super();
		const boundWorkspaceContextKey = this.workspaceContextKey.bindTo(contextKeyService);
		boundWorkspaceContextKey.set(workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE);
		this._register(workspaceContextService.onDidChangeWorkbenchState(() => boundWorkspaceContextKey.set(workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));

		const boundWorkspaceFolderContextKey = this.workspaceFolderContextKey.bindTo(contextKeyService);
		boundWorkspaceFolderContextKey.set(workspaceContextService.getWorkspace().folders.length > 0);
		this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => boundWorkspaceFolderContextKey.set(workspaceContextService.getWorkspace().folders.length > 0)));

1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
		const boundAddToWorkspaceRecommendationsContextKey = this.addToWorkspaceRecommendationsContextKey.bindTo(contextKeyService);
		boundAddToWorkspaceRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE);
		this._register(editorService.onDidActiveEditorChange(() => boundAddToWorkspaceRecommendationsContextKey.set(
			editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));
		this._register(workspaceContextService.onDidChangeWorkbenchState(() => boundAddToWorkspaceRecommendationsContextKey.set(
			editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));

		const boundAddToWorkspaceFolderRecommendationsContextKey = this.addToWorkspaceFolderRecommendationsContextKey.bindTo(contextKeyService);
		boundAddToWorkspaceFolderRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput);
		this._register(editorService.onDidActiveEditorChange(() => boundAddToWorkspaceFolderRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput)));
1908

S
Sandeep Somavarapu 已提交
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
		this.registerCommands();
	}

	private registerCommands(): void {
		CommandsRegistry.registerCommand(ConfigureWorkspaceRecommendedExtensionsAction.ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService).createInstance(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL).run();
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
				id: ConfigureWorkspaceRecommendedExtensionsAction.ID,
B
Benjamin Pasero 已提交
1919
				title: { value: `${ExtensionsLabel}: ${ConfigureWorkspaceRecommendedExtensionsAction.LABEL}`, original: 'Extensions: Configure Recommended Extensions (Workspace)' },
1920
				category: localize('extensions', "Extensions")
S
Sandeep Somavarapu 已提交
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
			},
			when: this.workspaceContextKey
		});

		CommandsRegistry.registerCommand(ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService).createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL).run();
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
				id: ConfigureWorkspaceFolderRecommendedExtensionsAction.ID,
B
Benjamin Pasero 已提交
1931
				title: { value: `${ExtensionsLabel}: ${ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL}`, original: 'Extensions: Configure Recommended Extensions (Workspace Folder)' },
1932
				category: localize('extensions', "Extensions")
S
Sandeep Somavarapu 已提交
1933 1934 1935
			},
			when: this.workspaceFolderContextKey
		});
1936

1937 1938 1939 1940
		CommandsRegistry.registerCommand(AddToWorkspaceRecommendationsAction.ADD_ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService)
				.createInstance(AddToWorkspaceRecommendationsAction, AddToWorkspaceRecommendationsAction.ADD_ID, AddToWorkspaceRecommendationsAction.ADD_LABEL)
				.run(AddToWorkspaceRecommendationsAction.ADD);
1941 1942 1943
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
1944
				id: AddToWorkspaceRecommendationsAction.ADD_ID,
1945 1946
				title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace)' },
				category: localize('extensions', "Extensions")
1947
			},
1948
			when: this.addToWorkspaceRecommendationsContextKey
1949 1950
		});

1951 1952 1953 1954 1955 1956 1957 1958
		CommandsRegistry.registerCommand(AddToWorkspaceFolderRecommendationsAction.ADD_ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService)
				.createInstance(AddToWorkspaceFolderRecommendationsAction, AddToWorkspaceFolderRecommendationsAction.ADD_ID, AddToWorkspaceFolderRecommendationsAction.ADD_LABEL)
				.run(AddToWorkspaceRecommendationsAction.ADD);
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
				id: AddToWorkspaceFolderRecommendationsAction.ADD_ID,
1959 1960
				title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.ADD_LABEL}`, original: 'Extensions: Add to Recommended Extensions (Workspace Folder)' },
				category: localize('extensions', "Extensions")
1961 1962 1963
			},
			when: this.addToWorkspaceFolderRecommendationsContextKey
		});
S
Sandeep Somavarapu 已提交
1964

1965 1966 1967 1968 1969 1970 1971 1972
		CommandsRegistry.registerCommand(AddToWorkspaceRecommendationsAction.IGNORE_ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService)
				.createInstance(AddToWorkspaceRecommendationsAction, AddToWorkspaceRecommendationsAction.IGNORE_ID, AddToWorkspaceRecommendationsAction.IGNORE_LABEL)
				.run(AddToWorkspaceRecommendationsAction.IGNORE);
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
				id: AddToWorkspaceRecommendationsAction.IGNORE_ID,
1973 1974
				title: { value: `${ExtensionsLabel}: ${AddToWorkspaceRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace)' },
				category: localize('extensions', "Extensions")
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986
			},
			when: this.addToWorkspaceRecommendationsContextKey
		});

		CommandsRegistry.registerCommand(AddToWorkspaceFolderRecommendationsAction.IGNORE_ID, serviceAccessor => {
			serviceAccessor.get(IInstantiationService)
				.createInstance(AddToWorkspaceFolderRecommendationsAction, AddToWorkspaceFolderRecommendationsAction.IGNORE_ID, AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL)
				.run(AddToWorkspaceRecommendationsAction.IGNORE);
		});
		MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
			command: {
				id: AddToWorkspaceFolderRecommendationsAction.IGNORE_ID,
1987 1988
				title: { value: `${ExtensionsLabel}: ${AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL}`, original: 'Extensions: Ignore Recommended Extension (Workspace Folder)' },
				category: localize('extensions', "Extensions")
1989 1990 1991 1992
			},
			when: this.addToWorkspaceFolderRecommendationsContextKey
		});
	}
1993 1994 1995 1996 1997 1998 1999 2000
}

export abstract class AbstractConfigureRecommendedExtensionsAction extends Action {

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService protected contextService: IWorkspaceContextService,
2001
		@IFileService private readonly fileService: IFileService,
2002
		@ITextFileService private readonly textFileService: ITextFileService,
2003
		@IEditorService protected editorService: IEditorService,
2004 2005
		@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
		@ITextModelService private readonly textModelResolverService: ITextModelService
2006
	) {
2007
		super(id, label);
2008 2009
	}

S
Sandeep Somavarapu 已提交
2010
	protected openExtensionsFile(extensionsFileResource: URI): Promise<any> {
2011
		return this.getOrCreateExtensionsFile(extensionsFileResource)
S
Sandeep Somavarapu 已提交
2012 2013 2014 2015 2016 2017 2018 2019 2020
			.then(({ created, content }) =>
				this.getSelectionPosition(content, extensionsFileResource, ['recommendations'])
					.then(selection => this.editorService.openEditor({
						resource: extensionsFileResource,
						options: {
							pinned: created,
							selection
						}
					})),
S
Sandeep Somavarapu 已提交
2021
				error => Promise.reject(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error))));
2022 2023
	}

S
Sandeep Somavarapu 已提交
2024
	protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<any> {
2025
		return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
B
Benjamin Pasero 已提交
2026
			.then(content => this.getSelectionPosition(content.value.toString(), content.resource, ['extensions', 'recommendations']))
2027 2028 2029
			.then(selection => this.editorService.openEditor({
				resource: workspaceConfigurationFile,
				options: {
B
Benjamin Pasero 已提交
2030 2031
					selection,
					forceReload: true // because content has changed
2032 2033 2034 2035
				}
			}));
	}

2036 2037 2038 2039
	protected addExtensionToWorkspaceConfig(workspaceConfigurationFile: URI, extensionId: string, shouldRecommend: boolean) {
		return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
			.then(content => {
				const extensionIdLowerCase = extensionId.toLowerCase();
B
Benjamin Pasero 已提交
2040
				const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value.toString()) || {})['extensions'] || {};
2041 2042 2043 2044
				let insertInto = shouldRecommend ? workspaceExtensionsConfigContent.recommendations || [] : workspaceExtensionsConfigContent.unwantedRecommendations || [];
				let removeFrom = shouldRecommend ? workspaceExtensionsConfigContent.unwantedRecommendations || [] : workspaceExtensionsConfigContent.recommendations || [];

				if (insertInto.some(e => e.toLowerCase() === extensionIdLowerCase)) {
S
Sandeep Somavarapu 已提交
2045
					return Promise.resolve(null);
2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062
				}

				insertInto.push(extensionId);
				removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);

				return this.jsonEditingService.write(workspaceConfigurationFile,
					{
						key: 'extensions',
						value: {
							recommendations: shouldRecommend ? insertInto : removeFrom,
							unwantedRecommendations: shouldRecommend ? removeFrom : insertInto
						}
					},
					true);
			});
	}

S
Sandeep Somavarapu 已提交
2063
	protected addExtensionToWorkspaceFolderConfig(extensionsFileResource: URI, extensionId: string, shouldRecommend: boolean): Promise<any> {
2064 2065 2066
		return this.getOrCreateExtensionsFile(extensionsFileResource)
			.then(({ content }) => {
				const extensionIdLowerCase = extensionId.toLowerCase();
2067 2068 2069
				const extensionsConfigContent: IExtensionsConfigContent = json.parse(content) || {};
				let insertInto = shouldRecommend ? extensionsConfigContent.recommendations || [] : extensionsConfigContent.unwantedRecommendations || [];
				let removeFrom = shouldRecommend ? extensionsConfigContent.unwantedRecommendations || [] : extensionsConfigContent.recommendations || [];
2070

2071
				if (insertInto.some(e => e.toLowerCase() === extensionIdLowerCase)) {
S
Sandeep Somavarapu 已提交
2072
					return Promise.resolve(null);
2073 2074
				}

2075 2076
				insertInto.push(extensionId);

2077
				let removeFromPromise: Promise<void> = Promise.resolve();
2078 2079 2080
				if (removeFrom.some(e => e.toLowerCase() === extensionIdLowerCase)) {
					removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);
					removeFromPromise = this.jsonEditingService.write(extensionsFileResource,
2081
						{
2082 2083
							key: shouldRecommend ? 'unwantedRecommendations' : 'recommendations',
							value: removeFrom
2084 2085 2086 2087
						},
						true);
				}

2088
				return removeFromPromise.then(() =>
2089 2090
					this.jsonEditingService.write(extensionsFileResource,
						{
2091 2092
							key: shouldRecommend ? 'recommendations' : 'unwantedRecommendations',
							value: insertInto
2093 2094 2095 2096 2097 2098
						},
						true)
				);
			});
	}

S
Sandeep Somavarapu 已提交
2099
	protected getWorkspaceExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
B
Benjamin Pasero 已提交
2100
		return Promise.resolve(this.fileService.readFile(extensionsFileResource))
2101
			.then(content => {
B
Benjamin Pasero 已提交
2102
				return (json.parse(content.value.toString()) || {})['extensions'] || {};
2103 2104 2105
			}, err => ({ recommendations: [], unwantedRecommendations: [] }));
	}

S
Sandeep Somavarapu 已提交
2106
	protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
B
Benjamin Pasero 已提交
2107
		return Promise.resolve(this.fileService.readFile(extensionsFileResource))
2108
			.then(content => {
B
Benjamin Pasero 已提交
2109
				return (<IExtensionsConfigContent>json.parse(content.value.toString()));
2110
			}, err => ({ recommendations: [], unwantedRecommendations: [] }));
2111 2112
	}

B
Benjamin Pasero 已提交
2113 2114
	private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IFileContent> {
		return Promise.resolve(this.fileService.readFile(workspaceConfigurationFile))
2115
			.then(content => {
B
Benjamin Pasero 已提交
2116
				const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value.toString())['extensions'];
2117 2118
				if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
					return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true)
B
Benjamin Pasero 已提交
2119
						.then(() => this.fileService.readFile(workspaceConfigurationFile));
2120 2121 2122 2123 2124
				}
				return content;
			});
	}

J
Johannes Rieken 已提交
2125
	private getSelectionPosition(content: string, resource: URI, path: json.JSONPath): Promise<ITextEditorSelection | undefined> {
S
Sandeep Somavarapu 已提交
2126 2127
		const tree = json.parseTree(content);
		const node = json.findNodeAtLocation(tree, path);
2128
		if (node && node.parent && node.parent.children) {
S
Sandeep Somavarapu 已提交
2129 2130 2131
			const recommendationsValueNode = node.parent.children[1];
			const lastExtensionNode = recommendationsValueNode.children && recommendationsValueNode.children.length ? recommendationsValueNode.children[recommendationsValueNode.children.length - 1] : null;
			const offset = lastExtensionNode ? lastExtensionNode.offset + lastExtensionNode.length : recommendationsValueNode.offset + 1;
S
Sandeep Somavarapu 已提交
2132
			return Promise.resolve(this.textModelResolverService.createModelReference(resource))
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
				.then(reference => {
					const position = reference.object.textEditorModel.getPositionAt(offset);
					reference.dispose();
					return <ITextEditorSelection>{
						startLineNumber: position.lineNumber,
						startColumn: position.column,
						endLineNumber: position.lineNumber,
						endColumn: position.column,
					};
				});
		}
J
Johannes Rieken 已提交
2144
		return Promise.resolve(undefined);
2145 2146
	}

S
Sandeep Somavarapu 已提交
2147
	private getOrCreateExtensionsFile(extensionsFileResource: URI): Promise<{ created: boolean, extensionsFileResource: URI, content: string }> {
B
Benjamin Pasero 已提交
2148 2149
		return Promise.resolve(this.fileService.readFile(extensionsFileResource)).then(content => {
			return { created: false, extensionsFileResource, content: content.value.toString() };
2150
		}, err => {
B
Benjamin Pasero 已提交
2151
			return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
S
Sandeep Somavarapu 已提交
2152
				return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
2153 2154 2155 2156 2157 2158
			});
		});
	}
}

export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction {
2159

2160
	static readonly ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions';
2161 2162
	static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)");

2163

2164 2165 2166
	constructor(
		id: string,
		label: string,
2167
		@IFileService fileService: IFileService,
2168
		@ITextFileService textFileService: ITextFileService,
2169
		@IWorkspaceContextService contextService: IWorkspaceContextService,
2170
		@IEditorService editorService: IEditorService,
2171 2172
		@IJSONEditingService jsonEditingService: IJSONEditingService,
		@ITextModelService textModelResolverService: ITextModelService
2173
	) {
2174
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
M
Matt Bierner 已提交
2175
		this._register(this.contextService.onDidChangeWorkbenchState(() => this.update(), this));
2176 2177 2178 2179 2180
		this.update();
	}

	private update(): void {
		this.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY;
2181 2182
	}

2183
	public run(): Promise<void> {
2184 2185
		switch (this.contextService.getWorkbenchState()) {
			case WorkbenchState.FOLDER:
2186
				return this.openExtensionsFile(this.contextService.getWorkspace().folders[0].toResource(EXTENSIONS_CONFIG));
2187
			case WorkbenchState.WORKSPACE:
2188
				return this.openWorkspaceConfigurationFile(this.contextService.getWorkspace().configuration!);
2189
		}
2190
		return Promise.resolve();
2191
	}
2192
}
2193

2194 2195
export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction {

2196
	static readonly ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions';
2197 2198 2199 2200 2201 2202 2203
	static LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)");


	constructor(
		id: string,
		label: string,
		@IFileService fileService: IFileService,
2204
		@ITextFileService textFileService: ITextFileService,
2205
		@IWorkspaceContextService contextService: IWorkspaceContextService,
2206
		@IEditorService editorService: IEditorService,
2207
		@IJSONEditingService jsonEditingService: IJSONEditingService,
S
Sandeep Somavarapu 已提交
2208
		@ITextModelService textModelResolverService: ITextModelService,
2209
		@ICommandService private readonly commandService: ICommandService
2210
	) {
2211
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
M
Matt Bierner 已提交
2212
		this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this));
2213
		this.update();
2214 2215
	}

2216 2217 2218
	private update(): void {
		this.enabled = this.contextService.getWorkspace().folders.length > 0;
	}
2219

S
Sandeep Somavarapu 已提交
2220
	public run(): Promise<any> {
2221
		const folderCount = this.contextService.getWorkspace().folders.length;
S
Sandeep Somavarapu 已提交
2222 2223
		const pickFolderPromise = folderCount === 1 ? Promise.resolve(this.contextService.getWorkspace().folders[0]) : this.commandService.executeCommand<IWorkspaceFolder>(PICK_WORKSPACE_FOLDER_COMMAND_ID);
		return Promise.resolve(pickFolderPromise)
S
Sandeep Somavarapu 已提交
2224 2225
			.then(workspaceFolder => {
				if (workspaceFolder) {
2226
					return this.openExtensionsFile(workspaceFolder.toResource(EXTENSIONS_CONFIG));
2227
				}
S
Sandeep Somavarapu 已提交
2228
				return null;
2229
			});
2230 2231 2232
	}
}

2233 2234 2235 2236 2237 2238 2239
export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction {
	static readonly ADD = true;
	static readonly IGNORE = false;
	static readonly ADD_ID = 'workbench.extensions.action.addToWorkspaceFolderRecommendations';
	static readonly ADD_LABEL = localize('addToWorkspaceFolderRecommendations', "Add to Recommended Extensions (Workspace Folder)");
	static readonly IGNORE_ID = 'workbench.extensions.action.addToWorkspaceFolderIgnoredRecommendations';
	static readonly IGNORE_LABEL = localize('addToWorkspaceFolderIgnoredRecommendations', "Ignore Recommended Extension (Workspace Folder)");
2240 2241 2242 2243 2244

	constructor(
		id: string,
		label: string,
		@IFileService fileService: IFileService,
2245
		@ITextFileService textFileService: ITextFileService,
2246 2247 2248 2249
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEditorService editorService: IEditorService,
		@IJSONEditingService jsonEditingService: IJSONEditingService,
		@ITextModelService textModelResolverService: ITextModelService,
2250 2251
		@ICommandService private readonly commandService: ICommandService,
		@INotificationService private readonly notificationService: INotificationService
2252
	) {
2253
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
2254 2255
	}

S
Sandeep Somavarapu 已提交
2256
	run(shouldRecommend: boolean): Promise<void> {
2257
		if (!(this.editorService.activeEditor instanceof ExtensionsInput) || !this.editorService.activeEditor.extension) {
2258
			return Promise.resolve();
2259 2260 2261
		}
		const folders = this.contextService.getWorkspace().folders;
		if (!folders || !folders.length) {
2262
			this.notificationService.info(localize('AddToWorkspaceFolderRecommendations.noWorkspace', 'There are no workspace folders open to add recommendations.'));
2263
			return Promise.resolve();
2264 2265
		}

S
Sandeep Somavarapu 已提交
2266
		const extensionId = this.editorService.activeEditor.extension.identifier;
2267
		const pickFolderPromise = folders.length === 1
S
Sandeep Somavarapu 已提交
2268
			? Promise.resolve(folders[0])
2269
			: this.commandService.executeCommand<IWorkspaceFolder>(PICK_WORKSPACE_FOLDER_COMMAND_ID);
S
Sandeep Somavarapu 已提交
2270
		return Promise.resolve(pickFolderPromise)
2271 2272
			.then(workspaceFolder => {
				if (!workspaceFolder) {
2273
					return Promise.resolve();
2274
				}
2275
				const configurationFile = workspaceFolder.toResource(EXTENSIONS_CONFIG);
2276
				return this.getWorkspaceFolderExtensionsConfigContent(configurationFile).then(content => {
S
Sandeep Somavarapu 已提交
2277
					const extensionIdLowerCase = extensionId.id.toLowerCase();
2278
					if (shouldRecommend) {
2279
						if ((content.recommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
2280
							this.notificationService.info(localize('AddToWorkspaceFolderRecommendations.alreadyExists', 'This extension is already present in this workspace folder\'s recommendations.'));
2281
							return Promise.resolve();
2282 2283
						}

S
Sandeep Somavarapu 已提交
2284
						return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId.id, shouldRecommend).then(() => {
2285 2286 2287 2288 2289 2290
							this.notificationService.prompt(Severity.Info,
								localize('AddToWorkspaceFolderRecommendations.success', 'The extension was successfully added to this workspace folder\'s recommendations.'),
								[{
									label: localize('viewChanges', "View Changes"),
									run: () => this.openExtensionsFile(configurationFile)
								}]);
2291 2292 2293
						}, err => {
							this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
						});
2294
					}
2295
					else {
2296
						if ((content.unwantedRecommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
2297
							this.notificationService.info(localize('AddToWorkspaceFolderIgnoredRecommendations.alreadyExists', 'This extension is already present in this workspace folder\'s unwanted recommendations.'));
2298
							return Promise.resolve();
2299
						}
2300

S
Sandeep Somavarapu 已提交
2301
						return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId.id, shouldRecommend).then(() => {
2302 2303 2304 2305 2306 2307
							this.notificationService.prompt(Severity.Info,
								localize('AddToWorkspaceFolderIgnoredRecommendations.success', 'The extension was successfully added to this workspace folder\'s unwanted recommendations.'),
								[{
									label: localize('viewChanges', "View Changes"),
									run: () => this.openExtensionsFile(configurationFile)
								}]);
2308 2309 2310 2311
						}, err => {
							this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
						});
					}
2312 2313 2314 2315 2316
				});
			});
	}
}

2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328
export class AddToWorkspaceRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction {
	static readonly ADD = true;
	static readonly IGNORE = false;
	static readonly ADD_ID = 'workbench.extensions.action.addToWorkspaceRecommendations';
	static readonly ADD_LABEL = localize('addToWorkspaceRecommendations', "Add to Recommended Extensions (Workspace)");
	static readonly IGNORE_ID = 'workbench.extensions.action.addToWorkspaceIgnoredRecommendations';
	static readonly IGNORE_LABEL = localize('addToWorkspaceIgnoredRecommendations', "Ignore Recommended Extension (Workspace)");

	constructor(
		id: string,
		label: string,
		@IFileService fileService: IFileService,
2329
		@ITextFileService textFileService: ITextFileService,
2330 2331 2332 2333
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IEditorService editorService: IEditorService,
		@IJSONEditingService jsonEditingService: IJSONEditingService,
		@ITextModelService textModelResolverService: ITextModelService,
2334
		@INotificationService private readonly notificationService: INotificationService
2335
	) {
2336
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
2337 2338
	}

S
Sandeep Somavarapu 已提交
2339
	run(shouldRecommend: boolean): Promise<void> {
2340 2341
		const workspaceConfig = this.contextService.getWorkspace().configuration;

2342 2343 2344 2345
		if (!(this.editorService.activeEditor instanceof ExtensionsInput) || !this.editorService.activeEditor.extension || !workspaceConfig) {
			return Promise.resolve();
		}

S
Sandeep Somavarapu 已提交
2346
		const extensionId = this.editorService.activeEditor.extension.identifier;
2347 2348

		return this.getWorkspaceExtensionsConfigContent(workspaceConfig).then(content => {
S
Sandeep Somavarapu 已提交
2349
			const extensionIdLowerCase = extensionId.id.toLowerCase();
2350 2351 2352
			if (shouldRecommend) {
				if ((content.recommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
					this.notificationService.info(localize('AddToWorkspaceRecommendations.alreadyExists', 'This extension is already present in workspace recommendations.'));
2353
					return Promise.resolve();
2354 2355
				}

S
Sandeep Somavarapu 已提交
2356
				return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId.id, shouldRecommend).then(() => {
2357 2358 2359 2360 2361 2362 2363
					this.notificationService.prompt(Severity.Info,
						localize('AddToWorkspaceRecommendations.success', 'The extension was successfully added to this workspace\'s recommendations.'),
						[{
							label: localize('viewChanges', "View Changes"),
							run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
						}]);

2364 2365 2366 2367 2368 2369
				}, err => {
					this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
				});
			} else {
				if ((content.unwantedRecommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
					this.notificationService.info(localize('AddToWorkspaceUnwantedRecommendations.alreadyExists', 'This extension is already present in workspace unwanted recommendations.'));
2370
					return Promise.resolve();
2371 2372
				}

S
Sandeep Somavarapu 已提交
2373
				return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId.id, shouldRecommend).then(() => {
2374 2375 2376 2377 2378 2379
					this.notificationService.prompt(Severity.Info,
						localize('AddToWorkspaceUnwantedRecommendations.success', 'The extension was successfully added to this workspace\'s unwanted recommendations.'),
						[{
							label: localize('viewChanges', "View Changes"),
							run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
						}]);
2380 2381 2382 2383 2384 2385 2386 2387
				}, err => {
					this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
				});
			}
		});
	}
}

S
#66931  
Sandeep Somavarapu 已提交
2388 2389 2390 2391 2392
export class StatusLabelAction extends Action implements IExtensionContainer {

	private static readonly ENABLED_CLASS = 'extension-status-label';
	private static readonly DISABLED_CLASS = `${StatusLabelAction.ENABLED_CLASS} hide`;

S
Sandeep Somavarapu 已提交
2393
	private initialStatus: ExtensionState | null = null;
S
#66931  
Sandeep Somavarapu 已提交
2394 2395 2396 2397 2398 2399
	private status: ExtensionState | null = null;
	private enablementState: EnablementState | null = null;

	private _extension: IExtension;
	get extension(): IExtension { return this._extension; }
	set extension(extension: IExtension) {
S
Sandeep Somavarapu 已提交
2400
		if (!(this._extension && extension && areSameExtensions(this._extension.identifier, extension.identifier))) {
S
#66931  
Sandeep Somavarapu 已提交
2401
			// Different extension. Reset
S
Sandeep Somavarapu 已提交
2402
			this.initialStatus = null;
S
#66931  
Sandeep Somavarapu 已提交
2403 2404 2405 2406 2407 2408 2409 2410
			this.status = null;
			this.enablementState = null;
		}
		this._extension = extension;
		this.update();
	}

	constructor(
2411 2412
		@IExtensionService private readonly extensionService: IExtensionService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
S
#66931  
Sandeep Somavarapu 已提交
2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
	) {
		super('extensions.action.statusLabel', '', StatusLabelAction.DISABLED_CLASS, false);
	}

	update(): void {
		this.computeLabel()
			.then(label => {
				this.label = label || '';
				this.class = label ? StatusLabelAction.ENABLED_CLASS : StatusLabelAction.DISABLED_CLASS;
			});
	}

	private async computeLabel(): Promise<string | null> {
		if (!this.extension) {
			return null;
		}

		const currentStatus = this.status;
		const currentEnablementState = this.enablementState;
		this.status = this.extension.state;
S
Sandeep Somavarapu 已提交
2433 2434 2435
		if (this.initialStatus === null) {
			this.initialStatus = this.status;
		}
S
#66931  
Sandeep Somavarapu 已提交
2436 2437 2438
		this.enablementState = this.extension.enablementState;

		const runningExtensions = await this.extensionService.getExtensions();
S
Sandeep Somavarapu 已提交
2439
		const canAddExtension = () => {
S
Sandeep Somavarapu 已提交
2440
			const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0];
S
Sandeep Somavarapu 已提交
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450
			if (this.extension.local) {
				if (runningExtension && this.extension.version === runningExtension.version) {
					return true;
				}
				return this.extensionService.canAddExtension(toExtensionDescription(this.extension.local));
			}
			return false;
		};
		const canRemoveExtension = () => {
			if (this.extension.local) {
S
Sandeep Somavarapu 已提交
2451
				if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) {
S
Sandeep Somavarapu 已提交
2452 2453 2454 2455 2456 2457
					return true;
				}
				return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension.local));
			}
			return false;
		};
S
#66931  
Sandeep Somavarapu 已提交
2458 2459 2460

		if (currentStatus !== null) {
			if (currentStatus === ExtensionState.Installing && this.status === ExtensionState.Installed) {
S
Sandeep Somavarapu 已提交
2461
				return canAddExtension() ? this.initialStatus === ExtensionState.Installed ? localize('updated', "Updated") : localize('installed', "Installed") : null;
S
#66931  
Sandeep Somavarapu 已提交
2462 2463
			}
			if (currentStatus === ExtensionState.Uninstalling && this.status === ExtensionState.Uninstalled) {
S
Sandeep Somavarapu 已提交
2464
				this.initialStatus = this.status;
S
#66931  
Sandeep Somavarapu 已提交
2465 2466 2467 2468 2469
				return canRemoveExtension() ? localize('uninstalled', "Uninstalled") : null;
			}
		}

		if (currentEnablementState !== null) {
2470 2471
			const currentlyEnabled = currentEnablementState === EnablementState.EnabledGlobally || currentEnablementState === EnablementState.EnabledWorkspace;
			const enabled = this.enablementState === EnablementState.EnabledGlobally || this.enablementState === EnablementState.EnabledWorkspace;
S
#66931  
Sandeep Somavarapu 已提交
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484
			if (!currentlyEnabled && enabled) {
				return canAddExtension() ? localize('enabled', "Enabled") : null;
			}
			if (currentlyEnabled && !enabled) {
				return canRemoveExtension() ? localize('disabled', "Disabled") : null;
			}

		}

		return null;
	}

	run(): Promise<any> {
2485
		return Promise.resolve();
S
#66931  
Sandeep Somavarapu 已提交
2486 2487 2488 2489
	}

}

S
Sandeep Somavarapu 已提交
2490
export class MaliciousStatusLabelAction extends ExtensionAction {
J
Joao Moreno 已提交
2491 2492 2493 2494

	private static readonly Class = 'malicious-status';

	constructor(long: boolean) {
J
Joao Moreno 已提交
2495
		const tooltip = localize('malicious tooltip', "This extension was reported to be problematic.");
J
Joao Moreno 已提交
2496 2497
		const label = long ? tooltip : localize('malicious', "Malicious");
		super('extensions.install', label, '', false);
J
Joao Moreno 已提交
2498
		this.tooltip = localize('malicious tooltip', "This extension was reported to be problematic.");
J
Joao Moreno 已提交
2499 2500
	}

S
Sandeep Somavarapu 已提交
2501
	update(): void {
J
Joao Moreno 已提交
2502 2503 2504 2505 2506 2507 2508
		if (this.extension && this.extension.isMalicious) {
			this.class = `${MaliciousStatusLabelAction.Class} malicious`;
		} else {
			this.class = `${MaliciousStatusLabelAction.Class} not-malicious`;
		}
	}

S
Sandeep Somavarapu 已提交
2509
	run(): Promise<any> {
2510
		return Promise.resolve();
J
Joao Moreno 已提交
2511 2512 2513
	}
}

S
Sandeep Somavarapu 已提交
2514
export class ExtensionToolTipAction extends ExtensionAction {
2515 2516 2517 2518

	private static readonly Class = 'disable-status';

	updateWhenCounterExtensionChanges: boolean = true;
2519
	private _runningExtensions: IExtensionDescription[] | null = null;
2520

2521 2522
	constructor(
		private readonly warningAction: SystemDisabledWarningAction,
S
Sandeep Somavarapu 已提交
2523
		private readonly reloadAction: ReloadAction,
2524
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
2525
		@IExtensionService private readonly extensionService: IExtensionService,
S
Sandeep Somavarapu 已提交
2526
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
2527
	) {
S
Sandeep Somavarapu 已提交
2528
		super('extensions.tooltip', warningAction.tooltip, `${ExtensionToolTipAction.Class} hide`, false);
M
Matt Bierner 已提交
2529 2530
		this._register(warningAction.onDidChange(() => this.update(), this));
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
2531 2532 2533 2534 2535
		this.updateRunningExtensions();
	}

	private updateRunningExtensions(): void {
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
2536 2537 2538
	}

	update(): void {
S
Sandeep Somavarapu 已提交
2539 2540 2541 2542
		this.label = this.getTooltip();
		this.class = ExtensionToolTipAction.Class;
		if (!this.label) {
			this.class = `${ExtensionToolTipAction.Class} hide`;
2543
		}
S
Sandeep Somavarapu 已提交
2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554
	}

	private getTooltip(): string {
		if (!this.extension) {
			return '';
		}
		if (this.reloadAction.enabled) {
			return this.reloadAction.tooltip;
		}
		if (this.warningAction.tooltip) {
			return this.warningAction.tooltip;
2555
		}
S
Sandeep Somavarapu 已提交
2556 2557
		if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) {
			const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier));
2558
			const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
S
Sandeep Somavarapu 已提交
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580

			if (isEnabled && isRunning) {
				if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
					if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
						return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.extension.server.label);
					}
				}
				if (this.extension.enablementState === EnablementState.EnabledGlobally) {
					return localize('globally enabled', "This extension is enabled globally.");
				}
				if (this.extension.enablementState === EnablementState.EnabledWorkspace) {
					return localize('workspace enabled', "This extension is enabled for this workspace by the user.");
				}
			}

			if (!isEnabled && !isRunning) {
				if (this.extension.enablementState === EnablementState.DisabledGlobally) {
					return localize('globally disabled', "This extension is disabled globally by the user.");
				}
				if (this.extension.enablementState === EnablementState.DisabledWorkspace) {
					return localize('workspace disabled', "This extension is disabled for this workspace by the user.");
				}
2581
			}
2582
		}
S
Sandeep Somavarapu 已提交
2583
		return '';
2584 2585 2586 2587 2588 2589 2590 2591 2592
	}

	run(): Promise<any> {
		return Promise.resolve(null);
	}
}

export class SystemDisabledWarningAction extends ExtensionAction {

2593 2594 2595
	private static readonly CLASS = 'system-disable';
	private static readonly WARNING_CLASS = `${SystemDisabledWarningAction.CLASS} warning`;
	private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} info`;
2596 2597

	updateWhenCounterExtensionChanges: boolean = true;
2598
	private _runningExtensions: IExtensionDescription[] | null = null;
2599

2600 2601 2602
	constructor(
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
A
Alex Dima 已提交
2603
		@IProductService private readonly productService: IProductService,
2604
		@ILabelService private readonly labelService: ILabelService,
2605 2606
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionService private readonly extensionService: IExtensionService,
2607
	) {
2608
		super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false);
M
Matt Bierner 已提交
2609 2610
		this._register(this.labelService.onDidChangeFormatters(() => this.update(), this));
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
2611
		this.updateRunningExtensions();
2612 2613 2614
		this.update();
	}

2615 2616 2617 2618
	private updateRunningExtensions(): void {
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
	}

2619
	update(): void {
2620
		this.class = `${SystemDisabledWarningAction.CLASS} hide`;
2621
		this.tooltip = '';
2622 2623 2624 2625 2626
		if (
			!this.extension ||
			!this.extension.local ||
			!this.extension.server ||
			!this._runningExtensions ||
2627
			!(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) ||
2628
			this.extension.state !== ExtensionState.Installed
2629
		) {
2630 2631
			return;
		}
2632 2633 2634 2635
		if (isLanguagePackExtension(this.extension.local.manifest)) {
			if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) {
				this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
				this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer
2636
					? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.extensionManagementServerService.remoteExtensionManagementServer.label)
S
Sandeep Somavarapu 已提交
2637
					: localize('Install language pack also locally', "Install the language pack extension locally to enable it also there.");
2638 2639 2640
			}
			return;
		}
S
Sandeep Somavarapu 已提交
2641
		const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0];
2642 2643 2644
		const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
		const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
		const localExtensionServer = localExtension ? localExtension.server : null;
A
Alex Dima 已提交
2645
		if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) {
2646
			if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
2647
				this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
2648
				this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.extensionManagementServerService.remoteExtensionManagementServer.label);
2649
				return;
2650
			}
2651
			if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
2652
				this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
2653
				this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.extensionManagementServerService.remoteExtensionManagementServer.label);
2654 2655 2656
				return;
			}
		}
A
Alex Dima 已提交
2657
		if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) {
2658
			if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
2659
				this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
2660
				this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.extensionManagementServerService.remoteExtensionManagementServer.label);
2661 2662 2663
				return;
			}
			if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
2664
				this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
2665 2666
				this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
				return;
2667
			}
2668 2669 2670 2671 2672 2673 2674 2675
		}
	}

	run(): Promise<any> {
		return Promise.resolve(null);
	}
}

2676 2677
export class DisableAllAction extends Action {

2678
	static readonly ID = 'workbench.extensions.action.disableAll';
2679 2680 2681 2682 2683
	static LABEL = localize('disableAll', "Disable All Installed Extensions");


	constructor(
		id: string = DisableAllAction.ID, label: string = DisableAllAction.LABEL,
2684 2685
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
2686 2687 2688
	) {
		super(id, label);
		this.update();
M
Matt Bierner 已提交
2689
		this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
2690 2691 2692
	}

	private update(): void {
2693
		this.enabled = this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
2694 2695
	}

S
Sandeep Somavarapu 已提交
2696
	run(): Promise<any> {
2697
		return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.DisabledGlobally);
2698 2699 2700 2701 2702
	}
}

export class DisableAllWorkpsaceAction extends Action {

2703
	static readonly ID = 'workbench.extensions.action.disableAllWorkspace';
2704 2705 2706 2707 2708
	static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace");


	constructor(
		id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL,
2709
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
2710 2711
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
2712 2713 2714
	) {
		super(id, label);
		this.update();
M
Matt Bierner 已提交
2715 2716
		this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this));
		this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this));
2717 2718 2719
	}

	private update(): void {
2720
		this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => e.type === ExtensionType.User && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
2721 2722
	}

S
Sandeep Somavarapu 已提交
2723
	run(): Promise<any> {
2724
		return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.DisabledWorkspace);
2725 2726 2727 2728 2729
	}
}

export class EnableAllAction extends Action {

2730
	static readonly ID = 'workbench.extensions.action.enableAll';
S
Sandeep Somavarapu 已提交
2731
	static LABEL = localize('enableAll', "Enable All Extensions");
2732 2733 2734 2735


	constructor(
		id: string = EnableAllAction.ID, label: string = EnableAllAction.LABEL,
2736 2737
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
2738 2739 2740
	) {
		super(id, label);
		this.update();
M
Matt Bierner 已提交
2741
		this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
2742 2743 2744
	}

	private update(): void {
2745
		this.enabled = this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
2746 2747
	}

S
Sandeep Somavarapu 已提交
2748
	run(): Promise<any> {
2749
		return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.EnabledGlobally);
2750 2751 2752 2753 2754
	}
}

export class EnableAllWorkpsaceAction extends Action {

2755
	static readonly ID = 'workbench.extensions.action.enableAllWorkspace';
S
Sandeep Somavarapu 已提交
2756
	static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace");
2757 2758 2759 2760


	constructor(
		id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL,
2761 2762 2763
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
2764 2765 2766
	) {
		super(id, label);
		this.update();
M
Matt Bierner 已提交
2767 2768
		this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this));
		this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this));
2769 2770 2771
	}

	private update(): void {
2772
		this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
2773 2774
	}

S
Sandeep Somavarapu 已提交
2775
	run(): Promise<any> {
2776
		return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.EnabledWorkspace);
2777
	}
2778 2779
}

J
Joao Moreno 已提交
2780 2781 2782 2783 2784 2785 2786 2787
export class OpenExtensionsFolderAction extends Action {

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

	constructor(
		id: string,
		label: string,
2788 2789 2790
		@IWindowsService private readonly windowsService: IWindowsService,
		@IFileService private readonly fileService: IFileService,
		@IEnvironmentService private readonly environmentService: IEnvironmentService
J
Joao Moreno 已提交
2791
	) {
R
Rob Lourens 已提交
2792
		super(id, label, undefined, true);
J
Joao Moreno 已提交
2793 2794
	}

S
Sandeep Somavarapu 已提交
2795
	run(): Promise<void> {
2796
		if (this.environmentService.extensionsPath) {
J
Joao Moreno 已提交
2797

2798
			const extensionsHome = URI.file(this.environmentService.extensionsPath);
J
Joao Moreno 已提交
2799

2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
			return Promise.resolve(this.fileService.resolve(extensionsHome)).then(file => {
				let itemToShow: URI;
				if (file.children && file.children.length > 0) {
					itemToShow = file.children[0].resource;
				} else {
					itemToShow = extensionsHome;
				}

				return this.windowsService.showItemInFolder(itemToShow);
			});
		}
		return Promise.resolve();
J
Joao Moreno 已提交
2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
	}
}

export class InstallVSIXAction extends Action {

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

	constructor(
		id = InstallVSIXAction.ID,
		label = InstallVSIXAction.LABEL,
2823 2824
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@INotificationService private readonly notificationService: INotificationService,
S
Sandeep Somavarapu 已提交
2825
		@IWindowService private readonly windowService: IWindowService,
2826
		@IFileDialogService private readonly fileDialogService: IFileDialogService,
S
Sandeep Somavarapu 已提交
2827 2828
		@IExtensionService private readonly extensionService: IExtensionService,
		@IInstantiationService private readonly instantiationService: IInstantiationService
J
Joao Moreno 已提交
2829
	) {
S
Sandeep Somavarapu 已提交
2830
		super(id, label, 'extension-action install-vsix', true);
J
Joao Moreno 已提交
2831 2832
	}

S
Sandeep Somavarapu 已提交
2833
	run(): Promise<any> {
2834
		return Promise.resolve(this.fileDialogService.showOpenDialog({
J
Joao Moreno 已提交
2835 2836
			title: localize('installFromVSIX', "Install from VSIX"),
			filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
2837 2838
			canSelectFiles: true,
			openLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
S
Sandeep Somavarapu 已提交
2839
		})).then(result => {
J
Joao Moreno 已提交
2840
			if (!result) {
2841
				return Promise.resolve();
J
Joao Moreno 已提交
2842 2843
			}

2844
			return Promise.all(result.map(vsix => this.extensionsWorkbenchService.install(vsix)))
S
Sandeep Somavarapu 已提交
2845 2846 2847
				.then(extensions => {
					for (const extension of extensions) {
						const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
2848 2849
						const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.displayName || extension.name)
							: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.displayName || extension.name);
S
Sandeep Somavarapu 已提交
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862
						const actions = requireReload ? [{
							label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
							run: () => this.windowService.reloadWindow()
						}] : [];
						this.notificationService.prompt(
							Severity.Info,
							message,
							actions,
							{ sticky: true }
						);
					}
					return this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL).run();
				});
J
Joao Moreno 已提交
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873
		});
	}
}

export class ReinstallAction extends Action {

	static readonly ID = 'workbench.extensions.action.reinstall';
	static LABEL = localize('reinstall', "Reinstall Extension...");

	constructor(
		id: string = ReinstallAction.ID, label: string = ReinstallAction.LABEL,
2874 2875 2876 2877
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
		@IWindowService private readonly windowService: IWindowService,
S
Sandeep Somavarapu 已提交
2878 2879
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IExtensionService private readonly extensionService: IExtensionService
J
Joao Moreno 已提交
2880 2881 2882 2883 2884
	) {
		super(id, label);
	}

	get enabled(): boolean {
2885
		return this.extensionsWorkbenchService.local.filter(l => l.type === ExtensionType.User && l.local).length > 0;
J
Joao Moreno 已提交
2886 2887
	}

J
Johannes Rieken 已提交
2888
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
2889
		return this.quickInputService.pick(this.getEntries(), { placeHolder: localize('selectExtensionToReinstall', "Select Extension to Reinstall") })
C
Christof Marti 已提交
2890
			.then(pick => pick && this.reinstallExtension(pick.extension));
J
Joao Moreno 已提交
2891 2892
	}

J
Johannes Rieken 已提交
2893
	private getEntries(): Promise<(IQuickPickItem & { extension: IExtension })[]> {
J
Joao Moreno 已提交
2894 2895
		return this.extensionsWorkbenchService.queryLocal()
			.then(local => {
C
Christof Marti 已提交
2896
				const entries = local
2897
					.filter(extension => extension.type === ExtensionType.User)
J
Joao Moreno 已提交
2898
					.map(extension => {
C
Christof Marti 已提交
2899
						return {
S
Sandeep Somavarapu 已提交
2900
							id: extension.identifier.id,
J
Joao Moreno 已提交
2901
							label: extension.displayName,
S
Sandeep Somavarapu 已提交
2902
							description: extension.identifier.id,
C
Christof Marti 已提交
2903 2904
							extension,
						} as (IQuickPickItem & { extension: IExtension });
J
Joao Moreno 已提交
2905 2906 2907 2908 2909
					});
				return entries;
			});
	}

J
Johannes Rieken 已提交
2910
	private reinstallExtension(extension: IExtension): Promise<void> {
S
Sandeep Somavarapu 已提交
2911 2912
		return this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL).run()
			.then(() => {
2913
				return this.extensionsWorkbenchService.reinstall(extension)
S
Sandeep Somavarapu 已提交
2914 2915 2916 2917 2918 2919 2920 2921
					.then(extension => {
						const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
						const message = requireReload ? localize('ReinstallAction.successReload', "Please reload Visual Studio Code to complete reinstalling the extension {0}.", extension.identifier.id)
							: localize('ReinstallAction.success', "Reinstalling the extension {0} is completed.", extension.identifier.id);
						const actions = requireReload ? [{
							label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
							run: () => this.windowService.reloadWindow()
						}] : [];
2922 2923
						this.notificationService.prompt(
							Severity.Info,
S
Sandeep Somavarapu 已提交
2924 2925
							message,
							actions,
2926 2927 2928 2929
							{ sticky: true }
						);
					}, error => this.notificationService.error(error));
			});
J
Joao Moreno 已提交
2930 2931 2932
	}
}

S
Sandeep Somavarapu 已提交
2933
export class InstallSpecificVersionOfExtensionAction extends Action {
2934

S
Sandeep Somavarapu 已提交
2935 2936
	static readonly ID = 'workbench.extensions.action.install.specificVersion';
	static LABEL = localize('install previous version', "Install Specific Version of Extension...");
2937 2938

	constructor(
S
Sandeep Somavarapu 已提交
2939
		id: string = InstallSpecificVersionOfExtensionAction.ID, label: string = InstallSpecificVersionOfExtensionAction.LABEL,
2940 2941 2942 2943 2944
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
		@IWindowService private readonly windowService: IWindowService,
S
Sandeep Somavarapu 已提交
2945
		@IInstantiationService private readonly instantiationService: IInstantiationService,
2946 2947
		@IExtensionService private readonly extensionService: IExtensionService,
		@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
2948 2949 2950 2951 2952
	) {
		super(id, label);
	}

	get enabled(): boolean {
S
Sandeep Somavarapu 已提交
2953
		return this.extensionsWorkbenchService.local.some(l => this.isEnabled(l));
2954 2955
	}

S
Sandeep Somavarapu 已提交
2956 2957 2958
	async run(): Promise<any> {
		const extensionPick = await this.quickInputService.pick(this.getExtensionEntries(), { placeHolder: localize('selectExtension', "Select Extension"), matchOnDetail: true });
		if (extensionPick && extensionPick.extension) {
2959
			const versionPick = await this.quickInputService.pick(extensionPick.versions.map(v => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === extensionPick.extension.version ? ` (${localize('current', "Current")})` : ''}` })), { placeHolder: localize('selectVersion', "Select Version to Install"), matchOnDetail: true });
S
Sandeep Somavarapu 已提交
2960 2961
			if (versionPick) {
				if (extensionPick.extension.version !== versionPick.id) {
2962
					await this.install(extensionPick.extension, versionPick.id);
S
Sandeep Somavarapu 已提交
2963 2964
				}
			}
S
Sandeep Somavarapu 已提交
2965 2966 2967 2968
		}
	}

	private isEnabled(extension: IExtension): boolean {
2969
		return !!extension.gallery && !!extension.local && this.extensionEnablementService.isEnabled(extension.local);
2970 2971
	}

S
Sandeep Somavarapu 已提交
2972
	private async getExtensionEntries(): Promise<(IQuickPickItem & { extension: IExtension, versions: IGalleryExtensionVersion[] })[]> {
2973
		const installed = await this.extensionsWorkbenchService.queryLocal();
2974
		const versionsPromises: Promise<{ extension: IExtension, versions: IGalleryExtensionVersion[] } | null>[] = [];
2975
		for (const extension of installed) {
S
Sandeep Somavarapu 已提交
2976
			if (this.isEnabled(extension)) {
2977
				versionsPromises.push(this.extensionGalleryService.getAllVersions(extension.gallery!, true)
S
Sandeep Somavarapu 已提交
2978
					.then(versions => (versions.length ? { extension, versions } : null)));
2979 2980 2981
			}
		}

S
Sandeep Somavarapu 已提交
2982
		const extensions = await Promise.all(versionsPromises);
M
Matt Bierner 已提交
2983
		return coalesce(extensions)
2984
			.sort((e1, e2) => e1.extension.displayName.localeCompare(e2.extension.displayName))
S
Sandeep Somavarapu 已提交
2985
			.map(({ extension, versions }) => {
2986
				return {
S
Sandeep Somavarapu 已提交
2987 2988 2989
					id: extension.identifier.id,
					label: extension.displayName || extension.identifier.id,
					description: extension.identifier.id,
2990
					extension,
S
Sandeep Somavarapu 已提交
2991 2992
					versions
				} as (IQuickPickItem & { extension: IExtension, versions: IGalleryExtensionVersion[] });
2993 2994 2995
			});
	}

J
Johannes Rieken 已提交
2996
	private install(extension: IExtension, version: string): Promise<void> {
S
Sandeep Somavarapu 已提交
2997 2998
		return this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL).run()
			.then(() => {
2999
				return this.extensionsWorkbenchService.installVersion(extension, version)
S
Sandeep Somavarapu 已提交
3000 3001 3002 3003 3004 3005 3006 3007
					.then(extension => {
						const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
						const message = requireReload ? localize('InstallAnotherVersionExtensionAction.successReload', "Please reload Visual Studio Code to complete installing the extension {0}.", extension.identifier.id)
							: localize('InstallAnotherVersionExtensionAction.success', "Installing the extension {0} is completed.", extension.identifier.id);
						const actions = requireReload ? [{
							label: localize('InstallAnotherVersionExtensionAction.reloadNow', "Reload Now"),
							run: () => this.windowService.reloadWindow()
						}] : [];
3008 3009
						this.notificationService.prompt(
							Severity.Info,
S
Sandeep Somavarapu 已提交
3010 3011
							message,
							actions,
3012 3013 3014 3015
							{ sticky: true }
						);
					}, error => this.notificationService.error(error));
			});
J
Joao Moreno 已提交
3016 3017 3018
	}
}

3019 3020 3021 3022
interface IExtensionPickItem extends IQuickPickItem {
	extension?: IExtension;
}

3023
export class InstallLocalExtensionsInRemoteAction extends Action {
3024 3025 3026 3027 3028 3029 3030 3031

	constructor(
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
		@IWindowService private readonly windowService: IWindowService,
3032 3033
		@IProgressService private readonly progressService: IProgressService,
		@IInstantiationService private readonly instantiationService: IInstantiationService
3034
	) {
3035
		super('workbench.extensions.actions.installLocalExtensionsInRemote');
3036 3037 3038 3039 3040 3041
		this.update();
		this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
	}

	get label(): string {
		return this.extensionManagementServerService.remoteExtensionManagementServer ?
3042
			localize('install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label) : '';
3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054
	}

	private update(): void {
		this.enabled = this.getLocalExtensionsToInstall().length > 0;
	}

	private getLocalExtensionsToInstall(): IExtension[] {
		return this.extensionsWorkbenchService.local.filter(extension => {
			const action = this.instantiationService.createInstance(RemoteInstallAction);
			action.extension = extension;
			return action.enabled;
		});
3055 3056 3057
	}

	async run(): Promise<void> {
3058 3059
		this.selectAndInstallLocalExtensions();
		return Promise.resolve();
3060 3061
	}

3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074
	private selectAndInstallLocalExtensions(): void {
		const quickPick = this.quickInputService.createQuickPick<IExtensionPickItem>();
		quickPick.busy = true;
		const disposable = quickPick.onDidAccept(() => {
			disposable.dispose();
			quickPick.hide();
			quickPick.dispose();
			this.onDidAccept(quickPick.selectedItems);
		});
		quickPick.show();
		const localExtensionsToInstall = this.getLocalExtensionsToInstall();
		quickPick.busy = false;
		if (localExtensionsToInstall.length) {
3075
			quickPick.title = localize('install local extensions title', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer!.label);
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086
			quickPick.placeholder = localize('select extensions to install', "Select extensions to install");
			quickPick.canSelectMany = true;
			localExtensionsToInstall.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName));
			quickPick.items = localExtensionsToInstall.map<IExtensionPickItem>(extension => ({ extension, label: extension.displayName, description: extension.version }));
		} else {
			quickPick.hide();
			quickPick.dispose();
			this.notificationService.notify({
				severity: Severity.Info,
				message: localize('no local extensions', "There are no extensions to install.")
			});
3087 3088 3089
		}
	}

3090 3091 3092
	private onDidAccept(selectedItems: ReadonlyArray<IExtensionPickItem>): void {
		if (selectedItems.length) {
			const localExtensionsToInstall = selectedItems.filter(r => !!r.extension).map(r => r.extension!);
3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132
			if (localExtensionsToInstall.length) {
				this.progressService.withProgress(
					{
						location: ProgressLocation.Notification,
						title: localize('installing extensions', "Installing Extensions...")
					},
					() => this.installLocalExtensions(localExtensionsToInstall));
			}
		}
	}

	private async installLocalExtensions(localExtensionsToInstall: IExtension[]): Promise<void> {
		const galleryExtensions: IGalleryExtension[] = [];
		const vsixs: URI[] = [];
		await Promise.all(localExtensionsToInstall.map(async extension => {
			if (this.extensionGalleryService.isEnabled()) {
				const gallery = await this.extensionGalleryService.getCompatibleExtension(extension.identifier, extension.version);
				if (gallery) {
					galleryExtensions.push(gallery);
					return;
				}
			}
			const vsix = await this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.zip(extension.local!);
			vsixs.push(vsix);
		}));

		await Promise.all(galleryExtensions.map(gallery => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.installFromGallery(gallery)));
		await Promise.all(vsixs.map(vsix => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.install(vsix)));

		this.notificationService.notify({
			severity: Severity.Info,
			message: localize('finished installing', "Completed installing the extensions. Please reload the window now."),
			actions: {
				primary: [new Action('realod', localize('reload', "Realod Window"), '', true,
					() => this.windowService.reloadWindow())]
			}
		});
	}
}

S
Sandeep Somavarapu 已提交
3133
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForLanguage', function (accessor: ServicesAccessor, fileExtension: string) {
3134 3135 3136 3137 3138 3139 3140 3141 3142
	const viewletService = accessor.get(IViewletService);

	return viewletService.openViewlet(VIEWLET_ID, true)
		.then(viewlet => viewlet as IExtensionsViewlet)
		.then(viewlet => {
			viewlet.search(`ext:${fileExtension.replace(/^\./, '')}`);
			viewlet.focus();
		});
});
B
Benjamin Pasero 已提交
3143

3144
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsWithIds', function (accessor: ServicesAccessor, extensionIds: string[]) {
3145 3146 3147 3148 3149
	const viewletService = accessor.get(IViewletService);

	return viewletService.openViewlet(VIEWLET_ID, true)
		.then(viewlet => viewlet as IExtensionsViewlet)
		.then(viewlet => {
3150 3151 3152 3153
			const query = extensionIds
				.map(id => `@id:${id}`)
				.join(' ');
			viewlet.search(query);
3154 3155 3156 3157
			viewlet.focus();
		});
});

B
Benjamin Pasero 已提交
3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176
export const extensionButtonProminentBackground = registerColor('extensionButton.prominentBackground', {
	dark: '#327e36',
	light: '#327e36',
	hc: null
}, localize('extensionButtonProminentBackground', "Button background color for actions extension that stand out (e.g. install button)."));

export const extensionButtonProminentForeground = registerColor('extensionButton.prominentForeground', {
	dark: Color.white,
	light: Color.white,
	hc: null
}, localize('extensionButtonProminentForeground', "Button foreground color for actions extension that stand out (e.g. install button)."));

export const extensionButtonProminentHoverBackground = registerColor('extensionButton.prominentHoverBackground', {
	dark: '#28632b',
	light: '#28632b',
	hc: null
}, localize('extensionButtonProminentHoverBackground', "Button background hover color for actions extension that stand out (e.g. install button)."));

registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
B
Benjamin Pasero 已提交
3177 3178
	const foregroundColor = theme.getColor(foreground);
	if (foregroundColor) {
3179 3180
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action.built-in-status { border-color: ${foregroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.built-in-status { border-color: ${foregroundColor}; }`);
B
Benjamin Pasero 已提交
3181 3182
	}

B
Benjamin Pasero 已提交
3183 3184
	const buttonBackgroundColor = theme.getColor(buttonBackground);
	if (buttonBackgroundColor) {
3185 3186
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action { background-color: ${buttonBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action { background-color: ${buttonBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3187 3188 3189 3190
	}

	const buttonForegroundColor = theme.getColor(buttonForeground);
	if (buttonForegroundColor) {
3191 3192
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action { color: ${buttonForegroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action { color: ${buttonForegroundColor}; }`);
B
Benjamin Pasero 已提交
3193 3194 3195 3196
	}

	const buttonHoverBackgroundColor = theme.getColor(buttonHoverBackground);
	if (buttonHoverBackgroundColor) {
3197 3198
		collector.addRule(`.extension .monaco-action-bar .action-item:hover .action-label.extension-action { background-color: ${buttonHoverBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item:hover .action-label.extension-action { background-color: ${buttonHoverBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3199 3200 3201 3202
	}

	const contrastBorderColor = theme.getColor(contrastBorder);
	if (contrastBorderColor) {
3203 3204
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action { border: 1px solid ${contrastBorderColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action { border: 1px solid ${contrastBorderColor}; }`);
B
Benjamin Pasero 已提交
3205 3206 3207 3208
	}

	const extensionButtonProminentBackgroundColor = theme.getColor(extensionButtonProminentBackground);
	if (extensionButtonProminentBackground) {
3209 3210
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action.prominent { background-color: ${extensionButtonProminentBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.prominent { background-color: ${extensionButtonProminentBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3211 3212 3213 3214
	}

	const extensionButtonProminentForegroundColor = theme.getColor(extensionButtonProminentForeground);
	if (extensionButtonProminentForeground) {
3215 3216
		collector.addRule(`.extension .monaco-action-bar .action-item .action-label.extension-action.prominent { color: ${extensionButtonProminentForegroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.prominent { color: ${extensionButtonProminentForegroundColor}; }`);
B
Benjamin Pasero 已提交
3217 3218 3219 3220
	}

	const extensionButtonProminentHoverBackgroundColor = theme.getColor(extensionButtonProminentHoverBackground);
	if (extensionButtonProminentHoverBackground) {
3221 3222
		collector.addRule(`.extension .monaco-action-bar .action-item:hover .action-label.extension-action.prominent { background-color: ${extensionButtonProminentHoverBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item:hover .action-label.extension-action.prominent { background-color: ${extensionButtonProminentHoverBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3223
	}
A
Alex Dima 已提交
3224
});