extensionsActions.ts 136.5 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
import { localize } from 'vs/nls';
8
import { IAction, Action, Separator, SubmenuAction } 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 { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
S
Sandeep Somavarapu 已提交
14
import { dispose } from 'vs/base/common/lifecycle';
15
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, AutoUpdateConfigurationKey, IExtensionContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions';
16
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
S
Sandeep Somavarapu 已提交
17
import { IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, INSTALL_ERROR_NOT_SUPPORTED, InstallOptions, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
18
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
S
Sandeep Somavarapu 已提交
19
import { ExtensionRecommendationReason, IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
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';
28
import { IHostService } from 'vs/workbench/services/host/browser/host';
29
import { IExtensionService, toExtension, toExtensionDescription } 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';
32
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
M
Martin Aeschlimann 已提交
33
import { registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
34
import { buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, registerColor, foreground } from 'vs/platform/theme/common/colorRegistry';
35 36 37
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';
S
Sandeep Somavarapu 已提交
38 39
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
I
isidor 已提交
40
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
S
Sandeep Somavarapu 已提交
41
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
J
Joao Moreno 已提交
42 43
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
44
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
45
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
46
import { IQuickPickItem, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
47
import { CancellationToken } from 'vs/base/common/cancellation';
48
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
49
import { alert } from 'vs/base/browser/ui/aria/aria';
M
Matt Bierner 已提交
50
import { coalesce } from 'vs/base/common/arrays';
51
import { IWorkbenchThemeService, IWorkbenchTheme, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IWorkbenchProductIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
52
import { ILabelService } from 'vs/platform/label/common/label';
53
import { prefersExecuteOnUI, prefersExecuteOnWorkspace, canExecuteOnUI, canExecuteOnWorkspace, prefersExecuteOnWeb } from 'vs/workbench/services/extensions/common/extensionsUtil';
54
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
55
import { IProductService } from 'vs/platform/product/common/productService';
S
Sandeep Somavarapu 已提交
56
import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs';
57
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
58
import { Codicon } from 'vs/base/common/codicons';
S
Sandeep Somavarapu 已提交
59
import { IViewsService } from 'vs/workbench/common/views';
60
import { IActionViewItemOptions, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
S
Sandeep Somavarapu 已提交
61
import { EXTENSIONS_CONFIG, IExtensionsConfigContent } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
S
Sandeep Somavarapu 已提交
62
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
63 64 65
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { ActionWithDropdownActionViewItem, IActionWithDropdownActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
S
Sandeep Somavarapu 已提交
66 67
import { ILogService } from 'vs/platform/log/common/log';
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
68

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
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 已提交
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
class PromptExtensionInstallFailureAction extends Action {

	constructor(
		private readonly extension: IExtension,
		private readonly installOperation: InstallOperation,
		private readonly error: Error,
		@IProductService private readonly productService: IProductService,
		@IOpenerService private readonly openerService: IOpenerService,
		@INotificationService private readonly notificationService: INotificationService,
		@IDialogService private readonly dialogService: IDialogService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@ILogService private readonly logService: ILogService,
	) {
		super('extension.promptExtensionInstallFailure');
	}

	async run(): Promise<void> {
		if (isPromiseCanceledError(this.error)) {
			return;
		}

		this.logService.error(this.error);
		const operationMessage = this.installOperation === InstallOperation.Update ? localize('update operation', "Error while updating '{0}' extension.", this.extension.displayName || this.extension.identifier.id)
			: localize('install operation', "Error while installing '{0}' extension.", this.extension.displayName || this.extension.identifier.id);

		if ([INSTALL_ERROR_INCOMPATIBLE, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_NOT_SUPPORTED].includes(this.error.name)) {
			await this.dialogService.show(Severity.Error, `${operationMessage}\n${getErrorMessage(this.error)}`, []);
			return;
		}

		const promptChoices: IPromptChoice[] = [];
		if (this.extension.gallery && this.productService.extensionsGallery) {
			promptChoices.push({
				label: localize('download', "Try Downloading Manually..."),
				run: () => this.openerService.open(URI.parse(`${this.productService.extensionsGallery!.serviceUrl}/publishers/${this.extension.publisher}/vsextensions/${this.extension.name}/${this.extension.version}/vspackage`)).then(() => {
					this.notificationService.prompt(
						Severity.Info,
						localize('install vsix', 'Once downloaded, please manually install the downloaded VSIX of \'{0}\'.', this.extension.identifier.id),
						[{
							label: InstallVSIXAction.LABEL,
							run: () => {
								const action = this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL);
								action.run();
								action.dispose();
							}
						}]
					);
				})
			});
		}
		const checkLogsMessage = localize('check logs', "Please check [logs]({0}) for more details.", `command:${Constants.showWindowLogActionId}`);
		this.notificationService.prompt(Severity.Error, `${operationMessage} ${checkLogsMessage}`, promptChoices);
	}
}

S
Sandeep Somavarapu 已提交
158
export abstract class ExtensionAction extends Action implements IExtensionContainer {
S
Sandeep Somavarapu 已提交
159 160 161 162
	static readonly EXTENSION_ACTION_CLASS = 'extension-action';
	static readonly TEXT_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} text`;
	static readonly LABEL_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} label`;
	static readonly ICON_ACTION_CLASS = `${ExtensionAction.EXTENSION_ACTION_CLASS} icon`;
S
Sandeep Somavarapu 已提交
163 164 165
	private _extension: IExtension | null = null;
	get extension(): IExtension | null { return this._extension; }
	set extension(extension: IExtension | null) { this._extension = extension; this.update(); }
S
Sandeep Somavarapu 已提交
166
	abstract update(): void;
167
}
168

S
Sandeep Somavarapu 已提交
169
export class ActionWithDropDownAction extends ExtensionAction {
170

171
	private action: IAction | undefined;
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	private _menuActions: IAction[] = [];
	get menuActions(): IAction[] { return [...this._menuActions]; }

	set extension(extension: IExtension | null) {
		this.actions.forEach(a => a.extension = extension);
		super.extension = extension;
	}

	constructor(
		id: string, label: string,
		protected readonly actions: ExtensionAction[],
	) {
		super(id, label);
		this.update();
		this._register(Event.any(...actions.map(a => a.onDidChange))(() => this.update(true)));
J
João Moreno 已提交
188
		actions.forEach(a => this._register(a));
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	}

	update(donotUpdateActions?: boolean): void {
		if (!donotUpdateActions) {
			this.actions.forEach(a => a.update());
		}

		const enabledActions = this.actions.filter(a => a.enabled);
		this.action = enabledActions[0];
		this._menuActions = enabledActions.slice(1);

		this.enabled = !!this.action;
		if (this.action) {
			this.label = this.action.label;
			this.tooltip = this.action.tooltip;
		}

		let clazz = (this.action || this.actions[0])?.class || '';
		clazz = clazz ? `${clazz} action-dropdown` : 'action-dropdown';
		if (this._menuActions.length === 0) {
			clazz += ' action-dropdown';
		}
		this.class = clazz;
	}
213

214 215 216 217 218 219 220 221 222 223 224
	run(): Promise<void> {
		const enabledActions = this.actions.filter(a => a.enabled);
		return enabledActions[0].run();
	}
}

export abstract class AbstractInstallAction extends ExtensionAction {

	static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`;

	protected _manifest: IExtensionManifest | null = null;
225 226 227 228 229
	set manifest(manifest: IExtensionManifest) {
		this._manifest = manifest;
		this.updateLabel();
	}

230
	constructor(
231
		id: string, label: string, cssClass: string,
232 233
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
S
Sandeep Somavarapu 已提交
234
		@IExtensionService private readonly runtimeExtensionService: IExtensionService,
235
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
236
		@ILabelService private readonly labelService: ILabelService,
237
	) {
238
		super(id, label, cssClass, false);
239
		this.update();
M
Matt Bierner 已提交
240
		this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
241 242
	}

S
Sandeep Somavarapu 已提交
243
	update(): void {
S
Sandeep Somavarapu 已提交
244
		this.enabled = false;
245
		if (this.extension && !this.extension.isBuiltin) {
S
Sandeep Somavarapu 已提交
246 247 248
			if (this.extension.state === ExtensionState.Uninstalled && this.extensionsWorkbenchService.canInstall(this.extension)) {
				this.enabled = true;
				this.updateLabel();
249
			}
250 251 252
		}
	}

S
Sandeep Somavarapu 已提交
253
	async run(): Promise<any> {
S
Sandeep Somavarapu 已提交
254 255 256
		if (!this.extension) {
			return;
		}
257
		this.extensionsWorkbenchService.open(this.extension);
J
Joao Moreno 已提交
258

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

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

S
Sandeep Somavarapu 已提交
263 264
		if (extension?.local) {
			alert(localize('installExtensionComplete', "Installing extension {0} is completed.", this.extension.displayName));
S
Sandeep Somavarapu 已提交
265
			const runningExtension = await this.getRunningExtension(extension.local);
S
Sandeep Somavarapu 已提交
266
			if (runningExtension && !(runningExtension.activationEvents && runningExtension.activationEvents.some(activationEent => activationEent.startsWith('onLanguage')))) {
267 268 269 270 271 272 273 274 275
				let action = await SetColorThemeAction.create(this.workbenchThemeService, this.instantiationService, extension)
					|| await SetFileIconThemeAction.create(this.workbenchThemeService, this.instantiationService, extension)
					|| await SetProductIconThemeAction.create(this.workbenchThemeService, this.instantiationService, extension);
				if (action) {
					try {
						return action.run({ showCurrentTheme: true, ignoreFocusLost: true });
					} finally {
						action.dispose();
					}
S
Sandeep Somavarapu 已提交
276 277
				}
			}
S
Sandeep Somavarapu 已提交
278 279
		}

J
Joao Moreno 已提交
280 281
	}

S
Sandeep Somavarapu 已提交
282 283 284 285 286 287 288
	private async install(extension: IExtension): Promise<IExtension | undefined> {
		try {
			return await this.extensionsWorkbenchService.install(extension, this.getInstallOptions());
		} catch (error) {
			await this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, InstallOperation.Install, error).run();
			return undefined;
		}
S
Sandeep Somavarapu 已提交
289
	}
J
Joao Moreno 已提交
290

S
Sandeep Somavarapu 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
	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;
308
	}
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

	protected abstract updateLabel(): void;
	protected abstract getInstallOptions(): InstallOptions;
}

export class InstallAction extends AbstractInstallAction {

	constructor(
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService instantiationService: IInstantiationService,
		@IExtensionService runtimeExtensionService: IExtensionService,
		@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
		@ILabelService labelService: ILabelService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IProductService private readonly productService: IProductService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IUserDataAutoSyncEnablementService protected readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService,
		@IUserDataSyncResourceEnablementService protected readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
	) {
		super(`extensions.installAndSync`, localize('install', "Install"), InstallAction.Class,
S
Sandeep Somavarapu 已提交
329
			extensionsWorkbenchService, instantiationService, runtimeExtensionService, workbenchThemeService, labelService);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
		this.updateLabel();
		this._register(labelService.onDidChangeFormatters(() => this.updateLabel(), this));
		this._register(Event.any(userDataAutoSyncEnablementService.onDidChangeEnablement,
			Event.filter(userDataSyncResourceEnablementService.onDidChangeResourceEnablement, e => e[0] === SyncResource.Extensions))(() => this.update()));
	}

	protected updateLabel(): void {
		if (!this.extension) {
			return;
		}

		const isMachineScoped = this.getInstallOptions().isMachineScoped;
		this.label = isMachineScoped ? localize('install and do no sync', "Install (Do not sync)") : localize('install', "Install");

		// When remote connection exists
		if (this._manifest && this.extensionManagementServerService.remoteExtensionManagementServer) {

			// On Desktop and UI Extension
			if (this.extensionManagementServerService.localExtensionManagementServer && prefersExecuteOnUI(this._manifest, this.productService, this.configurationService)) {
				this.label = isMachineScoped ? localize('install locally and do not sync', "Install Locally (Do not sync)") : localize('install locally', "Install Locally");
				return;
			}

			// On Web and Web Extension
			if (this.extensionManagementServerService.webExtensionManagementServer && prefersExecuteOnWeb(this._manifest, this.productService, this.configurationService)) {
				this.label = isMachineScoped ? localize('install locally and do not sync', "Install Locally (Do not sync)") : localize('install locally', "Install Locally");
				return;
			}

			const host = this.extensionManagementServerService.remoteExtensionManagementServer.label;
			this.label = isMachineScoped ? localize('install on remote and do not sync', "Install on {0} (Do not sync)", host) : localize('install on remote', "Install on {0}", host);
			return;
		}
	}

	protected getInstallOptions(): InstallOptions {
		return { isMachineScoped: this.userDataAutoSyncEnablementService.isEnabled() && this.userDataSyncResourceEnablementService.isResourceEnabled(SyncResource.Extensions) };
	}

}

export class InstallAndSyncAction extends AbstractInstallAction {

	constructor(
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService instantiationService: IInstantiationService,
		@IExtensionService runtimeExtensionService: IExtensionService,
		@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
		@ILabelService labelService: ILabelService,
		@IProductService productService: IProductService,
		@IUserDataAutoSyncEnablementService private readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService,
		@IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
	) {
		super(`extensions.installAndSync`, localize('install', "Install"), InstallAndSyncAction.Class,
S
Sandeep Somavarapu 已提交
384
			extensionsWorkbenchService, instantiationService, runtimeExtensionService, workbenchThemeService, labelService);
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
		this.tooltip = localize('install everywhere tooltip', "Install this extension in all your synced {0} instances", productService.nameLong);
		this._register(Event.any(userDataAutoSyncEnablementService.onDidChangeEnablement,
			Event.filter(userDataSyncResourceEnablementService.onDidChangeResourceEnablement, e => e[0] === SyncResource.Extensions))(() => this.update()));
	}


	update(): void {
		super.update();
		if (this.enabled) {
			this.enabled = this.userDataAutoSyncEnablementService.isEnabled() && this.userDataSyncResourceEnablementService.isResourceEnabled(SyncResource.Extensions);
		}
	}

	protected updateLabel(): void { }

	protected getInstallOptions(): InstallOptions {
		return { isMachineScoped: false };
	}
}

export class InstallDropdownAction extends ActionWithDropDownAction {

	set manifest(manifest: IExtensionManifest) {
		this.actions.forEach(a => (<AbstractInstallAction>a).manifest = manifest);
		this.actions.forEach(a => a.update());
		this.update();
	}

	constructor(
		@IInstantiationService instantiationService: IInstantiationService,
	) {
		super(`extensions.installActions`, '', [
			instantiationService.createInstance(InstallAndSyncAction),
			instantiationService.createInstance(InstallAction),
		]);
	}

}

export class InstallingLabelAction extends ExtensionAction {

	private static readonly LABEL = localize('installing', "Installing");
	private static readonly CLASS = `${ExtensionAction.LABEL_ACTION_CLASS} install installing`;

	constructor() {
		super('extension.installing', InstallingLabelAction.LABEL, InstallingLabelAction.CLASS, false);
	}

	update(): void {
		this.class = `${InstallingLabelAction.CLASS}${this.extension && this.extension.state === ExtensionState.Installing ? '' : ' hide'}`;
	}
436 437
}

S
Sandeep Somavarapu 已提交
438
export abstract class InstallInOtherServerAction extends ExtensionAction {
439

440 441
	protected static readonly INSTALL_LABEL = localize('install', "Install");
	protected static readonly INSTALLING_LABEL = localize('installing', "Installing");
442

S
Sandeep Somavarapu 已提交
443 444
	private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`;
	private static readonly InstallingClass = `${ExtensionAction.LABEL_ACTION_CLASS} install installing`;
445

446
	updateWhenCounterExtensionChanges: boolean = true;
447 448

	constructor(
S
Sandeep Somavarapu 已提交
449 450
		id: string,
		private readonly server: IExtensionManagementServer | null,
S
Sandeep Somavarapu 已提交
451
		private readonly canInstallAnyWhere: boolean,
452
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
453 454 455
		@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
		@IProductService private readonly productService: IProductService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
456
	) {
S
Sandeep Somavarapu 已提交
457
		super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false);
458 459 460
		this.update();
	}

461
	update(): void {
462
		this.enabled = false;
S
Sandeep Somavarapu 已提交
463 464
		this.class = InstallInOtherServerAction.Class;

S
Sandeep Somavarapu 已提交
465
		if (this.canInstall()) {
S
Sandeep Somavarapu 已提交
466
			const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === this.server)[0];
S
Sandeep Somavarapu 已提交
467 468 469 470 471 472 473 474 475 476 477 478
			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();
			}
479 480 481
		}
	}

S
Sandeep Somavarapu 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
	private canInstall(): boolean {
		// Disable if extension is not installed or not an user extension
		if (
			!this.extension
			|| !this.server
			|| !this.extension.local
			|| this.extension.state !== ExtensionState.Installed
			|| this.extension.type !== ExtensionType.User
			|| this.extension.enablementState === EnablementState.DisabledByEnvironemt
		) {
			return false;
		}

		if (isLanguagePackExtension(this.extension.local.manifest)) {
			return true;
		}

		// Prefers to run on UI
		if (this.server === this.extensionManagementServerService.localExtensionManagementServer && prefersExecuteOnUI(this.extension.local.manifest, this.productService, this.configurationService)) {
			return true;
		}

		// Prefers to run on Workspace
		if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && prefersExecuteOnWorkspace(this.extension.local.manifest, this.productService, this.configurationService)) {
			return true;
		}

		if (this.canInstallAnyWhere) {
			// Can run on UI
			if (this.server === this.extensionManagementServerService.localExtensionManagementServer && canExecuteOnUI(this.extension.local.manifest, this.productService, this.configurationService)) {
				return true;
			}

			// Can run on Workspace
			if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && canExecuteOnWorkspace(this.extension.local.manifest, this.productService, this.configurationService)) {
				return true;
			}
		}

		return false;
	}

524
	async run(): Promise<void> {
S
Sandeep Somavarapu 已提交
525 526 527
		if (!this.extension) {
			return;
		}
S
Sandeep Somavarapu 已提交
528
		if (this.server) {
529 530
			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 已提交
531 532 533 534 535
			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);
536 537 538
			}
		}
	}
