1464 lines
68 KiB
TypeScript
1464 lines
68 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { localize } from 'vs/nls';
|
|
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
|
import { Registry } from 'vs/platform/registry/common/platform';
|
|
import { MenuRegistry, MenuId, registerAction2, Action2, ISubmenuItem, IMenuItem, IAction2Options } from 'vs/platform/actions/common/actions';
|
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
|
import { ExtensionsLabel, ExtensionsLocalizedLabel, ExtensionsChannelId, IExtensionManagementService, IExtensionGalleryService, PreferencesLocalizedLabel, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
|
|
import { EnablementState, IExtensionManagementServerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
|
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
|
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
|
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, ExtensionEditorTab } from 'vs/workbench/contrib/extensions/common/extensions';
|
|
import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
|
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
|
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
|
|
import { StatusUpdater, MaliciousExtensionChecker, ExtensionsViewletViewsContribution, ExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/browser/extensionsViewlet';
|
|
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
|
import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
|
import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
|
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
|
import { KeymapExtensions } from 'vs/workbench/contrib/extensions/common/extensionsUtils';
|
|
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
|
import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor';
|
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
|
import { ExtensionActivationProgress } from 'vs/workbench/contrib/extensions/browser/extensionsActivationProgress';
|
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
|
import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/browser/extensionsDependencyChecker';
|
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
import { IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsService } from 'vs/workbench/common/views';
|
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
|
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
|
import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
|
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
|
|
import { InstallExtensionQuickAccessProvider, ManageExtensionsQuickAccessProvider } from 'vs/workbench/contrib/extensions/browser/extensionsQuickAccess';
|
|
import { ExtensionRecommendationsService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService';
|
|
import { CONTEXT_SYNC_ENABLEMENT } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
|
import { CopyAction, CutAction, PasteAction } from 'vs/editor/contrib/clipboard/clipboard';
|
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
import { MultiCommand } from 'vs/editor/browser/editorExtensions';
|
|
import { IWebview } from 'vs/workbench/contrib/webview/browser/webview';
|
|
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService';
|
|
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
|
|
import { CATEGORIES } from 'vs/workbench/common/actions';
|
|
import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
|
|
import { ExtensionRecommendationNotificationService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService';
|
|
import { IExtensionService, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
|
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
|
import { ResourceContextKey } from 'vs/workbench/common/resources';
|
|
import { IAction } from 'vs/base/common/actions';
|
|
import { IWorkspaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
|
import { Schemas } from 'vs/base/common/network';
|
|
import { ShowRuntimeExtensionsAction } from 'vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor';
|
|
import { ExtensionEnablementWorkspaceTrustTransitionParticipant } from 'vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant';
|
|
import { clearSearchResultsIcon, configureRecommendedIcon, extensionsViewIcon, filterIcon, installWorkspaceRecommendedIcon, refreshIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
|
|
import { EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
|
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
|
import { isArray } from 'vs/base/common/types';
|
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
|
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
|
|
import { Promises } from 'vs/base/common/async';
|
|
import { EditorExtensions } from 'vs/workbench/common/editor';
|
|
import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
|
import { ExtensionsCompletionItemsProvider } from 'vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider';
|
|
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
|
import { Event } from 'vs/base/common/event';
|
|
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
|
|
|
// Singletons
|
|
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
|
registerSingleton(IExtensionRecommendationNotificationService, ExtensionRecommendationNotificationService);
|
|
registerSingleton(IExtensionRecommendationsService, ExtensionRecommendationsService);
|
|
|
|
Registry.as<IOutputChannelRegistry>(OutputExtensions.OutputChannels)
|
|
.registerChannel({ id: ExtensionsChannelId, label: ExtensionsLabel, log: false });
|
|
|
|
// Quick Access
|
|
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
|
|
ctor: ManageExtensionsQuickAccessProvider,
|
|
prefix: ManageExtensionsQuickAccessProvider.PREFIX,
|
|
placeholder: localize('manageExtensionsQuickAccessPlaceholder', "Press Enter to manage extensions."),
|
|
helpEntries: [{ description: localize('manageExtensionsHelp', "Manage Extensions"), needsEditor: false }]
|
|
});
|
|
|
|
// Editor
|
|
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
|
|
EditorPaneDescriptor.create(
|
|
ExtensionEditor,
|
|
ExtensionEditor.ID,
|
|
localize('extension', "Extension")
|
|
),
|
|
[
|
|
new SyncDescriptor(ExtensionsInput)
|
|
]);
|
|
|
|
|
|
Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(
|
|
{
|
|
id: VIEWLET_ID,
|
|
title: localize('extensions', "Extensions"),
|
|
openCommandActionDescriptor: {
|
|
id: VIEWLET_ID,
|
|
mnemonicTitle: localize({ key: 'miViewExtensions', comment: ['&& denotes a mnemonic'] }, "E&&xtensions"),
|
|
keybindings: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyX },
|
|
order: 4,
|
|
},
|
|
ctorDescriptor: new SyncDescriptor(ExtensionsViewPaneContainer),
|
|
icon: extensionsViewIcon,
|
|
order: 4,
|
|
rejectAddedViews: true,
|
|
alwaysUseContainerInfo: true,
|
|
}, ViewContainerLocation.Sidebar);
|
|
|
|
|
|
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
|
.registerConfiguration({
|
|
id: 'extensions',
|
|
order: 30,
|
|
title: localize('extensionsConfigurationTitle', "Extensions"),
|
|
type: 'object',
|
|
properties: {
|
|
'extensions.autoUpdate': {
|
|
enum: [true, 'onlyEnabledExtensions', false,],
|
|
enumItemLabels: [
|
|
localize('all', "All Extensions"),
|
|
localize('enabled', "Only Enabled Extensions"),
|
|
localize('none', "None"),
|
|
],
|
|
enumDescriptions: [
|
|
localize('extensions.autoUpdate.true', 'Download and install updates automatically for all extensions.'),
|
|
localize('extensions.autoUpdate.enabled', 'Download and install updates automatically only for enabled extensions. Disabled extensions will not be updated automatically.'),
|
|
localize('extensions.autoUpdate.false', 'Extensions are not automatically updated.'),
|
|
],
|
|
description: localize('extensions.autoUpdate', "Controls the automatic update behavior of extensions. The updates are fetched from a Microsoft online service."),
|
|
default: true,
|
|
scope: ConfigurationScope.APPLICATION,
|
|
tags: ['usesOnlineServices']
|
|
},
|
|
'extensions.autoCheckUpdates': {
|
|
type: 'boolean',
|
|
description: localize('extensionsCheckUpdates', "When enabled, automatically checks extensions for updates. If an extension has an update, it is marked as outdated in the Extensions view. The updates are fetched from a Microsoft online service."),
|
|
default: true,
|
|
scope: ConfigurationScope.APPLICATION,
|
|
tags: ['usesOnlineServices']
|
|
},
|
|
'extensions.ignoreRecommendations': {
|
|
type: 'boolean',
|
|
description: localize('extensionsIgnoreRecommendations', "When enabled, the notifications for extension recommendations will not be shown."),
|
|
default: false
|
|
},
|
|
'extensions.showRecommendationsOnlyOnDemand': {
|
|
type: 'boolean',
|
|
deprecationMessage: localize('extensionsShowRecommendationsOnlyOnDemand_Deprecated', "This setting is deprecated. Use extensions.ignoreRecommendations setting to control recommendation notifications. Use Extensions view's visibility actions to hide Recommended view by default."),
|
|
default: false,
|
|
tags: ['usesOnlineServices']
|
|
},
|
|
'extensions.closeExtensionDetailsOnViewChange': {
|
|
type: 'boolean',
|
|
description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."),
|
|
default: false
|
|
},
|
|
'extensions.confirmedUriHandlerExtensionIds': {
|
|
type: 'array',
|
|
description: localize('handleUriConfirmedExtensions', "When an extension is listed here, a confirmation prompt will not be shown when that extension handles a URI."),
|
|
default: [],
|
|
scope: ConfigurationScope.APPLICATION
|
|
},
|
|
'extensions.webWorker': {
|
|
type: ['boolean', 'string'],
|
|
enum: [true, false, 'auto'],
|
|
enumDescriptions: [
|
|
localize('extensionsWebWorker.true', "The Web Worker Extension Host will always be launched."),
|
|
localize('extensionsWebWorker.false', "The Web Worker Extension Host will never be launched."),
|
|
localize('extensionsWebWorker.auto', "The Web Worker Extension Host will be launched when a web extension needs it."),
|
|
],
|
|
description: localize('extensionsWebWorker', "Enable web worker extension host."),
|
|
default: 'auto'
|
|
},
|
|
'extensions.supportVirtualWorkspaces': {
|
|
type: 'object',
|
|
markdownDescription: localize('extensions.supportVirtualWorkspaces', "Override the virtual workspaces support of an extension."),
|
|
patternProperties: {
|
|
'([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
|
|
type: 'boolean',
|
|
default: false
|
|
}
|
|
},
|
|
default: {
|
|
'pub.name': false
|
|
}
|
|
},
|
|
[WORKSPACE_TRUST_EXTENSION_SUPPORT]: {
|
|
type: 'object',
|
|
scope: ConfigurationScope.APPLICATION,
|
|
markdownDescription: localize('extensions.supportUntrustedWorkspaces', "Override the untrusted workspace support of an extension. Extensions using `true` will always be enabled. Extensions using `limited` will always be enabled, and the extension will hide functionality that requires trust. Extensions using `false` will only be enabled only when the workspace is trusted."),
|
|
patternProperties: {
|
|
'([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$': {
|
|
type: 'object',
|
|
properties: {
|
|
'supported': {
|
|
type: ['boolean', 'string'],
|
|
enum: [true, false, 'limited'],
|
|
enumDescriptions: [
|
|
localize('extensions.supportUntrustedWorkspaces.true', "Extension will always be enabled."),
|
|
localize('extensions.supportUntrustedWorkspaces.false', "Extension will only be enabled only when the workspace is trusted."),
|
|
localize('extensions.supportUntrustedWorkspaces.limited', "Extension will always be enabled, and the extension will hide functionality requiring trust."),
|
|
],
|
|
description: localize('extensions.supportUntrustedWorkspaces.supported', "Defines the untrusted workspace support setting for the extension."),
|
|
},
|
|
'version': {
|
|
type: 'string',
|
|
description: localize('extensions.supportUntrustedWorkspaces.version', "Defines the version of the extension for which the override should be applied. If not specified, the override will be applied independent of the extension version."),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const jsonRegistry = <jsonContributionRegistry.IJSONContributionRegistry>Registry.as(jsonContributionRegistry.Extensions.JSONContribution);
|
|
jsonRegistry.registerSchema(ExtensionsConfigurationSchemaId, ExtensionsConfigurationSchema);
|
|
|
|
// Register Commands
|
|
CommandsRegistry.registerCommand('_extensions.manage', (accessor: ServicesAccessor, extensionId: string, tab?: ExtensionEditorTab) => {
|
|
const extensionService = accessor.get(IExtensionsWorkbenchService);
|
|
const extension = extensionService.local.filter(e => areSameExtensions(e.identifier, { id: extensionId }));
|
|
if (extension.length === 1) {
|
|
extensionService.open(extension[0], { tab });
|
|
}
|
|
});
|
|
|
|
CommandsRegistry.registerCommand('extension.open', async (accessor: ServicesAccessor, extensionId: string, tab?: ExtensionEditorTab) => {
|
|
const extensionService = accessor.get(IExtensionsWorkbenchService);
|
|
const commandService = accessor.get(ICommandService);
|
|
|
|
const pager = await extensionService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None);
|
|
if (pager.total === 1) {
|
|
return extensionService.open(pager.firstPage[0], { tab });
|
|
}
|
|
|
|
return commandService.executeCommand('_extensions.manage', extensionId, tab);
|
|
});
|
|
|
|
CommandsRegistry.registerCommand({
|
|
id: 'workbench.extensions.installExtension',
|
|
description: {
|
|
description: localize('workbench.extensions.installExtension.description', "Install the given extension"),
|
|
args: [
|
|
{
|
|
name: 'extensionIdOrVSIXUri',
|
|
description: localize('workbench.extensions.installExtension.arg.decription', "Extension id or VSIX resource uri"),
|
|
constraint: (value: any) => typeof value === 'string' || value instanceof URI,
|
|
},
|
|
{
|
|
name: 'options',
|
|
description: '(optional) Options for installing the extension. Object with the following properties: ' +
|
|
'`installOnlyNewlyAddedFromExtensionPackVSIX`: When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only when installing VSIX. ',
|
|
isOptional: true,
|
|
schema: {
|
|
'type': 'object',
|
|
'properties': {
|
|
'installOnlyNewlyAddedFromExtensionPackVSIX': {
|
|
'type': 'boolean',
|
|
'description': localize('workbench.extensions.installExtension.option.installOnlyNewlyAddedFromExtensionPackVSIX', "When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only while installing a VSIX."),
|
|
default: false
|
|
},
|
|
'donotSync': {
|
|
'type': 'boolean',
|
|
'description': localize('workbench.extensions.installExtension.option.donotSync', "When enabled, VS Code do not sync this extension when Settings Sync is on."),
|
|
default: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
handler: async (accessor, arg: string | UriComponents, options?: { installOnlyNewlyAddedFromExtensionPackVSIX?: boolean, donotSync?: boolean }) => {
|
|
const extensionManagementService = accessor.get(IExtensionManagementService);
|
|
const extensionGalleryService = accessor.get(IExtensionGalleryService);
|
|
try {
|
|
if (typeof arg === 'string') {
|
|
const [extension] = await extensionGalleryService.getExtensions([{ id: arg }], CancellationToken.None);
|
|
if (extension) {
|
|
await extensionManagementService.installFromGallery(extension, options?.donotSync ? { isMachineScoped: true } : undefined);
|
|
} else {
|
|
throw new Error(localize('notFound', "Extension '{0}' not found.", arg));
|
|
}
|
|
} else {
|
|
const vsix = URI.revive(arg);
|
|
await extensionManagementService.install(vsix, { installOnlyNewlyAddedFromExtensionPack: options?.installOnlyNewlyAddedFromExtensionPackVSIX });
|
|
}
|
|
} catch (e) {
|
|
onUnexpectedError(e);
|
|
throw e;
|
|
}
|
|
}
|
|
});
|
|
|
|
CommandsRegistry.registerCommand({
|
|
id: 'workbench.extensions.uninstallExtension',
|
|
description: {
|
|
description: localize('workbench.extensions.uninstallExtension.description', "Uninstall the given extension"),
|
|
args: [
|
|
{
|
|
name: localize('workbench.extensions.uninstallExtension.arg.name', "Id of the extension to uninstall"),
|
|
schema: {
|
|
'type': 'string'
|
|
}
|
|
}
|
|
]
|
|
},
|
|
handler: async (accessor, id: string) => {
|
|
if (!id) {
|
|
throw new Error(localize('id required', "Extension id required."));
|
|
}
|
|
const extensionManagementService = accessor.get(IExtensionManagementService);
|
|
const installed = await extensionManagementService.getInstalled();
|
|
const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id }));
|
|
if (!extensionToUninstall) {
|
|
throw new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-dotnettools.csharp.", id));
|
|
}
|
|
if (extensionToUninstall.isBuiltin) {
|
|
throw new Error(localize('builtin', "Extension '{0}' is a Built-in extension and cannot be installed", id));
|
|
}
|
|
|
|
try {
|
|
await extensionManagementService.uninstall(extensionToUninstall);
|
|
} catch (e) {
|
|
onUnexpectedError(e);
|
|
throw e;
|
|
}
|
|
}
|
|
});
|
|
|
|
CommandsRegistry.registerCommand({
|
|
id: 'workbench.extensions.search',
|
|
description: {
|
|
description: localize('workbench.extensions.search.description', "Search for a specific extension"),
|
|
args: [
|
|
{
|
|
name: localize('workbench.extensions.search.arg.name', "Query to use in search"),
|
|
schema: { 'type': 'string' }
|
|
}
|
|
]
|
|
},
|
|
handler: async (accessor, query: string = '') => {
|
|
const paneCompositeService = accessor.get(IPaneCompositePartService);
|
|
const viewlet = await paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true);
|
|
|
|
if (!viewlet) {
|
|
return;
|
|
}
|
|
|
|
(viewlet.getViewPaneContainer() as IExtensionsViewPaneContainer).search(query);
|
|
viewlet.focus();
|
|
}
|
|
});
|
|
|
|
function overrideActionForActiveExtensionEditorWebview(command: MultiCommand | undefined, f: (webview: IWebview) => void) {
|
|
command?.addImplementation(105, 'extensions-editor', (accessor) => {
|
|
const editorService = accessor.get(IEditorService);
|
|
const editor = editorService.activeEditorPane;
|
|
if (editor instanceof ExtensionEditor) {
|
|
if (editor.activeWebview?.isFocused) {
|
|
f(editor.activeWebview);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
overrideActionForActiveExtensionEditorWebview(CopyAction, webview => webview.copy());
|
|
overrideActionForActiveExtensionEditorWebview(CutAction, webview => webview.cut());
|
|
overrideActionForActiveExtensionEditorWebview(PasteAction, webview => webview.paste());
|
|
|
|
// Contexts
|
|
export const CONTEXT_HAS_GALLERY = new RawContextKey<boolean>('hasGallery', false);
|
|
export const CONTEXT_HAS_LOCAL_SERVER = new RawContextKey<boolean>('hasLocalServer', false);
|
|
export const CONTEXT_HAS_REMOTE_SERVER = new RawContextKey<boolean>('hasRemoteServer', false);
|
|
export const CONTEXT_HAS_WEB_SERVER = new RawContextKey<boolean>('hasWebServer', false);
|
|
|
|
async function runAction(action: IAction): Promise<void> {
|
|
try {
|
|
await action.run();
|
|
} finally {
|
|
action.dispose();
|
|
}
|
|
}
|
|
|
|
interface IExtensionActionOptions extends IAction2Options {
|
|
menuTitles?: { [id: number]: string };
|
|
run(accessor: ServicesAccessor, ...args: any[]): Promise<any>;
|
|
}
|
|
|
|
class ExtensionsContributions extends Disposable implements IWorkbenchContribution {
|
|
|
|
constructor(
|
|
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
|
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
|
|
@IContextKeyService contextKeyService: IContextKeyService,
|
|
@IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService,
|
|
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
|
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
|
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
|
@IDialogService private readonly dialogService: IDialogService,
|
|
@ICommandService private readonly commandService: ICommandService,
|
|
) {
|
|
super();
|
|
const hasGalleryContext = CONTEXT_HAS_GALLERY.bindTo(contextKeyService);
|
|
if (extensionGalleryService.isEnabled()) {
|
|
hasGalleryContext.set(true);
|
|
}
|
|
|
|
const hasLocalServerContext = CONTEXT_HAS_LOCAL_SERVER.bindTo(contextKeyService);
|
|
if (this.extensionManagementServerService.localExtensionManagementServer) {
|
|
hasLocalServerContext.set(true);
|
|
}
|
|
|
|
const hasRemoteServerContext = CONTEXT_HAS_REMOTE_SERVER.bindTo(contextKeyService);
|
|
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
|
hasRemoteServerContext.set(true);
|
|
}
|
|
|
|
const hasWebServerContext = CONTEXT_HAS_WEB_SERVER.bindTo(contextKeyService);
|
|
if (this.extensionManagementServerService.webExtensionManagementServer) {
|
|
hasWebServerContext.set(true);
|
|
}
|
|
|
|
this.registerGlobalActions();
|
|
this.registerContextMenuActions();
|
|
this.registerQuickAccessProvider();
|
|
}
|
|
|
|
private registerQuickAccessProvider(): void {
|
|
if (this.extensionManagementServerService.localExtensionManagementServer
|
|
|| this.extensionManagementServerService.remoteExtensionManagementServer
|
|
|| this.extensionManagementServerService.webExtensionManagementServer
|
|
) {
|
|
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
|
|
ctor: InstallExtensionQuickAccessProvider,
|
|
prefix: InstallExtensionQuickAccessProvider.PREFIX,
|
|
placeholder: localize('installExtensionQuickAccessPlaceholder', "Type the name of an extension to install or search."),
|
|
helpEntries: [{ description: localize('installExtensionQuickAccessHelp', "Install or Search Extensions"), needsEditor: false }]
|
|
});
|
|
}
|
|
}
|
|
|
|
// Global actions
|
|
private registerGlobalActions(): void {
|
|
this._register(MenuRegistry.appendMenuItems([{
|
|
id: MenuId.MenubarPreferencesMenu,
|
|
item: {
|
|
command: {
|
|
id: VIEWLET_ID,
|
|
title: localize({ key: 'miPreferencesExtensions', comment: ['&& denotes a mnemonic'] }, "&&Extensions")
|
|
},
|
|
group: '1_settings',
|
|
order: 4
|
|
}
|
|
}, {
|
|
id: MenuId.GlobalActivity,
|
|
item: {
|
|
command: {
|
|
id: VIEWLET_ID,
|
|
title: localize('showExtensions', "Extensions")
|
|
},
|
|
group: '2_configuration',
|
|
order: 3
|
|
}
|
|
}]));
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.installExtensions',
|
|
title: { value: localize('installExtensions', "Install Extensions"), original: 'Install Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
},
|
|
run: async (accessor: ServicesAccessor) => {
|
|
accessor.get(IViewsService).openViewContainer(VIEWLET_ID);
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showRecommendedKeymapExtensions',
|
|
title: { value: localize('showRecommendedKeymapExtensionsShort', "Keymaps"), original: 'Keymaps' },
|
|
category: PreferencesLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
}, {
|
|
id: MenuId.MenubarPreferencesMenu,
|
|
group: '2_keybindings',
|
|
order: 2
|
|
}, {
|
|
id: MenuId.GlobalActivity,
|
|
group: '2_keybindings',
|
|
order: 2
|
|
}],
|
|
menuTitles: {
|
|
[MenuId.MenubarPreferencesMenu.id]: localize({ key: 'miimportKeyboardShortcutsFrom', comment: ['&& denotes a mnemonic'] }, "&&Migrate Keyboard Shortcuts from..."),
|
|
[MenuId.GlobalActivity.id]: localize('importKeyboardShortcutsFroms', "Migrate Keyboard Shortcuts from...")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended:keymaps '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showLanguageExtensions',
|
|
title: { value: localize('showLanguageExtensionsShort', "Language Extensions"), original: 'Language Extensions' },
|
|
category: PreferencesLocalizedLabel,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended:languages '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.checkForUpdates',
|
|
title: { value: localize('checkForUpdates', "Check for Extension Updates"), original: 'Check for Extension Updates' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
}, {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: '1_updates',
|
|
order: 1
|
|
}],
|
|
run: async () => {
|
|
await this.extensionsWorkbenchService.checkForUpdates();
|
|
const outdated = this.extensionsWorkbenchService.outdated;
|
|
if (outdated.length) {
|
|
return runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@outdated '));
|
|
} else {
|
|
return this.dialogService.show(Severity.Info, localize('noUpdatesAvailable', "All extensions are up to date."));
|
|
}
|
|
}
|
|
});
|
|
|
|
const autoUpdateExtensionsSubMenu = new MenuId('autoUpdateExtensionsSubMenu');
|
|
MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, <ISubmenuItem>{
|
|
submenu: autoUpdateExtensionsSubMenu,
|
|
title: localize('configure auto updating extensions', "Auto Update Extensions"),
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: '1_updates',
|
|
order: 5,
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'configureExtensionsAutoUpdate.all',
|
|
title: localize('configureExtensionsAutoUpdate.all', "All Extensions"),
|
|
toggled: ContextKeyExpr.and(ContextKeyExpr.has(`config.${AutoUpdateConfigurationKey}`), ContextKeyExpr.notEquals(`config.${AutoUpdateConfigurationKey}`, 'onlyEnabledExtensions')),
|
|
menu: [{
|
|
id: autoUpdateExtensionsSubMenu,
|
|
order: 1,
|
|
}],
|
|
run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, true)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'configureExtensionsAutoUpdate.enabled',
|
|
title: localize('configureExtensionsAutoUpdate.enabled', "Only Enabled Extensions"),
|
|
toggled: ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlyEnabledExtensions'),
|
|
menu: [{
|
|
id: autoUpdateExtensionsSubMenu,
|
|
order: 2,
|
|
}],
|
|
run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, 'onlyEnabledExtensions')
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'configureExtensionsAutoUpdate.none',
|
|
title: localize('configureExtensionsAutoUpdate.none', "None"),
|
|
toggled: ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, false),
|
|
menu: [{
|
|
id: autoUpdateExtensionsSubMenu,
|
|
order: 3,
|
|
}],
|
|
run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, false)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.updateAllExtensions',
|
|
title: { value: localize('updateAll', "Update All Extensions"), original: 'Update All Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
precondition: HasOutdatedExtensionsContext,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
}, {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), ContextKeyExpr.or(ContextKeyExpr.has(`config.${AutoUpdateConfigurationKey}`).negate(), ContextKeyExpr.equals(`config.${AutoUpdateConfigurationKey}`, 'onlyEnabledExtensions'))),
|
|
group: '1_updates',
|
|
order: 2
|
|
}],
|
|
run: () => {
|
|
return Promise.all(this.extensionsWorkbenchService.outdated.map(async extension => {
|
|
try {
|
|
await this.extensionsWorkbenchService.install(extension);
|
|
} catch (err) {
|
|
runAction(this.instantiationService.createInstance(PromptExtensionInstallFailureAction, extension, extension.latestVersion, InstallOperation.Update, undefined, err));
|
|
}
|
|
}));
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.disableAutoUpdate',
|
|
title: { value: localize('disableAutoUpdate', "Disable Auto Update for all extensions"), original: 'Disable Auto Update for all extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
f1: true,
|
|
run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, false)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.enableAutoUpdate',
|
|
title: { value: localize('enableAutoUpdate', "Enable Auto Update for all extensions"), original: 'Enable Auto Update for all extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
f1: true,
|
|
run: (accessor: ServicesAccessor) => accessor.get(IConfigurationService).updateValue(AutoUpdateConfigurationKey, true)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.enableAll',
|
|
title: { value: localize('enableAll', "Enable All Extensions"), original: 'Enable All Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: '2_enablement',
|
|
order: 1
|
|
}],
|
|
run: async () => {
|
|
const extensionsToEnable = this.extensionsWorkbenchService.local.filter(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
|
|
if (extensionsToEnable.length) {
|
|
await this.extensionsWorkbenchService.setEnablement(extensionsToEnable, EnablementState.EnabledGlobally);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.enableAllWorkspace',
|
|
title: { value: localize('enableAllWorkspace', "Enable All Extensions for this Workspace"), original: 'Enable All Extensions for this Workspace' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('empty'), ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
},
|
|
run: async () => {
|
|
const extensionsToEnable = this.extensionsWorkbenchService.local.filter(e => !!e.local && this.extensionEnablementService.canChangeEnablement(e.local) && !this.extensionEnablementService.isEnabled(e.local));
|
|
if (extensionsToEnable.length) {
|
|
await this.extensionsWorkbenchService.setEnablement(extensionsToEnable, EnablementState.EnabledWorkspace);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.disableAll',
|
|
title: { value: localize('disableAll', "Disable All Installed Extensions"), original: 'Disable All Installed Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: '2_enablement',
|
|
order: 2
|
|
}],
|
|
run: async () => {
|
|
const extensionsToDisable = this.extensionsWorkbenchService.local.filter(e => !e.isBuiltin && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
|
|
if (extensionsToDisable.length) {
|
|
await this.extensionsWorkbenchService.setEnablement(extensionsToDisable, EnablementState.DisabledGlobally);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.disableAllWorkspace',
|
|
title: { value: localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"), original: 'Disable All Installed Extensions for this Workspace' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('empty'), ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
},
|
|
run: async () => {
|
|
const extensionsToDisable = this.extensionsWorkbenchService.local.filter(e => !e.isBuiltin && !!e.local && this.extensionEnablementService.isEnabled(e.local) && this.extensionEnablementService.canChangeEnablement(e.local));
|
|
if (extensionsToDisable.length) {
|
|
await this.extensionsWorkbenchService.setEnablement(extensionsToDisable, EnablementState.DisabledWorkspace);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID,
|
|
title: { value: localize('InstallFromVSIX', "Install from VSIX..."), original: 'Install from VSIX...' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER)
|
|
}, {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.equals('viewContainer', VIEWLET_ID), ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER)),
|
|
group: '3_install',
|
|
order: 1
|
|
}],
|
|
run: async (accessor: ServicesAccessor) => {
|
|
const fileDialogService = accessor.get(IFileDialogService);
|
|
const commandService = accessor.get(ICommandService);
|
|
const vsixPaths = await fileDialogService.showOpenDialog({
|
|
title: localize('installFromVSIX', "Install from VSIX"),
|
|
filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
|
|
canSelectFiles: true,
|
|
canSelectMany: true,
|
|
openLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
|
|
});
|
|
if (vsixPaths) {
|
|
await commandService.executeCommand(INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, vsixPaths);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID,
|
|
title: localize('installVSIX', "Install Extension VSIX"),
|
|
menu: [{
|
|
id: MenuId.ExplorerContext,
|
|
group: 'extensions',
|
|
when: ContextKeyExpr.and(ResourceContextKey.Extension.isEqualTo('.vsix'), ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER)),
|
|
}],
|
|
run: async (accessor: ServicesAccessor, resources: URI[] | URI) => {
|
|
const extensionService = accessor.get(IExtensionService);
|
|
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
|
const hostService = accessor.get(IHostService);
|
|
const notificationService = accessor.get(INotificationService);
|
|
|
|
const extensions = Array.isArray(resources) ? resources : [resources];
|
|
await Promises.settled(extensions.map(async (vsix) => await extensionsWorkbenchService.install(vsix)))
|
|
.then(async (extensions) => {
|
|
for (const extension of extensions) {
|
|
const requireReload = !(extension.local && extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
|
const message = requireReload ? localize('InstallVSIXAction.successReload', "Completed installing {0} extension from VSIX. Please reload Visual Studio Code to enable it.", extension.displayName || extension.name)
|
|
: localize('InstallVSIXAction.success', "Completed installing {0} extension from VSIX.", extension.displayName || extension.name);
|
|
const actions = requireReload ? [{
|
|
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
|
run: () => hostService.reload()
|
|
}] : [];
|
|
notificationService.prompt(
|
|
Severity.Info,
|
|
message,
|
|
actions
|
|
);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.installWebExtensionFromLocation',
|
|
title: { value: localize('installWebExtensionFromLocation', "Install Web Extension..."), original: 'Install Web Extension...' },
|
|
category: CATEGORIES.Developer,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_WEB_SERVER)
|
|
}],
|
|
run: async (accessor: ServicesAccessor) => {
|
|
const quickInputService = accessor.get(IQuickInputService);
|
|
const extensionManagementService = accessor.get(IWorkbenchExtensionManagementService);
|
|
|
|
const disposables = new DisposableStore();
|
|
const quickPick = disposables.add(quickInputService.createQuickPick());
|
|
quickPick.title = localize('installFromLocation', "Install Web Extension from Location");
|
|
quickPick.customButton = true;
|
|
quickPick.customLabel = localize('install button', "Install");
|
|
quickPick.placeholder = localize('installFromLocationPlaceHolder', "Location of the web extension");
|
|
quickPick.ignoreFocusOut = true;
|
|
disposables.add(Event.any(quickPick.onDidAccept, quickPick.onDidCustom)(() => {
|
|
quickPick.hide();
|
|
if (quickPick.value) {
|
|
extensionManagementService.installWebExtension(URI.parse(quickPick.value));
|
|
}
|
|
}));
|
|
disposables.add(quickPick.onDidHide(() => disposables.dispose()));
|
|
quickPick.show();
|
|
}
|
|
});
|
|
|
|
const extensionsFilterSubMenu = new MenuId('extensionsFilterSubMenu');
|
|
MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, <ISubmenuItem>{
|
|
submenu: extensionsFilterSubMenu,
|
|
title: localize('filterExtensions', "Filter Extensions..."),
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: 'navigation',
|
|
order: 1,
|
|
icon: filterIcon,
|
|
});
|
|
|
|
const showFeaturedExtensionsId = 'extensions.filter.featured';
|
|
this.registerExtensionAction({
|
|
id: showFeaturedExtensionsId,
|
|
title: { value: localize('showFeaturedExtensions', "Show Featured Extensions"), original: 'Show Featured Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '1_predefined',
|
|
order: 1,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('featured filter', "Featured")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@featured '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showPopularExtensions',
|
|
title: { value: localize('showPopularExtensions', "Show Popular Extensions"), original: 'Show Popular Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '1_predefined',
|
|
order: 2,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('most popular filter', "Most Popular")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@popular '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showRecommendedExtensions',
|
|
title: { value: localize('showRecommendedExtensions', "Show Recommended Extensions"), original: 'Show Recommended Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '1_predefined',
|
|
order: 2,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('most popular recommended', "Recommended")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.recentlyPublishedExtensions',
|
|
title: { value: localize('recentlyPublishedExtensions', "Show Recently Published Extensions"), original: 'Show Recently Published Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: CONTEXT_HAS_GALLERY
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '1_predefined',
|
|
order: 2,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('recently published filter', "Recently Published")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@sort:publishedDate '))
|
|
});
|
|
|
|
const extensionsCategoryFilterSubMenu = new MenuId('extensionsCategoryFilterSubMenu');
|
|
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
|
|
submenu: extensionsCategoryFilterSubMenu,
|
|
title: localize('filter by category', "Category"),
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '2_categories',
|
|
order: 1,
|
|
});
|
|
|
|
EXTENSION_CATEGORIES.map((category, index) => {
|
|
this.registerExtensionAction({
|
|
id: `extensions.actions.searchByCategory.${category}`,
|
|
title: category,
|
|
menu: [{
|
|
id: extensionsCategoryFilterSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
order: index,
|
|
}],
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, `@category:"${category.toLowerCase()}"`))
|
|
});
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.listBuiltInExtensions',
|
|
title: { value: localize('showBuiltInExtensions', "Show Built-in Extensions"), original: 'Show Built-in Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 1,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('builtin filter', "Built-in")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@builtin '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID,
|
|
title: { value: localize('showWorkspaceUnsupportedExtensions', "Show Extensions Unsupported By Workspace"), original: 'Show Extensions Unsupported By Workspace' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER),
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 6,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER),
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('workspace unsupported filter', "Workspace Unsupported")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@workspaceUnsupported'))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showInstalledExtensions',
|
|
title: { value: localize('showInstalledExtensions', "Show Installed Extensions"), original: 'Show Installed Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 2,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('installed filter', "Installed")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@installed '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showEnabledExtensions',
|
|
title: { value: localize('showEnabledExtensions', "Show Enabled Extensions"), original: 'Show Enabled Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 3,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('enabled filter', "Enabled")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@enabled '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showDisabledExtensions',
|
|
title: { value: localize('showDisabledExtensions', "Show Disabled Extensions"), original: 'Show Disabled Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER)
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 4,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('disabled filter', "Disabled")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@disabled '))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.listOutdatedExtensions',
|
|
title: { value: localize('showOutdatedExtensions', "Show Outdated Extensions"), original: 'Show Outdated Extensions' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
}, {
|
|
id: extensionsFilterSubMenu,
|
|
group: '3_installed',
|
|
order: 5,
|
|
}],
|
|
menuTitles: {
|
|
[extensionsFilterSubMenu.id]: localize('outdated filter', "Outdated")
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@outdated '))
|
|
});
|
|
|
|
const extensionsSortSubMenu = new MenuId('extensionsSortSubMenu');
|
|
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
|
|
submenu: extensionsSortSubMenu,
|
|
title: localize('sorty by', "Sort By"),
|
|
when: CONTEXT_HAS_GALLERY,
|
|
group: '4_sort',
|
|
order: 1,
|
|
});
|
|
|
|
[
|
|
{ id: 'installs', title: localize('sort by installs', "Install Count") },
|
|
{ id: 'rating', title: localize('sort by rating', "Rating") },
|
|
{ id: 'name', title: localize('sort by name', "Name") },
|
|
{ id: 'publishedDate', title: localize('sort by date', "Published Date") },
|
|
].map(({ id, title }, index) => {
|
|
this.registerExtensionAction({
|
|
id: `extensions.sort.${id}`,
|
|
title,
|
|
precondition: DefaultViewsContext.toNegated(),
|
|
menu: [{
|
|
id: extensionsSortSubMenu,
|
|
when: CONTEXT_HAS_GALLERY,
|
|
order: index,
|
|
}],
|
|
toggled: ExtensionsSortByContext.isEqualTo(id),
|
|
run: async () => {
|
|
const viewlet = await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true);
|
|
const extensionsViewPaneContainer = viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer;
|
|
const currentQuery = Query.parse(extensionsViewPaneContainer.searchValue || '');
|
|
extensionsViewPaneContainer.search(new Query(currentQuery.value, id, currentQuery.groupBy).toString());
|
|
extensionsViewPaneContainer.focus();
|
|
}
|
|
});
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.clearExtensionsSearchResults',
|
|
title: { value: localize('clearExtensionsSearchResults', "Clear Extensions Search Results"), original: 'Clear Extensions Search Results' },
|
|
category: ExtensionsLocalizedLabel,
|
|
icon: clearSearchResultsIcon,
|
|
f1: true,
|
|
precondition: DefaultViewsContext.toNegated(),
|
|
menu: {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: 'navigation',
|
|
order: 3,
|
|
},
|
|
run: async (accessor: ServicesAccessor) => {
|
|
const viewPaneContainer = accessor.get(IViewsService).getActiveViewPaneContainerWithId(VIEWLET_ID);
|
|
if (viewPaneContainer) {
|
|
const extensionsViewPaneContainer = viewPaneContainer as IExtensionsViewPaneContainer;
|
|
extensionsViewPaneContainer.search('');
|
|
extensionsViewPaneContainer.focus();
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.refreshExtension',
|
|
title: { value: localize('refreshExtension', "Refresh"), original: 'Refresh' },
|
|
category: ExtensionsLocalizedLabel,
|
|
icon: refreshIcon,
|
|
f1: true,
|
|
menu: {
|
|
id: MenuId.ViewContainerTitle,
|
|
when: ContextKeyExpr.equals('viewContainer', VIEWLET_ID),
|
|
group: 'navigation',
|
|
order: 2
|
|
},
|
|
run: async (accessor: ServicesAccessor) => {
|
|
const viewPaneContainer = accessor.get(IViewsService).getActiveViewPaneContainerWithId(VIEWLET_ID);
|
|
if (viewPaneContainer) {
|
|
await (viewPaneContainer as IExtensionsViewPaneContainer).refresh();
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.installWorkspaceRecommendedExtensions',
|
|
title: localize('installWorkspaceRecommendedExtensions', "Install Workspace Recommended Extensions"),
|
|
icon: installWorkspaceRecommendedIcon,
|
|
menu: {
|
|
id: MenuId.ViewTitle,
|
|
when: ContextKeyExpr.equals('view', WORKSPACE_RECOMMENDATIONS_VIEW_ID),
|
|
group: 'navigation',
|
|
order: 1
|
|
},
|
|
run: async (accessor: ServicesAccessor) => {
|
|
const view = accessor.get(IViewsService).getActiveViewWithId(WORKSPACE_RECOMMENDATIONS_VIEW_ID) as IWorkspaceRecommendedExtensionsView;
|
|
return view.installWorkspaceRecommendations();
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: ConfigureWorkspaceFolderRecommendedExtensionsAction.ID,
|
|
title: ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL,
|
|
icon: configureRecommendedIcon,
|
|
menu: [{
|
|
id: MenuId.CommandPalette,
|
|
when: WorkbenchStateContext.notEqualsTo('empty'),
|
|
}, {
|
|
id: MenuId.ViewTitle,
|
|
when: ContextKeyExpr.equals('view', WORKSPACE_RECOMMENDATIONS_VIEW_ID),
|
|
group: 'navigation',
|
|
order: 2
|
|
}],
|
|
run: () => runAction(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: InstallSpecificVersionOfExtensionAction.ID,
|
|
title: { value: InstallSpecificVersionOfExtensionAction.LABEL, original: 'Install Specific Version of Extension...' },
|
|
category: ExtensionsLocalizedLabel,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER))
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(InstallSpecificVersionOfExtensionAction, InstallSpecificVersionOfExtensionAction.ID, InstallSpecificVersionOfExtensionAction.LABEL))
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: ReinstallAction.ID,
|
|
title: { value: ReinstallAction.LABEL, original: 'Reinstall Extension...' },
|
|
category: CATEGORIES.Developer,
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(CONTEXT_HAS_GALLERY, ContextKeyExpr.or(CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER))
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(ReinstallAction, ReinstallAction.ID, ReinstallAction.LABEL))
|
|
});
|
|
}
|
|
|
|
// Extension Context Menu
|
|
private registerContextMenuActions(): void {
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showPreReleaseVersion',
|
|
title: { value: localize('show pre-release version', "Show Pre-release Version"), original: 'Show Pre-release Version' },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '0_install',
|
|
order: 0,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('showPreReleaseVersion'))
|
|
},
|
|
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
|
const extension = (await extensionWorkbenchService.queryGallery({ names: [extensionId] }, CancellationToken.None)).firstPage[0];
|
|
extensionWorkbenchService.open(extension, { showPreReleaseVersion: true });
|
|
}
|
|
});
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.showReleasedVersion',
|
|
title: { value: localize('show released version', "Show Released Version"), original: 'Show Released Version' },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '0_install',
|
|
order: 1,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.has('inExtensionEditor'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.has('showPreReleaseVersion'))
|
|
},
|
|
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
|
const extension = (await extensionWorkbenchService.queryGallery({ names: [extensionId] }, CancellationToken.None)).firstPage[0];
|
|
extensionWorkbenchService.open(extension, { showPreReleaseVersion: false });
|
|
}
|
|
});
|
|
this.registerExtensionAction({
|
|
id: SwitchToPreReleaseVersionAction.ID,
|
|
title: SwitchToPreReleaseVersionAction.TITLE,
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '0_install',
|
|
order: 2,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.not('installedExtensionIsPreReleaseVersion'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('inExtensionEditor'), ContextKeyExpr.equals('extensionStatus', 'installed'))
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => {
|
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
|
const extension = extensionWorkbenchService.local.find(e => areSameExtensions(e.identifier, { id }));
|
|
if (extension) {
|
|
await extensionWorkbenchService.install(extension, { installPreReleaseVersion: true });
|
|
}
|
|
}
|
|
});
|
|
this.registerExtensionAction({
|
|
id: SwitchToReleasedVersionAction.ID,
|
|
title: SwitchToReleasedVersionAction.TITLE,
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '0_install',
|
|
order: 3,
|
|
when: ContextKeyExpr.and(ContextKeyExpr.has('installedExtensionIsPreReleaseVersion'), ContextKeyExpr.has('extensionHasPreReleaseVersion'), ContextKeyExpr.not('inExtensionEditor'), ContextKeyExpr.equals('extensionStatus', 'installed'))
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => {
|
|
const extensionWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
|
const extension = extensionWorkbenchService.local.find(e => areSameExtensions(e.identifier, { id }));
|
|
if (extension) {
|
|
await extensionWorkbenchService.install(extension, { installPreReleaseVersion: false });
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.copyExtension',
|
|
title: { value: localize('workbench.extensions.action.copyExtension', "Copy"), original: 'Copy' },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '1_copy'
|
|
},
|
|
run: async (accessor: ServicesAccessor, extensionId: string) => {
|
|
const clipboardService = accessor.get(IClipboardService);
|
|
let extension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, { id: extensionId }))[0]
|
|
|| (await this.extensionsWorkbenchService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None)).firstPage[0];
|
|
if (extension) {
|
|
const name = localize('extensionInfoName', 'Name: {0}', extension.displayName);
|
|
const id = localize('extensionInfoId', 'Id: {0}', extensionId);
|
|
const description = localize('extensionInfoDescription', 'Description: {0}', extension.description);
|
|
const verision = localize('extensionInfoVersion', 'Version: {0}', extension.version);
|
|
const publisher = localize('extensionInfoPublisher', 'Publisher: {0}', extension.publisherDisplayName);
|
|
const link = extension.url ? localize('extensionInfoVSMarketplaceLink', 'VS Marketplace Link: {0}', `${extension.url}`) : null;
|
|
const clipboardStr = `${name}\n${id}\n${description}\n${verision}\n${publisher}${link ? '\n' + link : ''}`;
|
|
await clipboardService.writeText(clipboardStr);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.copyExtensionId',
|
|
title: { value: localize('workbench.extensions.action.copyExtensionId', "Copy Extension ID"), original: 'Copy Extension ID' },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '1_copy'
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => accessor.get(IClipboardService).writeText(id)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.configure',
|
|
title: { value: localize('workbench.extensions.action.configure', "Extension Settings"), original: 'Extension Settings' },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '2_configure',
|
|
when: ContextKeyExpr.and(ContextKeyExpr.equals('extensionStatus', 'installed'), ContextKeyExpr.has('extensionHasConfiguration'))
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => accessor.get(IPreferencesService).openSettings({ jsonEditor: false, query: `@ext:${id}` })
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: TOGGLE_IGNORE_EXTENSION_ACTION_ID,
|
|
title: { value: localize('workbench.extensions.action.toggleIgnoreExtension', "Sync This Extension"), original: `Sync This Extension` },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '2_configure',
|
|
when: ContextKeyExpr.and(CONTEXT_SYNC_ENABLEMENT, ContextKeyExpr.has('inExtensionEditor').negate())
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => {
|
|
const extension = this.extensionsWorkbenchService.local.find(e => areSameExtensions({ id }, e.identifier));
|
|
if (extension) {
|
|
return this.extensionsWorkbenchService.toggleExtensionIgnoredToSync(extension);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.ignoreRecommendation',
|
|
title: { value: localize('workbench.extensions.action.ignoreRecommendation', "Ignore Recommendation"), original: `Ignore Recommendation` },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '3_recommendations',
|
|
when: ContextKeyExpr.has('isExtensionRecommended'),
|
|
order: 1
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => accessor.get(IExtensionIgnoredRecommendationsService).toggleGlobalIgnoredRecommendation(id, true)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.undoIgnoredRecommendation',
|
|
title: { value: localize('workbench.extensions.action.undoIgnoredRecommendation', "Undo Ignored Recommendation"), original: `Undo Ignored Recommendation` },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '3_recommendations',
|
|
when: ContextKeyExpr.has('isUserIgnoredRecommendation'),
|
|
order: 1
|
|
},
|
|
run: async (accessor: ServicesAccessor, id: string) => accessor.get(IExtensionIgnoredRecommendationsService).toggleGlobalIgnoredRecommendation(id, false)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.addExtensionToWorkspaceRecommendations',
|
|
title: { value: localize('workbench.extensions.action.addExtensionToWorkspaceRecommendations', "Add to Workspace Recommendations"), original: `Add to Workspace Recommendations` },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '3_recommendations',
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('empty'), ContextKeyExpr.has('isBuiltinExtension').negate(), ContextKeyExpr.has('isExtensionWorkspaceRecommended').negate(), ContextKeyExpr.has('isUserIgnoredRecommendation').negate()),
|
|
order: 2
|
|
},
|
|
run: (accessor: ServicesAccessor, id: string) => accessor.get(IWorkspaceExtensionsConfigService).toggleRecommendation(id)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.removeExtensionFromWorkspaceRecommendations',
|
|
title: { value: localize('workbench.extensions.action.removeExtensionFromWorkspaceRecommendations', "Remove from Workspace Recommendations"), original: `Remove from Workspace Recommendations` },
|
|
menu: {
|
|
id: MenuId.ExtensionContext,
|
|
group: '3_recommendations',
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('empty'), ContextKeyExpr.has('isBuiltinExtension').negate(), ContextKeyExpr.has('isExtensionWorkspaceRecommended')),
|
|
order: 2
|
|
},
|
|
run: (accessor: ServicesAccessor, id: string) => accessor.get(IWorkspaceExtensionsConfigService).toggleRecommendation(id)
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.addToWorkspaceRecommendations',
|
|
title: { value: localize('workbench.extensions.action.addToWorkspaceRecommendations', "Add Extension to Workspace Recommendations"), original: `Add Extension to Workspace Recommendations` },
|
|
category: localize('extensions', "Extensions"),
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), ContextKeyExpr.equals('resourceScheme', Schemas.extension)),
|
|
},
|
|
async run(accessor: ServicesAccessor): Promise<any> {
|
|
const editorService = accessor.get(IEditorService);
|
|
const workspaceExtensionsConfigService = accessor.get(IWorkspaceExtensionsConfigService);
|
|
if (!(editorService.activeEditor instanceof ExtensionsInput)) {
|
|
return;
|
|
}
|
|
const extensionId = editorService.activeEditor.extension.identifier.id.toLowerCase();
|
|
const recommendations = await workspaceExtensionsConfigService.getRecommendations();
|
|
if (recommendations.includes(extensionId)) {
|
|
return;
|
|
}
|
|
await workspaceExtensionsConfigService.toggleRecommendation(extensionId);
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.addToWorkspaceFolderRecommendations',
|
|
title: { value: localize('workbench.extensions.action.addToWorkspaceFolderRecommendations', "Add Extension to Workspace Folder Recommendations"), original: `Add Extension to Workspace Folder Recommendations` },
|
|
category: localize('extensions', "Extensions"),
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('folder'), ContextKeyExpr.equals('resourceScheme', Schemas.extension)),
|
|
},
|
|
run: () => this.commandService.executeCommand('workbench.extensions.action.addToWorkspaceRecommendations')
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.addToWorkspaceIgnoredRecommendations',
|
|
title: { value: localize('workbench.extensions.action.addToWorkspaceIgnoredRecommendations', "Add Extension to Workspace Ignored Recommendations"), original: `Add Extension to Workspace Ignored Recommendations` },
|
|
category: localize('extensions', "Extensions"),
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), ContextKeyExpr.equals('resourceScheme', Schemas.extension)),
|
|
},
|
|
async run(accessor: ServicesAccessor): Promise<any> {
|
|
const editorService = accessor.get(IEditorService);
|
|
const workspaceExtensionsConfigService = accessor.get(IWorkspaceExtensionsConfigService);
|
|
if (!(editorService.activeEditor instanceof ExtensionsInput)) {
|
|
return;
|
|
}
|
|
const extensionId = editorService.activeEditor.extension.identifier.id.toLowerCase();
|
|
const unwantedRecommendations = await workspaceExtensionsConfigService.getUnwantedRecommendations();
|
|
if (unwantedRecommendations.includes(extensionId)) {
|
|
return;
|
|
}
|
|
await workspaceExtensionsConfigService.toggleUnwantedRecommendation(extensionId);
|
|
}
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: 'workbench.extensions.action.addToWorkspaceFolderIgnoredRecommendations',
|
|
title: { value: localize('workbench.extensions.action.addToWorkspaceFolderIgnoredRecommendations', "Add Extension to Workspace Folder Ignored Recommendations"), original: `Add Extension to Workspace Folder Ignored Recommendations` },
|
|
category: localize('extensions', "Extensions"),
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('folder'), ContextKeyExpr.equals('resourceScheme', Schemas.extension)),
|
|
},
|
|
run: () => this.commandService.executeCommand('workbench.extensions.action.addToWorkspaceIgnoredRecommendations')
|
|
});
|
|
|
|
this.registerExtensionAction({
|
|
id: ConfigureWorkspaceRecommendedExtensionsAction.ID,
|
|
title: { value: ConfigureWorkspaceRecommendedExtensionsAction.LABEL, original: 'Configure Recommended Extensions (Workspace)' },
|
|
category: localize('extensions', "Extensions"),
|
|
menu: {
|
|
id: MenuId.CommandPalette,
|
|
when: WorkbenchStateContext.isEqualTo('workspace'),
|
|
},
|
|
run: () => runAction(this.instantiationService.createInstance(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL))
|
|
});
|
|
|
|
}
|
|
|
|
private registerExtensionAction(extensionActionOptions: IExtensionActionOptions): IDisposable {
|
|
const menus = extensionActionOptions.menu ? isArray(extensionActionOptions.menu) ? extensionActionOptions.menu : [extensionActionOptions.menu] : [];
|
|
let menusWithOutTitles: ({ id: MenuId } & Omit<IMenuItem, 'command'>)[] = [];
|
|
const menusWithTitles: { id: MenuId, item: IMenuItem }[] = [];
|
|
if (extensionActionOptions.menuTitles) {
|
|
for (let index = 0; index < menus.length; index++) {
|
|
const menu = menus[index];
|
|
const menuTitle = extensionActionOptions.menuTitles[menu.id.id];
|
|
if (menuTitle) {
|
|
menusWithTitles.push({ id: menu.id, item: { ...menu, command: { id: extensionActionOptions.id, title: menuTitle } } });
|
|
} else {
|
|
menusWithOutTitles.push(menu);
|
|
}
|
|
}
|
|
} else {
|
|
menusWithOutTitles = menus;
|
|
}
|
|
const disposables = new DisposableStore();
|
|
disposables.add(registerAction2(class extends Action2 {
|
|
constructor() {
|
|
super({
|
|
...extensionActionOptions,
|
|
menu: menusWithOutTitles
|
|
});
|
|
}
|
|
run(accessor: ServicesAccessor, ...args: any[]): Promise<any> {
|
|
return extensionActionOptions.run(accessor, ...args);
|
|
}
|
|
}));
|
|
if (menusWithTitles.length) {
|
|
disposables.add(MenuRegistry.appendMenuItems(menusWithTitles));
|
|
}
|
|
return disposables;
|
|
}
|
|
|
|
}
|
|
|
|
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
|
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
|
|
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
|
|
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrustTransitionParticipant, LifecyclePhase.Restored);
|
|
workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, LifecyclePhase.Restored);
|
|
|
|
// Running Extensions
|
|
registerAction2(ShowRuntimeExtensionsAction);
|