S
Sandeep Somavarapu 已提交
539 540

	protected abstract getInstallLabel(): string;
541 542
}

S
Sandeep Somavarapu 已提交
543
export class RemoteInstallAction extends InstallInOtherServerAction {
544

S
Sandeep Somavarapu 已提交
545
	constructor(
S
Sandeep Somavarapu 已提交
546
		canInstallAnyWhere: boolean,
S
Sandeep Somavarapu 已提交
547
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
548 549 550
		@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
		@IProductService productService: IProductService,
		@IConfigurationService configurationService: IConfigurationService,
S
Sandeep Somavarapu 已提交
551
	) {
S
Sandeep Somavarapu 已提交
552
		super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, canInstallAnyWhere, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService);
S
Sandeep Somavarapu 已提交
553
	}
554

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

S
Sandeep Somavarapu 已提交
559
}
560

S
Sandeep Somavarapu 已提交
561
export class LocalInstallAction extends InstallInOtherServerAction {
562 563

	constructor(
S
Sandeep Somavarapu 已提交
564
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
565 566 567
		@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
		@IProductService productService: IProductService,
		@IConfigurationService configurationService: IConfigurationService,
568
	) {
S
Sandeep Somavarapu 已提交
569
		super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService);
570 571
	}

S
Sandeep Somavarapu 已提交
572 573
	protected getInstallLabel(): string {
		return localize('install locally', "Install Locally");
574 575 576 577
	}

}

S
Sandeep Somavarapu 已提交
578
export class UninstallAction extends ExtensionAction {
579

S
Sandeep Somavarapu 已提交
580
	static readonly UninstallLabel = localize('uninstallAction', "Uninstall");
581
	private static readonly UninstallingLabel = localize('Uninstalling', "Uninstalling");
582

S
Sandeep Somavarapu 已提交
583 584
	private static readonly UninstallClass = `${ExtensionAction.LABEL_ACTION_CLASS} uninstall`;
	private static readonly UnInstallingClass = `${ExtensionAction.LABEL_ACTION_CLASS} uninstall uninstalling`;
S
Sandeep Somavarapu 已提交
585

586
	constructor(
S
Sandeep Somavarapu 已提交
587
		@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
588
	) {
S
Sandeep Somavarapu 已提交
589
		super('extensions.uninstall', UninstallAction.UninstallLabel, UninstallAction.UninstallClass, false);
590 591 592
		this.update();
	}

S
Sandeep Somavarapu 已提交
593
	update(): void {
594 595 596 597 598 599 600 601 602
		if (!this.extension) {
			this.enabled = false;
			return;
		}

		const state = this.extension.state;

		if (state === ExtensionState.Uninstalling) {
			this.label = UninstallAction.UninstallingLabel;
S
Sandeep Somavarapu 已提交
603
			this.class = UninstallAction.UnInstallingClass;
604 605 606 607 608
			this.enabled = false;
			return;
		}

		this.label = UninstallAction.UninstallLabel;
S
Sandeep Somavarapu 已提交
609
		this.class = UninstallAction.UninstallClass;
S
Sandeep Somavarapu 已提交
610
		this.tooltip = UninstallAction.UninstallLabel;
611

S
Sandeep Somavarapu 已提交
612 613 614 615 616
		if (state !== ExtensionState.Installed) {
			this.enabled = false;
			return;
		}

617
		if (this.extension.isBuiltin) {
618 619 620 621 622 623 624
			this.enabled = false;
			return;
		}

		this.enabled = true;
	}

S
Sandeep Somavarapu 已提交
625 626 627 628
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
629 630 631
		alert(localize('uninstallExtensionStart', "Uninstalling extension {0} started.", this.extension.displayName));

		return this.extensionsWorkbenchService.uninstall(this.extension).then(() => {
S
Sandeep Somavarapu 已提交
632
			alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension!.displayName));
633
		});
634 635 636
	}
}

S
Sandeep Somavarapu 已提交
637
export class UpdateAction extends ExtensionAction {
638

S
Sandeep Somavarapu 已提交
639
	private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} prominent update`;
640
	private static readonly DisabledClass = `${UpdateAction.EnabledClass} disabled`;
641 642

	constructor(
643 644
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
645
	) {
646
		super(`extensions.update`, '', UpdateAction.DisabledClass, false);
647 648 649
		this.update();
	}

S
Sandeep Somavarapu 已提交
650
	update(): void {
651 652 653
		if (!this.extension) {
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
654
			this.label = this.getUpdateLabel();
655 656 657
			return;
		}

658
		if (this.extension.type !== ExtensionType.User) {
659 660
			this.enabled = false;
			this.class = UpdateAction.DisabledClass;
661
			this.label = this.getUpdateLabel();
662 663 664 665 666 667 668 669
			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;
670
		this.label = this.extension.outdated ? this.getUpdateLabel(this.extension.latestVersion) : this.getUpdateLabel();
671 672
	}

S
Sandeep Somavarapu 已提交
673 674 675 676
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
677
		alert(localize('updateExtensionStart', "Updating extension {0} to version {1} started.", this.extension.displayName, this.extension.latestVersion));
J
Joao Moreno 已提交
678 679 680
		return this.install(this.extension);
	}

S
Sandeep Somavarapu 已提交
681 682 683
	private async install(extension: IExtension): Promise<void> {
		try {
			await this.extensionsWorkbenchService.install(extension);
S
Sandeep Somavarapu 已提交
684
			alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", extension.displayName, extension.latestVersion));
S
Sandeep Somavarapu 已提交
685 686 687
		} catch (err) {
			this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, InstallOperation.Update, err).run();
		}
688 689
	}

690
	private getUpdateLabel(version?: string): string {
691
		return version ? localize('updateTo', "Update to {0}", version) : localize('updateAction', "Update");
692
	}
693 694
}

695
export interface IExtensionActionViewItemOptions extends IActionViewItemOptions {
696 697 698
	tabOnlyOnFocus?: boolean;
}

699
export class ExtensionActionViewItem extends ActionViewItem {
700

701
	constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) {
702 703 704 705 706 707
		super(context, action, options);
	}

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

S
Sandeep Somavarapu 已提交
708
		if (this.label && (<IExtensionActionViewItemOptions>this.options).tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) {
709 710 711 712
			DOM.removeTabIndexAndUpdateFocus(this.label);
		}
	}

S
Sandeep Somavarapu 已提交
713
	private _hasFocus: boolean = false;
714
	setFocus(value: boolean): void {
S
Sandeep Somavarapu 已提交
715
		if (!(<IExtensionActionViewItemOptions>this.options).tabOnlyOnFocus || this._hasFocus === value) {
716 717 718
			return;
		}
		this._hasFocus = value;
719
		if (this.label && this.getAction().enabled) {
720 721 722 723 724 725 726 727 728
			if (this._hasFocus) {
				this.label.tabIndex = 0;
			} else {
				DOM.removeTabIndexAndUpdateFocus(this.label);
			}
		}
	}
}

729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
export class ExtensionActionWithDropdownActionViewItem extends ActionWithDropdownActionViewItem {

	constructor(
		action: ActionWithDropDownAction,
		options: IExtensionActionViewItemOptions & IActionWithDropdownActionViewItemOptions,
		contextMenuProvider: IContextMenuProvider
	) {
		super(null, action, options, contextMenuProvider);
	}

	render(container: HTMLElement): void {
		super.render(container);
		this.updateClass();
	}

	updateClass(): void {
		super.updateClass();
		if (this.dropdownMenuActionViewItem && this.dropdownMenuActionViewItem.element) {
			this.dropdownMenuActionViewItem.element.classList.toggle('hide', (<ActionWithDropDownAction>this._action).menuActions.length === 0);
		}
	}

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

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

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

}

S
Sandeep Somavarapu 已提交
776
export abstract class ExtensionDropDownAction extends ExtensionAction {
S
Explore  
Sandeep Somavarapu 已提交
777 778 779 780 781 782 783

	constructor(
		id: string,
		label: string,
		cssClass: string,
		enabled: boolean,
		private readonly tabOnlyOnFocus: boolean,
S
Sandeep Somavarapu 已提交
784
		@IInstantiationService protected instantiationService: IInstantiationService
S
Explore  
Sandeep Somavarapu 已提交
785 786 787 788
	) {
		super(id, label, cssClass, enabled);
	}

S
Sandeep Somavarapu 已提交
789
	private _actionViewItem: DropDownMenuActionViewItem | null = null;
790 791 792
	createActionViewItem(): DropDownMenuActionViewItem {
		this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus);
		return this._actionViewItem;
S
Explore  
Sandeep Somavarapu 已提交
793 794
	}

J
Johannes Rieken 已提交
795
	public run({ actionGroups, disposeActionsOnHide }: { actionGroups: IAction[][], disposeActionsOnHide: boolean }): Promise<any> {
796 797
		if (this._actionViewItem) {
			this._actionViewItem.showMenu(actionGroups, disposeActionsOnHide);
S
Explore  
Sandeep Somavarapu 已提交
798
		}
799
		return Promise.resolve();
S
Explore  
Sandeep Somavarapu 已提交
800 801 802
	}
}

803
export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
804

S
Sandeep Somavarapu 已提交
805
	constructor(action: ExtensionDropDownAction,
806
		tabOnlyOnFocus: boolean,
807
		@IContextMenuService private readonly contextMenuService: IContextMenuService
S
Sandeep Somavarapu 已提交
808
	) {
809
		super(null, action, { icon: true, label: true, tabOnlyOnFocus });
810 811
	}

S
Sandeep Somavarapu 已提交
812
	public showMenu(menuActionGroups: IAction[][], disposeActionsOnHide: boolean): void {
813 814 815 816 817 818 819 820 821 822 823
		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); } }
			});
		}
824 825
	}

S
Sandeep Somavarapu 已提交
826
	private getActions(menuActionGroups: IAction[][]): IAction[] {
B
Benjamin Pasero 已提交
827
		let actions: IAction[] = [];
S
Sandeep Somavarapu 已提交
828
		for (const menuActions of menuActionGroups) {
S
Sandeep Somavarapu 已提交
829
			actions = [...actions, ...menuActions, new Separator()];
830 831 832 833 834
		}
		return actions.length ? actions.slice(0, actions.length - 1) : actions;
	}
}

S
Sandeep Somavarapu 已提交
835
export function getContextMenuActions(extension: IExtension | undefined | null, inExtensionEditor: boolean, instantiationService: IInstantiationService): IAction[][] {
S
Sandeep Somavarapu 已提交
836 837 838 839 840 841 842 843 844 845 846 847
	return instantiationService.invokeFunction(accessor => {
		const scopedContextKeyService = accessor.get(IContextKeyService).createScoped();
		const menuService = accessor.get(IMenuService);
		const extensionRecommendationsService = accessor.get(IExtensionRecommendationsService);
		const extensionIgnoredRecommendationsService = accessor.get(IExtensionIgnoredRecommendationsService);
		if (extension) {
			scopedContextKeyService.createKey<string>('extension', extension.identifier.id);
			scopedContextKeyService.createKey<boolean>('isBuiltinExtension', extension.isBuiltin);
			scopedContextKeyService.createKey<boolean>('extensionHasConfiguration', extension.local && !!extension.local.manifest.contributes && !!extension.local.manifest.contributes.configuration);
			scopedContextKeyService.createKey<boolean>('isExtensionRecommended', !!extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]);
			scopedContextKeyService.createKey<boolean>('isExtensionWorkspaceRecommended', extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]?.reasonId === ExtensionRecommendationReason.Workspace);
			scopedContextKeyService.createKey<boolean>('isUserIgnoredRecommendation', extensionIgnoredRecommendationsService.globalIgnoredRecommendations.some(e => e === extension.identifier.id.toLowerCase()));
S
Sandeep Somavarapu 已提交
848
			scopedContextKeyService.createKey<boolean>('inExtensionEditor', inExtensionEditor);
S
Sandeep Somavarapu 已提交
849 850 851
			if (extension.state === ExtensionState.Installed) {
				scopedContextKeyService.createKey<string>('extensionStatus', 'installed');
			}
852 853
		}

S
Sandeep Somavarapu 已提交
854 855 856 857 858 859 860 861 862 863
		const groups: IAction[][] = [];
		const menu = menuService.createMenu(MenuId.ExtensionContext, scopedContextKeyService);
		menu.getActions({ shouldForwardArgs: true }).forEach(([, actions]) => groups.push(actions.map(action => {
			if (action instanceof SubmenuAction) {
				return action;
			}
			return instantiationService.createInstance(MenuItemExtensionAction, action);
		})));
		menu.dispose();
		scopedContextKeyService.dispose();
864

S
Sandeep Somavarapu 已提交
865 866
		return groups;
	});
S
Sandeep Somavarapu 已提交
867 868
}

S
Sandeep Somavarapu 已提交
869
export class ManageExtensionAction extends ExtensionDropDownAction {
870

871
	static readonly ID = 'extensions.manage';
S
Sandeep Somavarapu 已提交
872 873

	private static readonly Class = `${ExtensionAction.ICON_ACTION_CLASS} manage codicon-gear`;
874
	private static readonly HideManageExtensionClass = `${ManageExtensionAction.Class} hide`;
875 876

	constructor(
S
Sandeep Somavarapu 已提交
877
		@IInstantiationService instantiationService: IInstantiationService,
878
		@IExtensionService private readonly extensionService: IExtensionService,
879
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
880
	) {
S
Sandeep Somavarapu 已提交
881 882

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

S
Sandeep Somavarapu 已提交
884
		this.tooltip = localize('manage', "Manage");
885 886 887 888

		this.update();
	}

889
	async getActionGroups(runningExtensions: IExtensionDescription[]): Promise<IAction[][]> {
890
		const groups: IAction[][] = [];
891
		if (this.extension) {
892 893 894 895 896 897 898 899 900 901
			const actions = await Promise.all([
				SetColorThemeAction.create(this.workbenchThemeService, this.instantiationService, this.extension),
				SetFileIconThemeAction.create(this.workbenchThemeService, this.instantiationService, this.extension),
				SetProductIconThemeAction.create(this.workbenchThemeService, this.instantiationService, this.extension)
			]);

			const themesGroup: ExtensionAction[] = [];
			for (let action of actions) {
				if (action) {
					themesGroup.push(action);
902
				}
903 904
			}
			if (themesGroup.length) {
905 906 907
				groups.push(themesGroup);
			}
		}
S
Sandeep Somavarapu 已提交
908
		groups.push([
S
Sandeep Somavarapu 已提交
909
			this.instantiationService.createInstance(EnableGloballyAction),
910
			this.instantiationService.createInstance(EnableForWorkspaceAction)
S
Sandeep Somavarapu 已提交
911 912
		]);
		groups.push([
S
Sandeep Somavarapu 已提交
913 914
			this.instantiationService.createInstance(DisableGloballyAction, runningExtensions),
			this.instantiationService.createInstance(DisableForWorkspaceAction, runningExtensions)
S
Sandeep Somavarapu 已提交
915
		]);
916 917 918 919
		groups.push([
			this.instantiationService.createInstance(UninstallAction),
			this.instantiationService.createInstance(InstallAnotherVersionAction)
		]);
P
Peng Lyu 已提交
920

S
Sandeep Somavarapu 已提交
921
		getContextMenuActions(this.extension, false, this.instantiationService).forEach(actions => groups.push(actions));
P
Peng Lyu 已提交
922

923 924 925 926 927
		groups.forEach(group => group.forEach(extensionAction => {
			if (extensionAction instanceof ExtensionAction) {
				extensionAction.extension = this.extension;
			}
		}));
S
Sandeep Somavarapu 已提交
928 929 930 931

		return groups;
	}

932 933
	async run(): Promise<any> {
		const runtimeExtensions = await this.extensionService.getExtensions();
934
		return super.run({ actionGroups: await this.getActionGroups(runtimeExtensions), disposeActionsOnHide: true });
S
Sandeep Somavarapu 已提交
935 936
	}

S
Sandeep Somavarapu 已提交
937
	update(): void {
S
Sandeep Somavarapu 已提交
938
		this.class = ManageExtensionAction.HideManageExtensionClass;
939
		this.enabled = false;
S
Sandeep Somavarapu 已提交
940
		if (this.extension) {
941 942
			const state = this.extension.state;
			this.enabled = state === ExtensionState.Installed;
S
Sandeep Somavarapu 已提交
943
			this.class = this.enabled || state === ExtensionState.Uninstalling ? ManageExtensionAction.Class : ManageExtensionAction.HideManageExtensionClass;
944 945 946 947 948
			this.tooltip = state === ExtensionState.Uninstalling ? localize('ManageExtensionAction.uninstallingTooltip', "Uninstalling") : '';
		}
	}
}

S
Sandeep Somavarapu 已提交
949 950 951
export class ExtensionEditorManageExtensionAction extends ExtensionDropDownAction {

	constructor(
952
		@IInstantiationService instantiationService: IInstantiationService
S
Sandeep Somavarapu 已提交
953
	) {
954
		super('extensionEditor.manageExtension', '', `${ExtensionAction.ICON_ACTION_CLASS} manage codicon-gear`, true, true, instantiationService);
S
Sandeep Somavarapu 已提交
955 956 957
		this.tooltip = localize('manage', "Manage");
	}

958
	update(): void { }
S
Sandeep Somavarapu 已提交
959

960 961 962
	run(): Promise<any> {
		const actionGroups: IAction[][] = [];
		getContextMenuActions(this.extension, true, this.instantiationService).forEach(actions => actionGroups.push(actions));
963 964 965 966 967
		actionGroups.forEach(group => group.forEach(extensionAction => {
			if (extensionAction instanceof ExtensionAction) {
				extensionAction.extension = this.extension;
			}
		}));
968
		return super.run({ actionGroups, disposeActionsOnHide: true });
S
Sandeep Somavarapu 已提交
969 970 971 972
	}

}

973 974
export class MenuItemExtensionAction extends ExtensionAction {

S
Sandeep Somavarapu 已提交
975 976
	constructor(
		private readonly action: IAction,
977
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
978
	) {
979 980 981
		super(action.id, action.label);
	}

S
Sandeep Somavarapu 已提交
982 983 984 985 986
	update() {
		if (!this.extension) {
			return;
		}
		if (this.action.id === TOGGLE_IGNORE_EXTENSION_ACTION_ID) {
987
			this.checked = !this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension);
S
Sandeep Somavarapu 已提交
988 989
		}
	}
990 991 992

	async run(): Promise<void> {
		if (this.extension) {
S
Sandeep Somavarapu 已提交
993
			return this.action.run(this.extension.identifier.id);
994 995 996 997
		}
	}
}

S
Sandeep Somavarapu 已提交
998
export class InstallAnotherVersionAction extends ExtensionAction {
999

1000
	static readonly ID = 'workbench.extensions.action.install.anotherVersion';
1001
	static readonly LABEL = localize('install another version', "Install Another Version...");
1002

S
Sandeep Somavarapu 已提交
1003
	constructor(
1004 1005 1006 1007
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
1008
	) {
S
Sandeep Somavarapu 已提交
1009
		super(InstallAnotherVersionAction.ID, InstallAnotherVersionAction.LABEL, ExtensionAction.LABEL_ACTION_CLASS);
S
Sandeep Somavarapu 已提交
1010 1011 1012 1013
		this.update();
	}

	update(): void {
1014
		this.enabled = !!this.extension && !this.extension.isBuiltin && !!this.extension.gallery && this.extension.state === ExtensionState.Installed;
1015 1016
	}

J
Johannes Rieken 已提交
1017
	run(): Promise<any> {
1018 1019 1020
		if (!this.enabled) {
			return Promise.resolve();
		}
S
Sandeep Somavarapu 已提交
1021
		return this.quickInputService.pick(this.getVersionEntries(), { placeHolder: localize('selectVersion', "Select Version to Install"), matchOnDetail: true })
S
Sandeep Somavarapu 已提交
1022
			.then(async pick => {
1023
				if (pick) {
S
Sandeep Somavarapu 已提交
1024
					if (this.extension!.version === pick.id) {
S
Sandeep Somavarapu 已提交
1025 1026
						return Promise.resolve();
					}
S
Sandeep Somavarapu 已提交
1027 1028 1029 1030 1031 1032 1033 1034 1035
					try {
						if (pick.latest) {
							await this.extensionsWorkbenchService.install(this.extension!);
						} else {
							await this.extensionsWorkbenchService.installVersion(this.extension!, pick.id);
						}
					} catch (error) {
						this.instantiationService.createInstance(PromptExtensionInstallFailureAction, this.extension!, InstallOperation.Install, error).run();
					}
1036 1037 1038 1039
				}
				return null;
			});
	}
S
Sandeep Somavarapu 已提交
1040

1041
	private getVersionEntries(): Promise<(IQuickPickItem & { latest: boolean, id: string })[]> {
S
Sandeep Somavarapu 已提交
1042 1043
		return this.extensionGalleryService.getAllVersions(this.extension!.gallery!, true)
			.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 已提交
1044
	}
1045 1046
}

S
Sandeep Somavarapu 已提交
1047
export class EnableForWorkspaceAction extends ExtensionAction {
1048

1049
	static readonly ID = 'extensions.enableForWorkspace';
1050
	static readonly LABEL = localize('enableForWorkspaceAction', "Enable (Workspace)");
1051

S
Sandeep Somavarapu 已提交
1052
	constructor(
1053
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
1054
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
1055
	) {
1056
		super(EnableForWorkspaceAction.ID, EnableForWorkspaceAction.LABEL, ExtensionAction.LABEL_ACTION_CLASS);
1057 1058 1059
		this.update();
	}

S
Sandeep Somavarapu 已提交
1060
	update(): void {
1061
		this.enabled = false;
1062 1063
		if (this.extension && this.extension.local) {
			this.enabled = this.extension.state === ExtensionState.Installed
1064
				&& !this.extensionEnablementService.isEnabled(this.extension.local)
S
Sandeep Somavarapu 已提交
1065
				&& this.extensionEnablementService.canChangeWorkspaceEnablement(this.extension.local);
1066 1067 1068
		}
	}

S
Sandeep Somavarapu 已提交
1069 1070 1071 1072
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
1073
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledWorkspace);
1074 1075 1076
	}
}

S
Sandeep Somavarapu 已提交
1077
export class EnableGloballyAction extends ExtensionAction {
1078

1079
	static readonly ID = 'extensions.enableGlobally';
1080
	static readonly LABEL = localize('enableGloballyAction', "Enable");
1081

S
Sandeep Somavarapu 已提交
1082
	constructor(
1083
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
1084
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
1085
	) {
1086
		super(EnableGloballyAction.ID, EnableGloballyAction.LABEL, ExtensionAction.LABEL_ACTION_CLASS);
1087 1088 1089
		this.update();
	}

S
Sandeep Somavarapu 已提交
1090
	update(): void {
1091
		this.enabled = false;
1092
		if (this.extension && this.extension.local) {
1093
			this.enabled = this.extension.state === ExtensionState.Installed
S
Sandeep Somavarapu 已提交
1094
				&& this.extensionEnablementService.isDisabledGlobally(this.extension.local)
1095
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
1096 1097 1098
		}
	}

S
Sandeep Somavarapu 已提交
1099 1100 1101 1102
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
1103
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledGlobally);
1104 1105 1106
	}
}

S
Sandeep Somavarapu 已提交
1107
export class DisableForWorkspaceAction extends ExtensionAction {
1108

1109
	static readonly ID = 'extensions.disableForWorkspace';
1110
	static readonly LABEL = localize('disableForWorkspaceAction', "Disable (Workspace)");
1111

1112
	constructor(private _runningExtensions: IExtensionDescription[],
1113 1114
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
1115
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
1116
	) {
1117
		super(DisableForWorkspaceAction.ID, DisableForWorkspaceAction.LABEL, ExtensionAction.LABEL_ACTION_CLASS);
1118 1119 1120
		this.update();
	}

1121 1122 1123 1124 1125
	set runningExtensions(runningExtensions: IExtensionDescription[]) {
		this._runningExtensions = runningExtensions;
		this.update();
	}

S
Sandeep Somavarapu 已提交
1126
	update(): void {
1127
		this.enabled = false;
1128
		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)) {
1129
			this.enabled = this.extension.state === ExtensionState.Installed
1130
				&& (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace)
S
Sandeep Somavarapu 已提交
1131
				&& this.extensionEnablementService.canChangeWorkspaceEnablement(this.extension.local);
1132 1133 1134
		}
	}

S
Sandeep Somavarapu 已提交
1135 1136 1137 1138
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
1139
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledWorkspace);
1140 1141 1142
	}
}

S
Sandeep Somavarapu 已提交
1143
export class DisableGloballyAction extends ExtensionAction {
1144

1145
	static readonly ID = 'extensions.disableGlobally';
1146
	static readonly LABEL = localize('disableGloballyAction', "Disable");
1147

1148 1149
	constructor(
		private _runningExtensions: IExtensionDescription[],
1150
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
1151
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
1152
	) {
1153
		super(DisableGloballyAction.ID, DisableGloballyAction.LABEL, ExtensionAction.LABEL_ACTION_CLASS);
1154 1155 1156
		this.update();
	}

1157 1158 1159 1160 1161
	set runningExtensions(runningExtensions: IExtensionDescription[]) {
		this._runningExtensions = runningExtensions;
		this.update();
	}

S
Sandeep Somavarapu 已提交
1162
	update(): void {
1163
		this.enabled = false;
1164
		if (this.extension && this.extension.local && this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))) {
1165
			this.enabled = this.extension.state === ExtensionState.Installed
1166
				&& (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace)
1167
				&& this.extensionEnablementService.canChangeEnablement(this.extension.local);
1168 1169 1170
		}
	}

S
Sandeep Somavarapu 已提交
1171 1172 1173 1174
	async run(): Promise<any> {
		if (!this.extension) {
			return;
		}
1175
		return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledGlobally);
1176 1177 1178
	}
}

S
Sandeep Somavarapu 已提交
1179
export class EnableDropDownAction extends ActionWithDropDownAction {
S
Sandeep Somavarapu 已提交
1180 1181

	constructor(
S
Sandeep Somavarapu 已提交
1182
		@IInstantiationService instantiationService: IInstantiationService
S
Sandeep Somavarapu 已提交
1183
	) {
S
Sandeep Somavarapu 已提交
1184 1185
		super('extensions.enable', localize('enableAction', "Enable"), [
			instantiationService.createInstance(EnableGloballyAction),
1186
			instantiationService.createInstance(EnableForWorkspaceAction)
S
Sandeep Somavarapu 已提交
1187
		]);
S
Sandeep Somavarapu 已提交
1188 1189 1190
	}
}

S
Sandeep Somavarapu 已提交
1191
export class DisableDropDownAction extends ActionWithDropDownAction {
S
Sandeep Somavarapu 已提交
1192 1193

	constructor(
1194
		@IExtensionService extensionService: IExtensionService,
S
Sandeep Somavarapu 已提交
1195
		@IInstantiationService instantiationService: IInstantiationService
S
Sandeep Somavarapu 已提交
1196
	) {
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
		const actions = [
			instantiationService.createInstance(DisableGloballyAction, []),
			instantiationService.createInstance(DisableForWorkspaceAction, [])
		];
		super('extensions.disable', localize('disableAction', "Disable"), actions);

		const updateRunningExtensions = async () => {
			const runningExtensions = await extensionService.getExtensions();
			actions.forEach(a => a.runningExtensions = runningExtensions);
		};
		updateRunningExtensions();
		this._register(extensionService.onDidChangeExtensions(() => updateRunningExtensions()));
1209
	}
S
Sandeep Somavarapu 已提交
1210

1211 1212
}

J
Joao Moreno 已提交
1213 1214
export class CheckForUpdatesAction extends Action {

1215
	static readonly ID = 'workbench.extensions.action.checkForUpdates';
1216
	static readonly LABEL = localize('checkForUpdates', "Check for Extension Updates");
J
Joao Moreno 已提交
1217 1218

	constructor(
1219 1220
		id = CheckForUpdatesAction.ID,
		label = CheckForUpdatesAction.LABEL,
1221
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
1222
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
1223 1224
		@IViewletService private readonly viewletService: IViewletService,
		@INotificationService private readonly notificationService: INotificationService
J
Joao Moreno 已提交
1225 1226 1227 1228
	) {
		super(id, label, '', true);
	}

1229
	private checkUpdatesAndNotify(): void {
1230 1231
		const outdated = this.extensionsWorkbenchService.outdated;
		if (!outdated.length) {
1232
			this.notificationService.info(localize('noUpdatesAvailable', "All extensions are up to date."));
1233 1234
			return;
		}
1235

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

1238
		const disabledExtensionsCount = outdated.filter(ext => ext.local && !this.extensionEnablementService.isEnabled(ext.local)).length;
1239 1240 1241 1242 1243 1244 1245 1246 1247
		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);
1248
			}
1249 1250 1251
		}

		this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1252
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1253 1254 1255
			.then(viewlet => viewlet.search(''));

		this.notificationService.info(msgAvailableExtensions);
1256 1257
	}

S
Sandeep Somavarapu 已提交
1258
	run(): Promise<any> {
1259
		return this.extensionsWorkbenchService.checkForUpdates().then(() => this.checkUpdatesAndNotify());
J
Joao Moreno 已提交
1260 1261 1262
	}
}

S
Sandeep Somavarapu 已提交
1263 1264 1265 1266 1267 1268
export class ToggleAutoUpdateAction extends Action {

	constructor(
		id: string,
		label: string,
		private autoUpdateValue: boolean,
1269
		@IConfigurationService private readonly configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1270 1271 1272
	) {
		super(id, label, '', true);
		this.updateEnablement();
1273
		configurationService.onDidChangeConfiguration(() => this.updateEnablement());
S
Sandeep Somavarapu 已提交
1274 1275 1276
	}

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

S
Sandeep Somavarapu 已提交
1280
	run(): Promise<any> {
1281
		return this.configurationService.updateValue(AutoUpdateConfigurationKey, this.autoUpdateValue);
S
Sandeep Somavarapu 已提交
1282 1283 1284 1285 1286
	}
}

export class EnableAutoUpdateAction extends ToggleAutoUpdateAction {

1287
	static readonly ID = 'workbench.extensions.action.enableAutoUpdate';
1288
	static readonly LABEL = localize('enableAutoUpdate', "Enable Auto Updating Extensions");
S
Sandeep Somavarapu 已提交
1289 1290 1291 1292

	constructor(
		id = EnableAutoUpdateAction.ID,
		label = EnableAutoUpdateAction.LABEL,
1293
		@IConfigurationService configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1294
	) {
1295
		super(id, label, true, configurationService);
S
Sandeep Somavarapu 已提交
1296 1297 1298 1299 1300
	}
}

export class DisableAutoUpdateAction extends ToggleAutoUpdateAction {

1301
	static readonly ID = 'workbench.extensions.action.disableAutoUpdate';
1302
	static readonly LABEL = localize('disableAutoUpdate', "Disable Auto Updating Extensions");
S
Sandeep Somavarapu 已提交
1303 1304 1305 1306

	constructor(
		id = EnableAutoUpdateAction.ID,
		label = EnableAutoUpdateAction.LABEL,
1307
		@IConfigurationService configurationService: IConfigurationService
S
Sandeep Somavarapu 已提交
1308
	) {
1309
		super(id, label, false, configurationService);
S
Sandeep Somavarapu 已提交
1310 1311 1312
	}
}

1313 1314
export class UpdateAllAction extends Action {

1315
	static readonly ID = 'workbench.extensions.action.updateAllExtensions';
1316
	static readonly LABEL = localize('updateAll', "Update All Extensions");
1317 1318

	constructor(
S
Sandeep Somavarapu 已提交
1319
		id: string, label: string, isPrimary: boolean,
1320 1321
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
1322 1323 1324
	) {
		super(id, label, '', false);

S
Sandeep Somavarapu 已提交
1325 1326 1327
		if (isPrimary) {
			this._register(this.extensionsWorkbenchService.onChange(() => this._onDidChange.fire({ enabled: this.enabled })));
		}
1328 1329
	}

S
Sandeep Somavarapu 已提交
1330 1331
	get enabled(): boolean {
		return this.extensionsWorkbenchService.outdated.length > 0;
1332 1333
	}

S
Sandeep Somavarapu 已提交
1334
	run(): Promise<any> {
1335
		return Promise.all(this.extensionsWorkbenchService.outdated.map(e => this.install(e)));
J
Joao Moreno 已提交
1336 1337
	}

S
Sandeep Somavarapu 已提交
1338 1339 1340 1341 1342 1343
	private async install(extension: IExtension): Promise<void> {
		try {
			await this.extensionsWorkbenchService.install(extension);
		} catch (err) {
			this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, InstallOperation.Update, err).run();
		}
1344 1345 1346
	}
}

S
Sandeep Somavarapu 已提交
1347
export class ReloadAction extends ExtensionAction {
1348

S
Sandeep Somavarapu 已提交
1349
	private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} reload`;
1350
	private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
1351

1352
	updateWhenCounterExtensionChanges: boolean = true;
1353
	private _runningExtensions: IExtensionDescription[] | null = null;
1354 1355

	constructor(
1356
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
1357
		@IHostService private readonly hostService: IHostService,
1358
		@IExtensionService private readonly extensionService: IExtensionService,
S
rename  
Sandeep Somavarapu 已提交
1359
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
1360 1361 1362
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IProductService private readonly productService: IProductService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
1363 1364
	) {
		super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
M
Matt Bierner 已提交
1365
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
1366
		this.updateRunningExtensions();
1367 1368
	}

1369
	private updateRunningExtensions(): void {
1370
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
1371 1372 1373 1374 1375
	}

	update(): void {
		this.enabled = false;
		this.tooltip = '';
1376
		if (!this.extension || !this._runningExtensions) {
1377 1378 1379 1380 1381 1382
			return;
		}
		const state = this.extension.state;
		if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) {
			return;
		}
1383
		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) {
1384 1385
			return;
		}
1386
		this.computeReloadState();
1387
		this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
1388 1389
	}

1390
	private computeReloadState(): void {
S
Sandeep Somavarapu 已提交
1391
		if (!this._runningExtensions || !this.extension) {
1392 1393
			return;
		}
S
Sandeep Somavarapu 已提交
1394

1395
		const isUninstalled = this.extension.state === ExtensionState.Uninstalled;
S
Sandeep Somavarapu 已提交
1396
		const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0];
1397
		const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension));
1398

1399
		if (isUninstalled) {
S
Sandeep Somavarapu 已提交
1400
			if (isSameExtensionRunning && !this.extensionService.canRemoveExtension(runningExtension)) {
1401 1402 1403 1404 1405 1406 1407
				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;
		}
1408 1409
		if (this.extension.local) {
			const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
S
Sandeep Somavarapu 已提交
1410

1411
			// Extension is running
1412
			if (runningExtension) {
1413
				if (isEnabled) {
1414 1415 1416 1417
					// No Reload is required if extension can run without reload
					if (this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
						return;
					}
1418
					const runningExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension));
S
Sandeep Somavarapu 已提交
1419

1420 1421 1422 1423 1424 1425
					if (isSameExtensionRunning) {
						// Different version of same extension is running. Requires reload to run the current version
						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.");
S
Sandeep Somavarapu 已提交
1426
							return;
1427
						}
S
Sandeep Somavarapu 已提交
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447

						const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)[0];
						if (extensionInOtherServer) {
							// This extension prefers to run on UI/Local side but is running in remote
							if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && prefersExecuteOnUI(this.extension.local!.manifest, this.productService, this.configurationService)) {
								this.enabled = true;
								this.label = localize('reloadRequired', "Reload Required");
								this.tooltip = localize('enable locally', "Please reload Visual Studio Code to enable this extension locally.");
								return;
							}

							// This extension prefers to run on Workspace/Remote side but is running in local
							if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && prefersExecuteOnWorkspace(this.extension.local!.manifest, this.productService, this.configurationService)) {
								this.enabled = true;
								this.label = localize('reloadRequired', "Reload Required");
								this.tooltip = localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label);
								return;
							}
						}

1448
					} else {
S
Sandeep Somavarapu 已提交
1449

1450 1451 1452
						if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
							// This extension prefers to run on UI/Local side but is running in remote
							if (prefersExecuteOnUI(this.extension.local!.manifest, this.productService, this.configurationService)) {
1453 1454
								this.enabled = true;
								this.label = localize('reloadRequired', "Reload Required");
1455 1456 1457 1458 1459 1460 1461 1462 1463
								this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
							}
						}
						if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
							// This extension prefers to run on Workspace/Remote side but is running in local
							if (prefersExecuteOnWorkspace(this.extension.local!.manifest, this.productService, this.configurationService)) {
								this.enabled = true;
								this.label = localize('reloadRequired', "Reload Required");
								this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
1464 1465
							}
						}
1466
					}
1467
					return;
1468 1469 1470 1471 1472
				} 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 已提交
1473
					}
1474
				}
1475
				return;
S
Sandeep Somavarapu 已提交
1476 1477 1478 1479
			}

			// Extension is not running
			else {
1480
				if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
1481
					this.enabled = true;
S
Sandeep Somavarapu 已提交
1482
					this.label = localize('reloadRequired', "Reload Required");
1483
					this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension.");
1484
					return;
1485
				}
S
Sandeep Somavarapu 已提交
1486 1487 1488

				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) {
S
Sandeep Somavarapu 已提交
1489
					const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === otherServer)[0];
S
Sandeep Somavarapu 已提交
1490 1491 1492 1493 1494
					// 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.");
1495
						alert(localize('installExtensionCompletedAndReloadRequired', "Installing extension {0} is completed. Please reload Visual Studio Code to enable it.", this.extension.displayName));
S
Sandeep Somavarapu 已提交
1496
						return;
S
Explore  
Sandeep Somavarapu 已提交
1497
					}
1498
				}
1499 1500 1501 1502
			}
		}
	}

S
Sandeep Somavarapu 已提交
1503
	run(): Promise<any> {
1504
		return Promise.resolve(this.hostService.reload());
1505 1506 1507
	}
}

1508 1509 1510
function isThemeFromExtension(theme: IWorkbenchTheme, extension: IExtension | undefined | null): boolean {
	return !!(extension && theme.extensionData && ExtensionIdentifier.equals(theme.extensionData.extensionId, extension.identifier.id));
}
S
Sandeep Somavarapu 已提交
1511

1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
function getQuickPickEntries(themes: IWorkbenchTheme[], currentTheme: IWorkbenchTheme, extension: IExtension | null | undefined, showCurrentTheme: boolean): (IQuickPickItem | IQuickPickSeparator)[] {
	const picks: (IQuickPickItem | IQuickPickSeparator)[] = [];
	for (const theme of themes) {
		if (isThemeFromExtension(theme, extension) && !(showCurrentTheme && theme === currentTheme)) {
			picks.push({ label: theme.label, id: theme.id });
		}
	}
	if (showCurrentTheme) {
		picks.push(<IQuickPickSeparator>{ type: 'separator', label: localize('current', "Current") });
		picks.push(<IQuickPickItem>{ label: currentTheme.label, id: currentTheme.id });
1522
	}
1523 1524 1525 1526 1527
	return picks;
}


export class SetColorThemeAction extends ExtensionAction {
1528

S
Sandeep Somavarapu 已提交
1529
	private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} theme`;
S
Sandeep Somavarapu 已提交
1530 1531
	private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`;

1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
	static async create(workbenchThemeService: IWorkbenchThemeService, instantiationService: IInstantiationService, extension: IExtension): Promise<SetColorThemeAction | undefined> {
		const themes = await workbenchThemeService.getColorThemes();
		if (themes.some(th => isThemeFromExtension(th, extension))) {
			const action = instantiationService.createInstance(SetColorThemeAction, themes);
			action.extension = extension;
			return action;
		}
		return undefined;
	}

S
Sandeep Somavarapu 已提交
1542
	constructor(
1543
		private colorThemes: IWorkbenchColorTheme[],
S
Sandeep Somavarapu 已提交
1544 1545 1546 1547 1548
		@IExtensionService extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
	) {
		super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false);
M
Matt Bierner 已提交
1549
		this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this));
S
Sandeep Somavarapu 已提交
1550 1551 1552
		this.update();
	}

1553
	update(): void {
1554
		this.enabled = !!this.extension && (this.extension.state === ExtensionState.Installed) && this.colorThemes.some(th => isThemeFromExtension(th, this.extension));
S
Sandeep Somavarapu 已提交
1555 1556 1557
		this.class = this.enabled ? SetColorThemeAction.EnabledClass : SetColorThemeAction.DisabledClass;
	}

S
Sandeep Somavarapu 已提交
1558
	async run({ showCurrentTheme, ignoreFocusLost }: { showCurrentTheme: boolean, ignoreFocusLost: boolean } = { showCurrentTheme: false, ignoreFocusLost: false }): Promise<any> {
1559 1560
		this.colorThemes = await this.workbenchThemeService.getColorThemes();

1561
		this.update();
S
Sandeep Somavarapu 已提交
1562 1563 1564
		if (!this.enabled) {
			return;
		}
1565
		const currentTheme = this.workbenchThemeService.getColorTheme();
S
Sandeep Somavarapu 已提交
1566 1567

		const delayer = new Delayer<any>(100);
1568
		const picks = getQuickPickEntries(this.colorThemes, currentTheme, this.extension, showCurrentTheme);
S
Sandeep Somavarapu 已提交
1569 1570 1571 1572
		const pickedTheme = await this.quickInputService.pick(
			picks,
			{
				placeHolder: localize('select color theme', "Select Color Theme"),
S
Sandeep Somavarapu 已提交
1573 1574
				onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, undefined)),
				ignoreFocusLost
S
Sandeep Somavarapu 已提交
1575
			});
1576
		return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, 'auto');
S
Sandeep Somavarapu 已提交
1577 1578 1579 1580 1581
	}
}

export class SetFileIconThemeAction extends ExtensionAction {

S
Sandeep Somavarapu 已提交
1582
	private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} theme`;
S
Sandeep Somavarapu 已提交
1583 1584
	private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`;

1585 1586 1587 1588 1589 1590 1591 1592
	static async create(workbenchThemeService: IWorkbenchThemeService, instantiationService: IInstantiationService, extension: IExtension): Promise<SetFileIconThemeAction | undefined> {
		const themes = await workbenchThemeService.getFileIconThemes();
		if (themes.some(th => isThemeFromExtension(th, extension))) {
			const action = instantiationService.createInstance(SetFileIconThemeAction, themes);
			action.extension = extension;
			return action;
		}
		return undefined;
1593 1594
	}

S
Sandeep Somavarapu 已提交
1595
	constructor(
1596
		private fileIconThemes: IWorkbenchFileIconTheme[],
S
Sandeep Somavarapu 已提交
1597 1598
		@IExtensionService extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
1599
		@IQuickInputService private readonly quickInputService: IQuickInputService
S
Sandeep Somavarapu 已提交
1600 1601
	) {
		super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false);
M
Matt Bierner 已提交
1602
		this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this));
S
Sandeep Somavarapu 已提交
1603 1604 1605
		this.update();
	}

1606
	update(): void {
1607
		this.enabled = !!this.extension && (this.extension.state === ExtensionState.Installed) && this.fileIconThemes.some(th => isThemeFromExtension(th, this.extension));
S
Sandeep Somavarapu 已提交
1608 1609 1610
		this.class = this.enabled ? SetFileIconThemeAction.EnabledClass : SetFileIconThemeAction.DisabledClass;
	}

S
Sandeep Somavarapu 已提交
1611
	async run({ showCurrentTheme, ignoreFocusLost }: { showCurrentTheme: boolean, ignoreFocusLost: boolean } = { showCurrentTheme: false, ignoreFocusLost: false }): Promise<any> {
1612 1613
		this.fileIconThemes = await this.workbenchThemeService.getFileIconThemes();
		this.update();
S
Sandeep Somavarapu 已提交
1614 1615 1616
		if (!this.enabled) {
			return;
		}
1617
		const currentTheme = this.workbenchThemeService.getFileIconTheme();
S
Sandeep Somavarapu 已提交
1618 1619

		const delayer = new Delayer<any>(100);
1620
		const picks = getQuickPickEntries(this.fileIconThemes, currentTheme, this.extension, showCurrentTheme);
S
Sandeep Somavarapu 已提交
1621 1622 1623 1624
		const pickedTheme = await this.quickInputService.pick(
			picks,
			{
				placeHolder: localize('select file icon theme', "Select File Icon Theme"),
S
Sandeep Somavarapu 已提交
1625 1626
				onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setFileIconTheme(item.id, undefined)),
				ignoreFocusLost
S
Sandeep Somavarapu 已提交
1627
			});
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
		return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, 'auto');
	}
}

export class SetProductIconThemeAction extends ExtensionAction {

	private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} theme`;
	private static readonly DisabledClass = `${SetProductIconThemeAction.EnabledClass} disabled`;

	static async create(workbenchThemeService: IWorkbenchThemeService, instantiationService: IInstantiationService, extension: IExtension): Promise<SetProductIconThemeAction | undefined> {
		const themes = await workbenchThemeService.getProductIconThemes();
		if (themes.some(th => isThemeFromExtension(th, extension))) {
			const action = instantiationService.createInstance(SetProductIconThemeAction, themes);
			action.extension = extension;
			return action;
		}
		return undefined;
	}

	constructor(
		private productIconThemes: IWorkbenchProductIconTheme[],
		@IExtensionService extensionService: IExtensionService,
		@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
		@IQuickInputService private readonly quickInputService: IQuickInputService
	) {
		super(`extensions.productIconTheme`, localize('product icon theme', "Set Product Icon Theme"), SetProductIconThemeAction.DisabledClass, false);
		this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidProductIconThemeChange)(() => this.update(), this));
		this.enabled = true; // enabled by default
		this.class = SetProductIconThemeAction.EnabledClass;
		//		this.update();
	}

	update(): void {
		this.enabled = !!this.extension && (this.extension.state === ExtensionState.Installed) && this.productIconThemes.some(th => isThemeFromExtension(th, this.extension));
		this.class = this.enabled ? SetProductIconThemeAction.EnabledClass : SetProductIconThemeAction.DisabledClass;
	}

	async run({ showCurrentTheme, ignoreFocusLost }: { showCurrentTheme: boolean, ignoreFocusLost: boolean } = { showCurrentTheme: false, ignoreFocusLost: false }): Promise<any> {
		this.productIconThemes = await this.workbenchThemeService.getProductIconThemes();
		this.update();
		if (!this.enabled) {
			return;
		}

		const currentTheme = this.workbenchThemeService.getProductIconTheme();

		const delayer = new Delayer<any>(100);
		const picks = getQuickPickEntries(this.productIconThemes, currentTheme, this.extension, showCurrentTheme);
		const pickedTheme = await this.quickInputService.pick(
			picks,
			{
				placeHolder: localize('select product icon theme', "Select Product Icon Theme"),
				onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setProductIconTheme(item.id, undefined)),
				ignoreFocusLost
			});
		return this.workbenchThemeService.setProductIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, 'auto');
S
Sandeep Somavarapu 已提交
1684 1685 1686
	}
}

B
Benjamin Pasero 已提交
1687
export class OpenExtensionsViewletAction extends ShowViewletAction {
1688 1689 1690 1691 1692 1693 1694 1695

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

	constructor(
		id: string,
		label: string,
		@IViewletService viewletService: IViewletService,
B
Benjamin Pasero 已提交
1696
		@IEditorGroupsService editorGroupService: IEditorGroupsService,
1697
		@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
1698
	) {
1699
		super(id, label, VIEWLET_ID, viewletService, editorGroupService, layoutService);
1700 1701 1702 1703 1704 1705 1706 1707
	}
}

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

1708 1709
export class ShowEnabledExtensionsAction extends Action {

1710
	static readonly ID = 'workbench.extensions.action.showEnabledExtensions';
1711
	static readonly LABEL = localize('showEnabledExtensions', "Show Enabled Extensions");
1712 1713 1714 1715

	constructor(
		id: string,
		label: string,
1716
		@IViewletService private readonly viewletService: IViewletService
1717
	) {
R
Rob Lourens 已提交
1718
		super(id, label, undefined, true);
1719 1720
	}

J
Johannes Rieken 已提交
1721
	run(): Promise<void> {
1722
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1723
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1724
			.then(viewlet => {
1725
				viewlet.search('@enabled ');
1726 1727 1728 1729 1730
				viewlet.focus();
			});
	}
}

1731 1732
export class ShowInstalledExtensionsAction extends Action {

1733
	static readonly ID = 'workbench.extensions.action.showInstalledExtensions';
1734
	static readonly LABEL = localize('showInstalledExtensions', "Show Installed Extensions");
1735 1736 1737 1738

	constructor(
		id: string,
		label: string,
1739
		@IViewletService private readonly viewletService: IViewletService
1740
	) {
R
Rob Lourens 已提交
1741
		super(id, label, undefined, true);
1742 1743
	}

S
Sandeep Somavarapu 已提交
1744
	run(): Promise<void> {
1745
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1746
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1747
			.then(viewlet => {
S
Sandeep Somavarapu 已提交
1748
				viewlet.search('@installed ');
1749 1750 1751 1752 1753 1754 1755
				viewlet.focus();
			});
	}
}

export class ShowDisabledExtensionsAction extends Action {

1756
	static readonly ID = 'workbench.extensions.action.showDisabledExtensions';
1757
	static readonly LABEL = localize('showDisabledExtensions', "Show Disabled Extensions");
1758 1759 1760 1761

	constructor(
		id: string,
		label: string,
1762
		@IViewletService private readonly viewletService: IViewletService
1763 1764 1765 1766
	) {
		super(id, label, 'null', true);
	}

J
Johannes Rieken 已提交
1767
	run(): Promise<void> {
1768
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1769
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1770 1771 1772 1773 1774 1775 1776
			.then(viewlet => {
				viewlet.search('@disabled ');
				viewlet.focus();
			});
	}
}

S
Sandeep Somavarapu 已提交
1777
export class ClearExtensionsSearchResultsAction extends Action {
1778

S
Sandeep Somavarapu 已提交
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800
	static readonly ID = 'workbench.extensions.action.clearExtensionsSearchResults';
	static readonly LABEL = localize('clearExtensionsSearchResults', "Clear Extensions Search Results");

	constructor(
		id: string,
		label: string,
		@IViewsService private readonly viewsService: IViewsService
	) {
		super(id, label, 'codicon-clear-all', true);
	}

	async run(): Promise<void> {
		const viewPaneContainer = this.viewsService.getActiveViewPaneContainerWithId(VIEWLET_ID);
		if (viewPaneContainer) {
			const extensionsViewPaneContainer = viewPaneContainer as IExtensionsViewPaneContainer;
			extensionsViewPaneContainer.search('');
			extensionsViewPaneContainer.focus();
		}
	}
}

export class ClearExtensionsInputAction extends ClearExtensionsSearchResultsAction {
1801 1802 1803 1804 1805

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
J
João Moreno 已提交
1806
		getValue: () => string,
S
Sandeep Somavarapu 已提交
1807
		@IViewsService viewsService: IViewsService
1808
	) {
S
Sandeep Somavarapu 已提交
1809
		super(id, label, viewsService);
J
João Moreno 已提交
1810
		this.onSearchChange(getValue());
M
Matt Bierner 已提交
1811
		this._register(onSearchChange(this.onSearchChange, this));
1812 1813 1814 1815 1816 1817 1818
	}

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

S
Sandeep Somavarapu 已提交
1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
export class RefreshExtensionsAction extends Action {

	static readonly ID = 'workbench.extensions.action.refreshExtension';
	static readonly LABEL = localize('refreshExtension', "Refresh");

	constructor(
		id: string,
		label: string,
		@IViewsService private readonly viewsService: IViewsService
	) {
		super(id, label, 'codicon-refresh', true);
	}

	async run(): Promise<void> {
		const viewPaneContainer = this.viewsService.getActiveViewPaneContainerWithId(VIEWLET_ID);
		if (viewPaneContainer) {
			const extensionsViewPaneContainer = viewPaneContainer as IExtensionsViewPaneContainer;
S
Sandeep Somavarapu 已提交
1836
			return extensionsViewPaneContainer.refresh();
S
Sandeep Somavarapu 已提交
1837 1838 1839 1840
		}
	}
}

S
Sandeep Somavarapu 已提交
1841 1842 1843
export class ShowBuiltInExtensionsAction extends Action {

	static readonly ID = 'workbench.extensions.action.listBuiltInExtensions';
1844
	static readonly LABEL = localize('showBuiltInExtensions', "Show Built-in Extensions");
S
Sandeep Somavarapu 已提交
1845 1846 1847 1848

	constructor(
		id: string,
		label: string,
1849
		@IViewletService private readonly viewletService: IViewletService
S
Sandeep Somavarapu 已提交
1850
	) {
R
Rob Lourens 已提交
1851
		super(id, label, undefined, true);
S
Sandeep Somavarapu 已提交
1852 1853
	}

J
Johannes Rieken 已提交
1854
	run(): Promise<void> {
S
Sandeep Somavarapu 已提交
1855
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1856
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
S
Sandeep Somavarapu 已提交
1857 1858 1859 1860 1861 1862 1863
			.then(viewlet => {
				viewlet.search('@builtin ');
				viewlet.focus();
			});
	}
}

1864 1865
export class ShowOutdatedExtensionsAction extends Action {

1866
	static readonly ID = 'workbench.extensions.action.listOutdatedExtensions';
1867
	static readonly LABEL = localize('showOutdatedExtensions', "Show Outdated Extensions");
1868 1869 1870 1871

	constructor(
		id: string,
		label: string,
1872
		@IViewletService private readonly viewletService: IViewletService
1873
	) {
R
Rob Lourens 已提交
1874
		super(id, label, undefined, true);
1875 1876
	}

J
Johannes Rieken 已提交
1877
	run(): Promise<void> {
1878
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1879
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1880 1881 1882 1883 1884 1885 1886 1887 1888
			.then(viewlet => {
				viewlet.search('@outdated ');
				viewlet.focus();
			});
	}
}

export class ShowPopularExtensionsAction extends Action {

1889
	static readonly ID = 'workbench.extensions.action.showPopularExtensions';
1890
	static readonly LABEL = localize('showPopularExtensions', "Show Popular Extensions");
1891 1892 1893 1894

	constructor(
		id: string,
		label: string,
1895
		@IViewletService private readonly viewletService: IViewletService
1896
	) {
R
Rob Lourens 已提交
1897
		super(id, label, undefined, true);
1898 1899
	}

J
Johannes Rieken 已提交
1900
	run(): Promise<void> {
1901
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1902
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1903
			.then(viewlet => {
S
Sandeep Somavarapu 已提交
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
				viewlet.search('@popular ');
				viewlet.focus();
			});
	}
}

export class PredefinedExtensionFilterAction extends Action {

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

	run(): Promise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
			.then(viewlet => {
				viewlet.search(`${this.filter} `);
1926 1927 1928 1929 1930
				viewlet.focus();
			});
	}
}

S
Sandeep Somavarapu 已提交
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
export class RecentlyPublishedExtensionsAction extends Action {

	static readonly ID = 'workbench.extensions.action.recentlyPublishedExtensions';
	static readonly LABEL = localize('recentlyPublishedExtensions', "Recently Published Extensions");

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

	run(): Promise<void> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
			.then(viewlet => {
				viewlet.search('@sort:publishedDate ');
				viewlet.focus();
			});
	}
}

1954 1955
export class ShowRecommendedExtensionsAction extends Action {

1956
	static readonly ID = 'workbench.extensions.action.showRecommendedExtensions';
1957
	static readonly LABEL = localize('showRecommendedExtensions', "Show Recommended Extensions");
1958 1959 1960 1961

	constructor(
		id: string,
		label: string,
1962
		@IViewletService private readonly viewletService: IViewletService
1963
	) {
R
Rob Lourens 已提交
1964
		super(id, label, undefined, true);
1965 1966
	}

J
Johannes Rieken 已提交
1967
	run(): Promise<void> {
1968
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
1969
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
1970
			.then(viewlet => {
S
Sandeep Somavarapu 已提交
1971
				viewlet.search('@recommended ');
1972 1973 1974 1975 1976
				viewlet.focus();
			});
	}
}

1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
export class ShowRecommendedExtensionAction extends Action {

	static readonly ID = 'workbench.extensions.action.showRecommendedExtension';
	static readonly LABEL = localize('showRecommendedExtension', "Show Recommended Extension");

	private extensionId: string;

	constructor(
		extensionId: string,
		@IViewletService private readonly viewletService: IViewletService,
		@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
	) {
1989
		super(ShowRecommendedExtensionAction.ID, ShowRecommendedExtensionAction.LABEL, undefined, false);
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
		this.extensionId = extensionId;
	}

	run(): Promise<any> {
		return this.viewletService.openViewlet(VIEWLET_ID, true)
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
			.then(viewlet => {
				viewlet.search(`@id:${this.extensionId}`);
				viewlet.focus();
				return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None)
					.then(pager => {
						if (pager && pager.firstPage && pager.firstPage.length) {
							const extension = pager.firstPage[0];
							return this.extensionWorkbenchService.open(extension);
						}
						return null;
					});
			});
	}
}

2011
export class InstallRecommendedExtensionAction extends Action {
2012

2013
	static readonly ID = 'workbench.extensions.action.installRecommendedExtension';
2014
	static readonly LABEL = localize('installRecommendedExtension', "Install Recommended Extension");
2015 2016 2017 2018

	private extensionId: string;

	constructor(
2019
		extensionId: string,
2020 2021
		@IViewletService private readonly viewletService: IViewletService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
2022
		@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
2023
	) {
R
Rob Lourens 已提交
2024
		super(InstallRecommendedExtensionAction.ID, InstallRecommendedExtensionAction.LABEL, undefined, false);
2025 2026 2027
		this.extensionId = extensionId;
	}

S
Sandeep Somavarapu 已提交
2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
	async run(): Promise<any> {
		const viewlet = await this.viewletService.openViewlet(VIEWLET_ID, true);
		const viewPaneContainer = viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer;
		viewPaneContainer.search(`@id:${this.extensionId}`);
		viewPaneContainer.focus();
		const pager = await this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None);
		if (pager && pager.firstPage && pager.firstPage.length) {
			const extension = pager.firstPage[0];
			await this.extensionWorkbenchService.open(extension);
			try {
				await this.extensionWorkbenchService.install(extension);
			} catch (err) {
				this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, InstallOperation.Install, err).run();
			}
		}
2043 2044 2045
	}
}

2046 2047 2048 2049
export class IgnoreExtensionRecommendationAction extends Action {

	static readonly ID = 'extensions.ignore';

S
Sandeep Somavarapu 已提交
2050
	private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} ignore`;
2051 2052

	constructor(
S
Sandeep Somavarapu 已提交
2053
		private readonly extension: IExtension,
2054
		@IExtensionIgnoredRecommendationsService private readonly extensionRecommendationsManagementService: IExtensionIgnoredRecommendationsService,
2055
	) {
2056
		super(IgnoreExtensionRecommendationAction.ID, 'Ignore Recommendation');
2057 2058 2059 2060 2061 2062

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

S
Sandeep Somavarapu 已提交
2063
	public run(): Promise<any> {
2064
		this.extensionRecommendationsManagementService.toggleGlobalIgnoredRecommendation(this.extension.identifier.id, true);
2065
		return Promise.resolve();
2066 2067 2068 2069 2070 2071 2072
	}
}

export class UndoIgnoreExtensionRecommendationAction extends Action {

	static readonly ID = 'extensions.ignore';

S
Sandeep Somavarapu 已提交
2073
	private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} undo-ignore`;
2074 2075

	constructor(
S
Sandeep Somavarapu 已提交
2076
		private readonly extension: IExtension,
2077
		@IExtensionIgnoredRecommendationsService private readonly extensionRecommendationsManagementService: IExtensionIgnoredRecommendationsService,
2078 2079 2080 2081 2082 2083 2084 2085
	) {
		super(UndoIgnoreExtensionRecommendationAction.ID, 'Undo');

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

S
Sandeep Somavarapu 已提交
2086
	public run(): Promise<any> {
2087
		this.extensionRecommendationsManagementService.toggleGlobalIgnoredRecommendation(this.extension.identifier.id, false);
2088
		return Promise.resolve();
2089 2090 2091
	}
}

2092 2093
export class ShowRecommendedKeymapExtensionsAction extends Action {

2094
	static readonly ID = 'workbench.extensions.action.showRecommendedKeymapExtensions';
2095
	static readonly LABEL = localize('showRecommendedKeymapExtensionsShort', "Keymaps");
2096 2097 2098 2099

	constructor(
		id: string,
		label: string,
2100
		@IViewletService private readonly viewletService: IViewletService
2101
	) {
R
Rob Lourens 已提交
2102
		super(id, label, undefined, true);
2103 2104
	}

J
Johannes Rieken 已提交
2105
	run(): Promise<void> {
2106
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
2107
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
2108 2109 2110 2111 2112 2113 2114
			.then(viewlet => {
				viewlet.search('@recommended:keymaps ');
				viewlet.focus();
			});
	}
}

2115
export class ShowLanguageExtensionsAction extends Action {
2116

2117
	static readonly ID = 'workbench.extensions.action.showLanguageExtensions';
2118
	static readonly LABEL = localize('showLanguageExtensionsShort', "Language Extensions");
2119 2120 2121 2122

	constructor(
		id: string,
		label: string,
2123
		@IViewletService private readonly viewletService: IViewletService
2124
	) {
R
Rob Lourens 已提交
2125
		super(id, label, undefined, true);
2126 2127
	}

J
Johannes Rieken 已提交
2128
	run(): Promise<void> {
2129
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
2130
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
2131
			.then(viewlet => {
C
Christof Marti 已提交
2132
				viewlet.search('@category:"programming languages" @sort:installs ');
2133 2134 2135 2136 2137
				viewlet.focus();
			});
	}
}

S
Sandeep Somavarapu 已提交
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149
export class SearchCategoryAction extends Action {

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

	run(): Promise<void> {
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166
		return new SearchExtensionsAction(`@category:"${this.category.toLowerCase()}"`, this.viewletService).run();
	}
}

export class SearchExtensionsAction extends Action {

	constructor(
		private readonly searchValue: string,
		@IViewletService private readonly viewletService: IViewletService
	) {
		super('extensions.searchExtensions', localize('search recommendations', "Search Extensions"), undefined, true);
	}

	async run(): Promise<void> {
		const viewPaneContainer = (await this.viewletService.openViewlet(VIEWLET_ID, true))?.getViewPaneContainer() as IExtensionsViewPaneContainer;
		viewPaneContainer.search(this.searchValue);
		viewPaneContainer.focus();
S
Sandeep Somavarapu 已提交
2167 2168 2169
	}
}

2170 2171 2172 2173 2174 2175 2176 2177 2178
export class ChangeSortAction extends Action {

	private query: Query;

	constructor(
		id: string,
		label: string,
		onSearchChange: Event<string>,
		private sortBy: string,
2179
		@IViewletService private readonly viewletService: IViewletService
2180
	) {
R
Rob Lourens 已提交
2181
		super(id, label, undefined, true);
2182

J
Joao Moreno 已提交
2183
		if (sortBy === undefined) {
2184 2185 2186 2187 2188
			throw new Error('bad arguments');
		}

		this.query = Query.parse('');
		this.enabled = false;
S
Sandeep Somavarapu 已提交
2189
		this.checked = false;
M
Matt Bierner 已提交
2190
		this._register(onSearchChange(this.onSearchChange, this));
2191 2192 2193 2194
	}

	private onSearchChange(value: string): void {
		const query = Query.parse(value);
2195
		this.query = new Query(query.value, this.sortBy || query.sortBy, query.groupBy);
S
Sandeep Somavarapu 已提交
2196 2197
		this.enabled = !!value && this.query.isValid();
		this.checked = this.enabled && this.query.equals(query);
2198 2199
	}

J
Johannes Rieken 已提交
2200
	run(): Promise<void> {
2201
		return this.viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
2202
			.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
2203 2204 2205 2206 2207 2208 2209
			.then(viewlet => {
				viewlet.search(this.query.toString());
				viewlet.focus();
			});
	}
}

2210 2211 2212 2213 2214 2215
export abstract class AbstractConfigureRecommendedExtensionsAction extends Action {

	constructor(
		id: string,
		label: string,
		@IWorkspaceContextService protected contextService: IWorkspaceContextService,
2216
		@IFileService private readonly fileService: IFileService,
2217
		@ITextFileService private readonly textFileService: ITextFileService,
2218
		@IEditorService protected editorService: IEditorService,
2219 2220
		@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
		@ITextModelService private readonly textModelResolverService: ITextModelService
2221
	) {
2222
		super(id, label);
2223 2224
	}

S
Sandeep Somavarapu 已提交
2225
	protected openExtensionsFile(extensionsFileResource: URI): Promise<any> {
2226
		return this.getOrCreateExtensionsFile(extensionsFileResource)
S
Sandeep Somavarapu 已提交
2227 2228 2229 2230 2231 2232 2233 2234 2235
			.then(({ created, content }) =>
				this.getSelectionPosition(content, extensionsFileResource, ['recommendations'])
					.then(selection => this.editorService.openEditor({
						resource: extensionsFileResource,
						options: {
							pinned: created,
							selection
						}
					})),
S
Sandeep Somavarapu 已提交
2236
				error => Promise.reject(new Error(localize('OpenExtensionsFile.failed', "Unable to create 'extensions.json' file inside the '.vscode' folder ({0}).", error))));
2237 2238
	}

S
Sandeep Somavarapu 已提交
2239
	protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<any> {
2240
		return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
B
Benjamin Pasero 已提交
2241
			.then(content => this.getSelectionPosition(content.value.toString(), content.resource, ['extensions', 'recommendations']))
2242 2243 2244
			.then(selection => this.editorService.openEditor({
				resource: workspaceConfigurationFile,
				options: {
B
Benjamin Pasero 已提交
2245 2246
					selection,
					forceReload: true // because content has changed
2247 2248 2249 2250
				}
			}));
	}

B
Benjamin Pasero 已提交
2251 2252
	private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IFileContent> {
		return Promise.resolve(this.fileService.readFile(workspaceConfigurationFile))
2253
			.then(content => {
B
Benjamin Pasero 已提交
2254
				const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value.toString())['extensions'];
2255
				if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
S
Sandeep Somavarapu 已提交
2256
					return this.jsonEditingService.write(workspaceConfigurationFile, [{ path: ['extensions'], value: { recommendations: [] } }], true)
B
Benjamin Pasero 已提交
2257
						.then(() => this.fileService.readFile(workspaceConfigurationFile));
2258 2259 2260 2261 2262
				}
				return content;
			});
	}

J
Johannes Rieken 已提交
2263
	private getSelectionPosition(content: string, resource: URI, path: json.JSONPath): Promise<ITextEditorSelection | undefined> {
S
Sandeep Somavarapu 已提交
2264 2265
		const tree = json.parseTree(content);
		const node = json.findNodeAtLocation(tree, path);
2266
		if (node && node.parent && node.parent.children) {
S
Sandeep Somavarapu 已提交
2267 2268 2269
			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 已提交
2270
			return Promise.resolve(this.textModelResolverService.createModelReference(resource))
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
				.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 已提交
2282
		return Promise.resolve(undefined);
2283 2284
	}

S
Sandeep Somavarapu 已提交
2285
	private getOrCreateExtensionsFile(extensionsFileResource: URI): Promise<{ created: boolean, extensionsFileResource: URI, content: string }> {
B
Benjamin Pasero 已提交
2286 2287
		return Promise.resolve(this.fileService.readFile(extensionsFileResource)).then(content => {
			return { created: false, extensionsFileResource, content: content.value.toString() };
2288
		}, err => {
B
Benjamin Pasero 已提交
2289
			return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
S
Sandeep Somavarapu 已提交
2290
				return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
2291 2292 2293 2294 2295 2296
			});
		});
	}
}

export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction {
2297

2298
	static readonly ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions';
2299
	static readonly LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)");
2300 2301 2302 2303

	constructor(
		id: string,
		label: string,
2304
		@IFileService fileService: IFileService,
2305
		@ITextFileService textFileService: ITextFileService,
2306
		@IWorkspaceContextService contextService: IWorkspaceContextService,
2307
		@IEditorService editorService: IEditorService,
2308 2309
		@IJSONEditingService jsonEditingService: IJSONEditingService,
		@ITextModelService textModelResolverService: ITextModelService
2310
	) {
2311
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
M
Matt Bierner 已提交
2312
		this._register(this.contextService.onDidChangeWorkbenchState(() => this.update(), this));
2313 2314 2315 2316 2317
		this.update();
	}

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

2320
	public run(): Promise<void> {
2321 2322
		switch (this.contextService.getWorkbenchState()) {
			case WorkbenchState.FOLDER:
2323
				return this.openExtensionsFile(this.contextService.getWorkspace().folders[0].toResource(EXTENSIONS_CONFIG));
2324
			case WorkbenchState.WORKSPACE:
2325
				return this.openWorkspaceConfigurationFile(this.contextService.getWorkspace().configuration!);
2326
		}
2327
		return Promise.resolve();
2328
	}
2329
}
2330

2331 2332
export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction {

2333
	static readonly ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions';
2334
	static readonly LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)");
2335 2336 2337 2338 2339

	constructor(
		id: string,
		label: string,
		@IFileService fileService: IFileService,
2340
		@ITextFileService textFileService: ITextFileService,
2341
		@IWorkspaceContextService contextService: IWorkspaceContextService,
2342
		@IEditorService editorService: IEditorService,
2343
		@IJSONEditingService jsonEditingService: IJSONEditingService,
S
Sandeep Somavarapu 已提交
2344
		@ITextModelService textModelResolverService: ITextModelService,
2345
		@ICommandService private readonly commandService: ICommandService
2346
	) {
2347
		super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
M
Matt Bierner 已提交
2348
		this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this));
2349
		this.update();
2350 2351
	}

2352 2353 2354
	private update(): void {
		this.enabled = this.contextService.getWorkspace().folders.length > 0;
	}
2355

S
Sandeep Somavarapu 已提交
2356
	public run(): Promise<any> {
2357
		const folderCount = this.contextService.getWorkspace().folders.length;
S
Sandeep Somavarapu 已提交
2358 2359
		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 已提交
2360 2361
			.then(workspaceFolder => {
				if (workspaceFolder) {
2362
					return this.openExtensionsFile(workspaceFolder.toResource(EXTENSIONS_CONFIG));
2363
				}
S
Sandeep Somavarapu 已提交
2364
				return null;
2365
			});
2366 2367 2368
	}
}

S
#66931  
Sandeep Somavarapu 已提交
2369 2370
export class StatusLabelAction extends Action implements IExtensionContainer {

S
Sandeep Somavarapu 已提交
2371
	private static readonly ENABLED_CLASS = `${ExtensionAction.TEXT_ACTION_CLASS} extension-status-label`;
S
#66931  
Sandeep Somavarapu 已提交
2372 2373
	private static readonly DISABLED_CLASS = `${StatusLabelAction.ENABLED_CLASS} hide`;

S
Sandeep Somavarapu 已提交
2374
	private initialStatus: ExtensionState | null = null;
S
#66931  
Sandeep Somavarapu 已提交
2375 2376 2377
	private status: ExtensionState | null = null;
	private enablementState: EnablementState | null = null;

S
Sandeep Somavarapu 已提交
2378 2379 2380
	private _extension: IExtension | null = null;
	get extension(): IExtension | null { return this._extension; }
	set extension(extension: IExtension | null) {
S
Sandeep Somavarapu 已提交
2381
		if (!(this._extension && extension && areSameExtensions(this._extension.identifier, extension.identifier))) {
S
#66931  
Sandeep Somavarapu 已提交
2382
			// Different extension. Reset
S
Sandeep Somavarapu 已提交
2383
			this.initialStatus = null;
S
#66931  
Sandeep Somavarapu 已提交
2384 2385 2386 2387 2388 2389 2390 2391
			this.status = null;
			this.enablementState = null;
		}
		this._extension = extension;
		this.update();
	}

	constructor(
2392 2393
		@IExtensionService private readonly extensionService: IExtensionService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
S
#66931  
Sandeep Somavarapu 已提交
2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
	) {
		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 已提交
2414 2415 2416
		if (this.initialStatus === null) {
			this.initialStatus = this.status;
		}
S
#66931  
Sandeep Somavarapu 已提交
2417 2418 2419
		this.enablementState = this.extension.enablementState;

		const runningExtensions = await this.extensionService.getExtensions();
S
Sandeep Somavarapu 已提交
2420
		const canAddExtension = () => {
S
Sandeep Somavarapu 已提交
2421 2422 2423
			const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0];
			if (this.extension!.local) {
				if (runningExtension && this.extension!.version === runningExtension.version) {
S
Sandeep Somavarapu 已提交
2424 2425
					return true;
				}
S
Sandeep Somavarapu 已提交
2426
				return this.extensionService.canAddExtension(toExtensionDescription(this.extension!.local));
S
Sandeep Somavarapu 已提交
2427 2428 2429 2430
			}
			return false;
		};
		const canRemoveExtension = () => {
S
Sandeep Somavarapu 已提交
2431
			if (this.extension!.local) {
2432
				if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier) && this.extension!.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(e))))) {
S
Sandeep Somavarapu 已提交
2433 2434
					return true;
				}
S
Sandeep Somavarapu 已提交
2435
				return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension!.local));
S
Sandeep Somavarapu 已提交
2436 2437 2438
			}
			return false;
		};
S
#66931  
Sandeep Somavarapu 已提交
2439 2440 2441

		if (currentStatus !== null) {
			if (currentStatus === ExtensionState.Installing && this.status === ExtensionState.Installed) {
S
Sandeep Somavarapu 已提交
2442
				return canAddExtension() ? this.initialStatus === ExtensionState.Installed ? localize('updated', "Updated") : localize('installed', "Installed") : null;
S
#66931  
Sandeep Somavarapu 已提交
2443 2444
			}
			if (currentStatus === ExtensionState.Uninstalling && this.status === ExtensionState.Uninstalled) {
S
Sandeep Somavarapu 已提交
2445
				this.initialStatus = this.status;
S
#66931  
Sandeep Somavarapu 已提交
2446 2447 2448 2449 2450
				return canRemoveExtension() ? localize('uninstalled', "Uninstalled") : null;
			}
		}

		if (currentEnablementState !== null) {
2451 2452
			const currentlyEnabled = currentEnablementState === EnablementState.EnabledGlobally || currentEnablementState === EnablementState.EnabledWorkspace;
			const enabled = this.enablementState === EnablementState.EnabledGlobally || this.enablementState === EnablementState.EnabledWorkspace;
S
#66931  
Sandeep Somavarapu 已提交
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
			if (!currentlyEnabled && enabled) {
				return canAddExtension() ? localize('enabled', "Enabled") : null;
			}
			if (currentlyEnabled && !enabled) {
				return canRemoveExtension() ? localize('disabled', "Disabled") : null;
			}

		}

		return null;
	}

	run(): Promise<any> {
2466
		return Promise.resolve();
S
#66931  
Sandeep Somavarapu 已提交
2467 2468 2469 2470
	}

}

S
Sandeep Somavarapu 已提交
2471
export class MaliciousStatusLabelAction extends ExtensionAction {
J
Joao Moreno 已提交
2472

S
Sandeep Somavarapu 已提交
2473
	private static readonly Class = `${ExtensionAction.TEXT_ACTION_CLASS} malicious-status`;
J
Joao Moreno 已提交
2474 2475

	constructor(long: boolean) {
J
Joao Moreno 已提交
2476
		const tooltip = localize('malicious tooltip', "This extension was reported to be problematic.");
2477
		const label = long ? tooltip : localize({ key: 'malicious', comment: ['Refers to a malicious extension'] }, "Malicious");
J
Joao Moreno 已提交
2478
		super('extensions.install', label, '', false);
J
Joao Moreno 已提交
2479
		this.tooltip = localize('malicious tooltip', "This extension was reported to be problematic.");
J
Joao Moreno 已提交
2480 2481
	}

S
Sandeep Somavarapu 已提交
2482
	update(): void {
J
Joao Moreno 已提交
2483 2484 2485 2486 2487 2488 2489
		if (this.extension && this.extension.isMalicious) {
			this.class = `${MaliciousStatusLabelAction.Class} malicious`;
		} else {
			this.class = `${MaliciousStatusLabelAction.Class} not-malicious`;
		}
	}

S
Sandeep Somavarapu 已提交
2490
	run(): Promise<any> {
2491
		return Promise.resolve();
J
Joao Moreno 已提交
2492 2493 2494
	}
}

S
Sandeep Somavarapu 已提交
2495
export class ToggleSyncExtensionAction extends ExtensionDropDownAction {
S
Sandeep Somavarapu 已提交
2496

S
Sandeep Somavarapu 已提交
2497 2498
	private static readonly IGNORED_SYNC_CLASS = `${ExtensionAction.ICON_ACTION_CLASS} extension-sync codicon-sync-ignored`;
	private static readonly SYNC_CLASS = `${ToggleSyncExtensionAction.ICON_ACTION_CLASS} extension-sync codicon-sync`;
S
Sandeep Somavarapu 已提交
2499 2500

	constructor(
2501 2502
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
Sandeep Somavarapu 已提交
2503 2504
		@IUserDataAutoSyncEnablementService private readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService,
		@IInstantiationService instantiationService: IInstantiationService,
S
Sandeep Somavarapu 已提交
2505
	) {
S
Sandeep Somavarapu 已提交
2506
		super('extensions.sync', '', ToggleSyncExtensionAction.SYNC_CLASS, false, true, instantiationService);
S
Sandeep Somavarapu 已提交
2507
		this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectedKeys.includes('settingsSync.ignoredExtensions'))(() => this.update()));
S
Sandeep Somavarapu 已提交
2508
		this._register(userDataAutoSyncEnablementService.onDidChangeEnablement(() => this.update()));
S
Sandeep Somavarapu 已提交
2509 2510 2511 2512
		this.update();
	}

	update(): void {
2513
		this.enabled = !!this.extension && this.userDataAutoSyncEnablementService.isEnabled() && this.extension.state === ExtensionState.Installed;
S
Sandeep Somavarapu 已提交
2514 2515 2516 2517
		if (this.extension) {
			const isIgnored = this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension);
			this.class = isIgnored ? ToggleSyncExtensionAction.IGNORED_SYNC_CLASS : ToggleSyncExtensionAction.SYNC_CLASS;
			this.tooltip = isIgnored ? localize('ignored', "This extension is ignored during sync") : localize('synced', "This extension is synced");
2518
		}
S
Sandeep Somavarapu 已提交
2519 2520
	}

S
Sandeep Somavarapu 已提交
2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
	async run(): Promise<any> {
		return super.run({
			actionGroups: [
				[
					new Action(
						'extensions.syncignore',
						this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension!) ? localize('sync', "Sync this extension") : localize('do not sync', "Do not sync this extension")
						, undefined, true, () => this.extensionsWorkbenchService.toggleExtensionIgnoredToSync(this.extension!))
				]
			], disposeActionsOnHide: true
		});
S
Sandeep Somavarapu 已提交
2532 2533 2534
	}
}

S
Sandeep Somavarapu 已提交
2535
export class ExtensionToolTipAction extends ExtensionAction {
2536

S
Sandeep Somavarapu 已提交
2537
	private static readonly Class = `${ExtensionAction.TEXT_ACTION_CLASS} disable-status`;
2538 2539

	updateWhenCounterExtensionChanges: boolean = true;
2540
	private _runningExtensions: IExtensionDescription[] | null = null;
2541

2542 2543
	constructor(
		private readonly warningAction: SystemDisabledWarningAction,
S
Sandeep Somavarapu 已提交
2544
		private readonly reloadAction: ReloadAction,
S
rename  
Sandeep Somavarapu 已提交
2545
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
2546
		@IExtensionService private readonly extensionService: IExtensionService,
S
Sandeep Somavarapu 已提交
2547
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
2548
	) {
S
Sandeep Somavarapu 已提交
2549
		super('extensions.tooltip', warningAction.tooltip, `${ExtensionToolTipAction.Class} hide`, false);
M
Matt Bierner 已提交
2550 2551
		this._register(warningAction.onDidChange(() => this.update(), this));
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
2552 2553 2554 2555 2556
		this.updateRunningExtensions();
	}

	private updateRunningExtensions(): void {
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
2557 2558 2559
	}

	update(): void {
S
Sandeep Somavarapu 已提交
2560 2561 2562 2563
		this.label = this.getTooltip();
		this.class = ExtensionToolTipAction.Class;
		if (!this.label) {
			this.class = `${ExtensionToolTipAction.Class} hide`;
2564
		}
S
Sandeep Somavarapu 已提交
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
	}

	private getTooltip(): string {
		if (!this.extension) {
			return '';
		}
		if (this.reloadAction.enabled) {
			return this.reloadAction.tooltip;
		}
		if (this.warningAction.tooltip) {
			return this.warningAction.tooltip;
2576
		}
S
Sandeep Somavarapu 已提交
2577
		if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) {
S
Sandeep Somavarapu 已提交
2578
			const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier));
2579
			const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
S
Sandeep Somavarapu 已提交
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601

			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.");
				}
2602
			}
2603
		}
S
Sandeep Somavarapu 已提交
2604
		return '';
2605 2606 2607 2608 2609 2610 2611 2612 2613
	}

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

export class SystemDisabledWarningAction extends ExtensionAction {

S
Sandeep Somavarapu 已提交
2614
	private static readonly CLASS = `${ExtensionAction.ICON_ACTION_CLASS} system-disable`;
2615 2616
	private static readonly WARNING_CLASS = `${SystemDisabledWarningAction.CLASS} ${Codicon.warning.classNames}`;
	private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} ${Codicon.info.classNames}`;
2617 2618

	updateWhenCounterExtensionChanges: boolean = true;
2619
	private _runningExtensions: IExtensionDescription[] | null = null;
2620

2621 2622 2623
	constructor(
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@ILabelService private readonly labelService: ILabelService,
2624
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
2625 2626 2627
		@IExtensionService private readonly extensionService: IExtensionService,
		@IProductService private readonly productService: IProductService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
2628
	) {
2629
		super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false);
M
Matt Bierner 已提交
2630 2631
		this._register(this.labelService.onDidChangeFormatters(() => this.update(), this));
		this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
2632
		this.updateRunningExtensions();
2633 2634 2635
		this.update();
	}

2636 2637 2638 2639
	private updateRunningExtensions(): void {
		this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
	}

2640
	update(): void {
2641
		this.class = `${SystemDisabledWarningAction.CLASS} hide`;
2642
		this.tooltip = '';
2643 2644 2645 2646 2647
		if (
			!this.extension ||
			!this.extension.local ||
			!this.extension.server ||
			!this._runningExtensions ||
2648
			this.extension.state !== ExtensionState.Installed
2649
		) {
2650 2651
			return;
		}
2652 2653 2654 2655 2656
		if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
			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
D
Daniel Imms 已提交
2657 2658
						? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it there also.", this.extensionManagementServerService.remoteExtensionManagementServer.label)
						: localize('Install language pack also locally', "Install the language pack extension locally to enable it there also.");
2659 2660
				}
				return;
2661 2662
			}
		}
S
Sandeep Somavarapu 已提交
2663
		if (this.extension.enablementState === EnablementState.DisabledByExtensionKind) {
S
Sandeep Somavarapu 已提交
2664
			if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)) {
S
Sandeep Somavarapu 已提交
2665
				const server = this.extensionManagementServerService.localExtensionManagementServer === this.extension.server ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer;
2666
				this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
2667 2668 2669
				if (server) {
					this.tooltip = localize('Install in other server to enable', "Install the extension on '{0}' to enable.", server.label);
				} else {
S
Sandeep Somavarapu 已提交
2670
					this.tooltip = localize('disabled because of extension kind', "This extension has defined that it cannot run on the remote server");
2671
				}
S
Sandeep Somavarapu 已提交
2672 2673
				return;
			}
2674
		}
2675 2676
		if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
			const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0];
2677
			const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)) : null;
2678 2679 2680 2681 2682 2683
			if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
				if (prefersExecuteOnWorkspace(this.extension.local!.manifest, this.productService, this.configurationService)) {
					this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
					this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.extensionManagementServerService.remoteExtensionManagementServer.label);
				}
				return;
2684
			}
2685 2686 2687 2688 2689 2690
			if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
				if (prefersExecuteOnUI(this.extension.local!.manifest, this.productService, this.configurationService)) {
					this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
					this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.extensionManagementServerService.remoteExtensionManagementServer.label);
				}
				return;
2691
			}
2692 2693 2694 2695 2696 2697 2698 2699
		}
	}

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

2700 2701
export class DisableAllAction extends Action {

2702
	static readonly ID = 'workbench.extensions.action.disableAll';
2703
	static readonly LABEL = localize('disableAll', "Disable All Installed Extensions");
2704 2705

	constructor(
S
Sandeep Somavarapu 已提交
2706
		id: string, label: string, isPrimary: boolean,
2707
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
2708
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
2709 2710
	) {
		super(id, label);
S
Sandeep Somavarapu 已提交
2711 2712 2713
		if (isPrimary) {
			this._register(this.extensionsWorkbenchService.onChange(() => this._onDidChange.fire({ enabled: this.enabled })));
		}
2714 2715
	}

S
Sandeep Somavarapu 已提交
2716
	private getExtensionsToDisable(): IExtension[] {
2717
		return this.extensionsWorkbenchService.local.filter(e => !e.isBuiltin && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
S
Sandeep Somavarapu 已提交
2718 2719
	}

S
Sandeep Somavarapu 已提交
2720 2721
	get enabled(): boolean {
		return this.getExtensionsToDisable().length > 0;
2722 2723
	}

S
Sandeep Somavarapu 已提交
2724
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
2725
		return this.extensionsWorkbenchService.setEnablement(this.getExtensionsToDisable(), EnablementState.DisabledGlobally);
2726 2727 2728
	}
}

2729
export class DisableAllWorkspaceAction extends Action {
2730

2731
	static readonly ID = 'workbench.extensions.action.disableAllWorkspace';
2732
	static readonly LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace");
2733 2734

	constructor(
S
Sandeep Somavarapu 已提交
2735
		id: string, label: string, isPrimary: boolean,
2736
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
2737
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
2738
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
2739 2740
	) {
		super(id, label);
S
Sandeep Somavarapu 已提交
2741 2742 2743
		if (isPrimary) {
			this._register(Event.any(this.workspaceContextService.onDidChangeWorkbenchState, this.extensionsWorkbenchService.onChange)(() => this._onDidChange.fire({ enabled: this.enabled })));
		}
2744 2745
	}

S
Sandeep Somavarapu 已提交
2746
	private getExtensionsToDisable(): IExtension[] {
2747
		return this.extensionsWorkbenchService.local.filter(e => !e.isBuiltin && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
S
Sandeep Somavarapu 已提交
2748 2749
	}

S
Sandeep Somavarapu 已提交
2750 2751
	get enabled(): boolean {
		return this.getExtensionsToDisable().length > 0;
2752 2753
	}

S
Sandeep Somavarapu 已提交
2754
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
2755
		return this.extensionsWorkbenchService.setEnablement(this.getExtensionsToDisable(), EnablementState.DisabledWorkspace);
2756 2757 2758 2759 2760
	}
}

export class EnableAllAction extends Action {

2761
	static readonly ID = 'workbench.extensions.action.enableAll';
2762
	static readonly LABEL = localize('enableAll', "Enable All Extensions");
2763 2764

	constructor(
S
Sandeep Somavarapu 已提交
2765
		id: string, label: string, isPrimary: boolean,
2766
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
2767
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
2768 2769
	) {
		super(id, label);
S
Sandeep Somavarapu 已提交
2770 2771 2772
		if (isPrimary) {
			this._register(this.extensionsWorkbenchService.onChange(() => this._onDidChange.fire({ enabled: this.enabled })));
		}
2773 2774
	}

S
Sandeep Somavarapu 已提交
2775 2776 2777 2778
	private getExtensionsToEnable(): IExtension[] {
		return this.extensionsWorkbenchService.local.filter(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
	}

S
Sandeep Somavarapu 已提交
2779 2780
	get enabled(): boolean {
		return this.getExtensionsToEnable().length > 0;
2781 2782
	}

S
Sandeep Somavarapu 已提交
2783
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
2784
		return this.extensionsWorkbenchService.setEnablement(this.getExtensionsToEnable(), EnablementState.EnabledGlobally);
2785 2786 2787
	}
}

2788
export class EnableAllWorkspaceAction extends Action {
2789

2790
	static readonly ID = 'workbench.extensions.action.enableAllWorkspace';
2791
	static readonly LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace");
2792 2793

	constructor(
S
Sandeep Somavarapu 已提交
2794
		id: string, label: string, isPrimary: boolean,
2795 2796
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
S
rename  
Sandeep Somavarapu 已提交
2797
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService
2798 2799
	) {
		super(id, label);
S
Sandeep Somavarapu 已提交
2800 2801 2802
		if (isPrimary) {
			this._register(Event.any(this.workspaceContextService.onDidChangeWorkbenchState, this.extensionsWorkbenchService.onChange)(() => this._onDidChange.fire({ enabled: this.enabled })));
		}
2803 2804
	}

S
Sandeep Somavarapu 已提交
2805 2806 2807 2808
	private getExtensionsToEnable(): IExtension[] {
		return this.extensionsWorkbenchService.local.filter(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
	}

S
Sandeep Somavarapu 已提交
2809 2810
	get enabled(): boolean {
		return this.getExtensionsToEnable().length > 0;
2811 2812
	}

S
Sandeep Somavarapu 已提交
2813
	run(): Promise<any> {
S
Sandeep Somavarapu 已提交
2814
		return this.extensionsWorkbenchService.setEnablement(this.getExtensionsToEnable(), EnablementState.EnabledWorkspace);
2815
	}
2816 2817
}

J
Joao Moreno 已提交
2818 2819 2820
export class InstallVSIXAction extends Action {

	static readonly ID = 'workbench.extensions.action.installVSIX';
2821
	static readonly LABEL = localize('installVSIX', "Install from VSIX...");
J
Joao Moreno 已提交
2822 2823 2824 2825

	constructor(
		id = InstallVSIXAction.ID,
		label = InstallVSIXAction.LABEL,
2826
		@IFileDialogService private readonly fileDialogService: IFileDialogService,
2827
		@ICommandService private readonly commandService: ICommandService
J
Joao Moreno 已提交
2828
	) {
S
Sandeep Somavarapu 已提交
2829
		super(id, label, 'extension-action install-vsix', true);
J
Joao Moreno 已提交
2830 2831
	}

2832 2833 2834 2835 2836
	async run(): Promise<void> {
		const vsixPaths = await this.fileDialogService.showOpenDialog({
			title: localize('installFromVSIX', "Install from VSIX"),
			filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
			canSelectFiles: true,
S
Sandeep Somavarapu 已提交
2837
			canSelectMany: true,
2838 2839
			openLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
		});
2840

2841 2842
		if (!vsixPaths) {
			return;
2843
		}
J
Joao Moreno 已提交
2844

2845
		// Install extension(s), display notification(s), display @installed extensions
2846
		await this.commandService.executeCommand(INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, vsixPaths);
J
Joao Moreno 已提交
2847 2848 2849 2850 2851 2852
	}
}

export class ReinstallAction extends Action {

	static readonly ID = 'workbench.extensions.action.reinstall';
2853
	static readonly LABEL = localize('reinstall', "Reinstall Extension...");
J
Joao Moreno 已提交
2854 2855 2856

	constructor(
		id: string = ReinstallAction.ID, label: string = ReinstallAction.LABEL,
2857 2858 2859
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
2860
		@IHostService private readonly hostService: IHostService,
S
Sandeep Somavarapu 已提交
2861 2862
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IExtensionService private readonly extensionService: IExtensionService
J
Joao Moreno 已提交
2863 2864 2865 2866 2867
	) {
		super(id, label);
	}

	get enabled(): boolean {
2868
		return this.extensionsWorkbenchService.local.filter(l => !l.isBuiltin && l.local).length > 0;
J
Joao Moreno 已提交
2869 2870
	}

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

J
Johannes Rieken 已提交
2876
	private getEntries(): Promise<(IQuickPickItem & { extension: IExtension })[]> {
J
Joao Moreno 已提交
2877 2878
		return this.extensionsWorkbenchService.queryLocal()
			.then(local => {
C
Christof Marti 已提交
2879
				const entries = local
2880
					.filter(extension => !extension.isBuiltin)
J
Joao Moreno 已提交
2881
					.map(extension => {
C
Christof Marti 已提交
2882
						return {
S
Sandeep Somavarapu 已提交
2883
							id: extension.identifier.id,
J
Joao Moreno 已提交
2884
							label: extension.displayName,
S
Sandeep Somavarapu 已提交
2885
							description: extension.identifier.id,
C
Christof Marti 已提交
2886 2887
							extension,
						} as (IQuickPickItem & { extension: IExtension });
J
Joao Moreno 已提交
2888 2889 2890 2891 2892
					});
				return entries;
			});
	}

J
Johannes Rieken 已提交
2893
	private reinstallExtension(extension: IExtension): Promise<void> {
S
Sandeep Somavarapu 已提交
2894 2895
		return this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL).run()
			.then(() => {
2896
				return this.extensionsWorkbenchService.reinstall(extension)
S
Sandeep Somavarapu 已提交
2897 2898 2899 2900 2901 2902
					.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"),
2903
							run: () => this.hostService.reload()
S
Sandeep Somavarapu 已提交
2904
						}] : [];
2905 2906
						this.notificationService.prompt(
							Severity.Info,
S
Sandeep Somavarapu 已提交
2907 2908
							message,
							actions,
2909 2910 2911 2912
							{ sticky: true }
						);
					}, error => this.notificationService.error(error));
			});
J
Joao Moreno 已提交
2913 2914 2915
	}
}

S
Sandeep Somavarapu 已提交
2916
export class InstallSpecificVersionOfExtensionAction extends Action {
2917

S
Sandeep Somavarapu 已提交
2918
	static readonly ID = 'workbench.extensions.action.install.specificVersion';
2919
	static readonly LABEL = localize('install previous version', "Install Specific Version of Extension...");
2920 2921

	constructor(
S
Sandeep Somavarapu 已提交
2922
		id: string = InstallSpecificVersionOfExtensionAction.ID, label: string = InstallSpecificVersionOfExtensionAction.LABEL,
2923 2924 2925 2926
		@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
2927
		@IHostService private readonly hostService: IHostService,
S
Sandeep Somavarapu 已提交
2928
		@IInstantiationService private readonly instantiationService: IInstantiationService,
2929
		@IExtensionService private readonly extensionService: IExtensionService,
S
rename  
Sandeep Somavarapu 已提交
2930
		@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
2931 2932 2933 2934 2935
	) {
		super(id, label);
	}

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

S
Sandeep Somavarapu 已提交
2939 2940 2941
	async run(): Promise<any> {
		const extensionPick = await this.quickInputService.pick(this.getExtensionEntries(), { placeHolder: localize('selectExtension', "Select Extension"), matchOnDetail: true });
		if (extensionPick && extensionPick.extension) {
2942
			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 已提交
2943 2944
			if (versionPick) {
				if (extensionPick.extension.version !== versionPick.id) {
2945
					await this.install(extensionPick.extension, versionPick.id);
S
Sandeep Somavarapu 已提交
2946 2947
				}
			}
S
Sandeep Somavarapu 已提交
2948 2949 2950 2951
		}
	}

	private isEnabled(extension: IExtension): boolean {
2952
		return !!extension.gallery && !!extension.local && this.extensionEnablementService.isEnabled(extension.local);
2953 2954
	}

S
Sandeep Somavarapu 已提交
2955
	private async getExtensionEntries(): Promise<(IQuickPickItem & { extension: IExtension, versions: IGalleryExtensionVersion[] })[]> {
2956
		const installed = await this.extensionsWorkbenchService.queryLocal();
2957
		const versionsPromises: Promise<{ extension: IExtension, versions: IGalleryExtensionVersion[] } | null>[] = [];
2958
		for (const extension of installed) {
S
Sandeep Somavarapu 已提交
2959
			if (this.isEnabled(extension)) {
2960
				versionsPromises.push(this.extensionGalleryService.getAllVersions(extension.gallery!, true)
S
Sandeep Somavarapu 已提交
2961
					.then(versions => (versions.length ? { extension, versions } : null)));
2962 2963 2964
			}
		}

S
Sandeep Somavarapu 已提交
2965
		const extensions = await Promise.all(versionsPromises);
M
Matt Bierner 已提交
2966
		return coalesce(extensions)
2967
			.sort((e1, e2) => e1.extension.displayName.localeCompare(e2.extension.displayName))
S
Sandeep Somavarapu 已提交
2968
			.map(({ extension, versions }) => {
2969
				return {
S
Sandeep Somavarapu 已提交
2970 2971 2972
					id: extension.identifier.id,
					label: extension.displayName || extension.identifier.id,
					description: extension.identifier.id,
2973
					extension,
S
Sandeep Somavarapu 已提交
2974 2975
					versions
				} as (IQuickPickItem & { extension: IExtension, versions: IGalleryExtensionVersion[] });
2976 2977 2978
			});
	}

J
Johannes Rieken 已提交
2979
	private install(extension: IExtension, version: string): Promise<void> {
S
Sandeep Somavarapu 已提交
2980 2981
		return this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL).run()
			.then(() => {
2982
				return this.extensionsWorkbenchService.installVersion(extension, version)
S
Sandeep Somavarapu 已提交
2983 2984 2985 2986 2987 2988
					.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"),
2989
							run: () => this.hostService.reload()
S
Sandeep Somavarapu 已提交
2990
						}] : [];
2991 2992
						this.notificationService.prompt(
							Severity.Info,
S
Sandeep Somavarapu 已提交
2993 2994
							message,
							actions,
2995 2996 2997 2998
							{ sticky: true }
						);
					}, error => this.notificationService.error(error));
			});
J
Joao Moreno 已提交
2999 3000 3001
	}
}

3002 3003 3004 3005
interface IExtensionPickItem extends IQuickPickItem {
	extension?: IExtension;
}

S
Sandeep Somavarapu 已提交
3006
export abstract class AbstractInstallExtensionsInServerAction extends Action {
3007

3008 3009
	private extensions: IExtension[] | undefined = undefined;

3010
	constructor(
S
Sandeep Somavarapu 已提交
3011 3012
		id: string,
		@IExtensionsWorkbenchService protected readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
3013 3014
		@IQuickInputService private readonly quickInputService: IQuickInputService,
		@INotificationService private readonly notificationService: INotificationService,
3015
		@IProgressService private readonly progressService: IProgressService,
3016
	) {
S
Sandeep Somavarapu 已提交
3017
		super(id);
3018
		this.update();
3019 3020 3021 3022 3023 3024
		this.extensionsWorkbenchService.queryLocal().then(() => this.updateExtensions());
		this._register(this.extensionsWorkbenchService.onChange(() => {
			if (this.extensions) {
				this.updateExtensions();
			}
		}));
3025 3026
	}

3027 3028 3029 3030 3031
	private updateExtensions(): void {
		this.extensions = this.extensionsWorkbenchService.local;
		this.update();
	}

3032
	private update(): void {
3033
		this.enabled = !!this.extensions && this.getExtensionsToInstall(this.extensions).length > 0;
S
Sandeep Somavarapu 已提交
3034
		this.tooltip = this.label;
3035 3036
	}

3037
	async run(): Promise<void> {
S
Sandeep Somavarapu 已提交
3038
		return this.selectAndInstallExtensions();
3039 3040 3041 3042 3043 3044 3045
	}

	private async queryExtensionsToInstall(): Promise<IExtension[]> {
		const local = await this.extensionsWorkbenchService.queryLocal();
		return this.getExtensionsToInstall(local);
	}

S
Sandeep Somavarapu 已提交
3046
	private async selectAndInstallExtensions(): Promise<void> {
3047 3048 3049 3050 3051 3052 3053 3054 3055
		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();
3056
		const localExtensionsToInstall = await this.queryExtensionsToInstall();
3057 3058
		quickPick.busy = false;
		if (localExtensionsToInstall.length) {
S
Sandeep Somavarapu 已提交
3059
			quickPick.title = this.getQuickPickTitle();
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070
			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.")
			});
3071 3072 3073
		}
	}

S
Sandeep Somavarapu 已提交
3074
	private async onDidAccept(selectedItems: ReadonlyArray<IExtensionPickItem>): Promise<void> {
3075 3076
		if (selectedItems.length) {
			const localExtensionsToInstall = selectedItems.filter(r => !!r.extension).map(r => r.extension!);
3077
			if (localExtensionsToInstall.length) {
S
Sandeep Somavarapu 已提交
3078
				await this.progressService.withProgress(
3079 3080 3081 3082
					{
						location: ProgressLocation.Notification,
						title: localize('installing extensions', "Installing Extensions...")
					},
S
Sandeep Somavarapu 已提交
3083 3084
					() => this.installExtensions(localExtensionsToInstall));
				this.notificationService.info(localize('finished installing', "Successfully installed extensions."));
3085 3086 3087 3088
			}
		}
	}

S
Sandeep Somavarapu 已提交
3089 3090 3091 3092 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
	protected abstract getQuickPickTitle(): string;
	protected abstract getExtensionsToInstall(local: IExtension[]): IExtension[];
	protected abstract installExtensions(extensions: IExtension[]): Promise<void>;
}

export class InstallLocalExtensionsInRemoteAction extends AbstractInstallExtensionsInServerAction {

	constructor(
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IQuickInputService quickInputService: IQuickInputService,
		@IProgressService progressService: IProgressService,
		@INotificationService notificationService: INotificationService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
		@IInstantiationService private readonly instantiationService: IInstantiationService
	) {
		super('workbench.extensions.actions.installLocalExtensionsInRemote', extensionsWorkbenchService, quickInputService, notificationService, progressService);
	}

	get label(): string {
		if (this.extensionManagementServerService && this.extensionManagementServerService.remoteExtensionManagementServer) {
			return localize('select and install local extensions', "Install Local Extensions in '{0}'...", this.extensionManagementServerService.remoteExtensionManagementServer.label);
		}
		return '';
	}

	protected getQuickPickTitle(): string {
		return localize('install local extensions title', "Install Local Extensions in '{0}'", this.extensionManagementServerService.remoteExtensionManagementServer!.label);
	}

	protected getExtensionsToInstall(local: IExtension[]): IExtension[] {
		return local.filter(extension => {
			const action = this.instantiationService.createInstance(RemoteInstallAction, true);
			action.extension = extension;
			return action.enabled;
		});
	}

	protected async installExtensions(localExtensionsToInstall: IExtension[]): Promise<void> {
3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143
		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)));
S
Sandeep Somavarapu 已提交
3144 3145 3146 3147
	}
}

export class InstallRemoteExtensionsInLocalAction extends AbstractInstallExtensionsInServerAction {
3148

S
Sandeep Somavarapu 已提交
3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184
	constructor(
		id: string,
		@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
		@IQuickInputService quickInputService: IQuickInputService,
		@IProgressService progressService: IProgressService,
		@INotificationService notificationService: INotificationService,
		@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
		@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
	) {
		super(id, extensionsWorkbenchService, quickInputService, notificationService, progressService);
	}

	get label(): string {
		return localize('select and install remote extensions', "Install Remote Extensions Locally...");
	}

	protected getQuickPickTitle(): string {
		return localize('install remote extensions', "Install Remote Extensions Locally");
	}

	protected getExtensionsToInstall(local: IExtension[]): IExtension[] {
		return local.filter(extension =>
			extension.type === ExtensionType.User && extension.server !== this.extensionManagementServerService.localExtensionManagementServer
			&& !this.extensionsWorkbenchService.installed.some(e => e.server === this.extensionManagementServerService.localExtensionManagementServer && areSameExtensions(e.identifier, extension.identifier)));
	}

	protected async installExtensions(extensions: IExtension[]): Promise<void> {
		const galleryExtensions: IGalleryExtension[] = [];
		const vsixs: URI[] = [];
		await Promise.all(extensions.map(async extension => {
			if (this.extensionGalleryService.isEnabled()) {
				const gallery = await this.extensionGalleryService.getCompatibleExtension(extension.identifier, extension.version);
				if (gallery) {
					galleryExtensions.push(gallery);
					return;
				}
3185
			}
S
Sandeep Somavarapu 已提交
3186 3187 3188 3189 3190 3191
			const vsix = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.zip(extension.local!);
			vsixs.push(vsix);
		}));

		await Promise.all(galleryExtensions.map(gallery => this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.installFromGallery(gallery)));
		await Promise.all(vsixs.map(vsix => this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.install(vsix)));
3192 3193 3194
	}
}

S
Sandeep Somavarapu 已提交
3195
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForLanguage', function (accessor: ServicesAccessor, fileExtension: string) {
3196 3197 3198
	const viewletService = accessor.get(IViewletService);

	return viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
3199
		.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
3200 3201 3202 3203 3204
		.then(viewlet => {
			viewlet.search(`ext:${fileExtension.replace(/^\./, '')}`);
			viewlet.focus();
		});
});
B
Benjamin Pasero 已提交
3205

3206
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsWithIds', function (accessor: ServicesAccessor, extensionIds: string[]) {
3207 3208 3209
	const viewletService = accessor.get(IViewletService);

	return viewletService.openViewlet(VIEWLET_ID, true)
S
SteVen Batten 已提交
3210
		.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
3211
		.then(viewlet => {
3212 3213 3214 3215
			const query = extensionIds
				.map(id => `@id:${id}`)
				.join(' ');
			viewlet.search(query);
3216 3217 3218 3219
			viewlet.focus();
		});
});

B
Benjamin Pasero 已提交
3220
export const extensionButtonProminentBackground = registerColor('extensionButton.prominentBackground', {
3221 3222
	dark: buttonBackground,
	light: buttonBackground,
B
Benjamin Pasero 已提交
3223 3224 3225 3226
	hc: null
}, localize('extensionButtonProminentBackground', "Button background color for actions extension that stand out (e.g. install button)."));

export const extensionButtonProminentForeground = registerColor('extensionButton.prominentForeground', {
3227 3228
	dark: buttonForeground,
	light: buttonForeground,
B
Benjamin Pasero 已提交
3229 3230 3231 3232
	hc: null
}, localize('extensionButtonProminentForeground', "Button foreground color for actions extension that stand out (e.g. install button)."));

export const extensionButtonProminentHoverBackground = registerColor('extensionButton.prominentHoverBackground', {
3233 3234
	dark: buttonHoverBackground,
	light: buttonHoverBackground,
B
Benjamin Pasero 已提交
3235 3236 3237
	hc: null
}, localize('extensionButtonProminentHoverBackground', "Button background hover color for actions extension that stand out (e.g. install button)."));

M
Martin Aeschlimann 已提交
3238
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
B
Benjamin Pasero 已提交
3239 3240
	const foregroundColor = theme.getColor(foreground);
	if (foregroundColor) {
3241
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action.built-in-status { border-color: ${foregroundColor}; }`);
3242
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.built-in-status { border-color: ${foregroundColor}; }`);
B
Benjamin Pasero 已提交
3243 3244
	}

B
Benjamin Pasero 已提交
3245 3246
	const buttonBackgroundColor = theme.getColor(buttonBackground);
	if (buttonBackgroundColor) {
S
Sandeep Somavarapu 已提交
3247 3248
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action.label { background-color: ${buttonBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.label { background-color: ${buttonBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3249 3250 3251 3252
	}

	const buttonForegroundColor = theme.getColor(buttonForeground);
	if (buttonForegroundColor) {
S
Sandeep Somavarapu 已提交
3253 3254
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action.label { color: ${buttonForegroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.label { color: ${buttonForegroundColor}; }`);
B
Benjamin Pasero 已提交
3255 3256 3257 3258
	}

	const buttonHoverBackgroundColor = theme.getColor(buttonHoverBackground);
	if (buttonHoverBackgroundColor) {
S
Sandeep Somavarapu 已提交
3259 3260
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item:hover .action-label.extension-action.label { background-color: ${buttonHoverBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item:hover .action-label.extension-action.label { background-color: ${buttonHoverBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3261 3262 3263 3264
	}

	const extensionButtonProminentBackgroundColor = theme.getColor(extensionButtonProminentBackground);
	if (extensionButtonProminentBackground) {
S
Sandeep Somavarapu 已提交
3265 3266
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action.label.prominent { background-color: ${extensionButtonProminentBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.label.prominent { background-color: ${extensionButtonProminentBackgroundColor}; }`);
B
Benjamin Pasero 已提交
3267 3268 3269 3270
	}

	const extensionButtonProminentForegroundColor = theme.getColor(extensionButtonProminentForeground);
	if (extensionButtonProminentForeground) {
S
Sandeep Somavarapu 已提交
3271 3272
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action.label.prominent { color: ${extensionButtonProminentForegroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action.label.prominent { color: ${extensionButtonProminentForegroundColor}; }`);
B
Benjamin Pasero 已提交
3273 3274 3275 3276
	}

	const extensionButtonProminentHoverBackgroundColor = theme.getColor(extensionButtonProminentHoverBackground);
	if (extensionButtonProminentHoverBackground) {
S
Sandeep Somavarapu 已提交
3277 3278 3279 3280 3281 3282
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item:hover .action-label.extension-action.label.prominent { background-color: ${extensionButtonProminentHoverBackgroundColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item:hover .action-label.extension-action.label.prominent { background-color: ${extensionButtonProminentHoverBackgroundColor}; }`);
	}

	const contrastBorderColor = theme.getColor(contrastBorder);
	if (contrastBorderColor) {
S
Sandeep Somavarapu 已提交
3283 3284
		collector.addRule(`.extension-list-item .monaco-action-bar .action-item .action-label.extension-action:not(.disabled) { border: 1px solid ${contrastBorderColor}; }`);
		collector.addRule(`.extension-editor .monaco-action-bar .action-item .action-label.extension-action:not(.disabled) { border: 1px solid ${contrastBorderColor}; }`);
B
Benjamin Pasero 已提交
3285
	}
A
Alex Dima 已提交
3286
});