Fix #110121
This commit is contained in:
parent
23579d815f
commit
294406d7a1
9 changed files with 487 additions and 447 deletions
|
@ -365,6 +365,10 @@
|
|||
{
|
||||
"name": "vs/workbench/services/authentication",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/extensionRecommendations",
|
||||
"project": "vscode-workbench"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||
})
|
||||
]);
|
||||
|
||||
this._register(this.extensionRecommendationsManagementService.onDidChangeIgnoredRecommendations(() => this._onDidChangeRecommendations.fire()));
|
||||
this._register(Event.any(this.workspaceRecommendations.onDidChangeRecommendations, this.configBasedRecommendations.onDidChangeRecommendations, this.extensionRecommendationsManagementService.onDidChangeIgnoredRecommendations)(() => this._onDidChangeRecommendations.fire()));
|
||||
this._register(this.extensionRecommendationsManagementService.onDidChangeGlobalIgnoredRecommendation(({ extensionId, isRecommended }) => {
|
||||
if (!isRecommended) {
|
||||
const reason = this.getAllRecommendationsWithReason()[extensionId];
|
||||
|
@ -111,7 +111,6 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
|
|||
}));
|
||||
|
||||
await this.promptWorkspaceRecommendations();
|
||||
this._register(Event.any(this.workspaceRecommendations.onDidChangeRecommendations, this.configBasedRecommendations.onDidChangeRecommendations)(() => this.promptWorkspaceRecommendations()));
|
||||
}
|
||||
|
||||
private isEnabled(): boolean {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/acti
|
|||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ExtensionsLabel, ExtensionsLocalizedLabel, ExtensionsChannelId, IExtensionManagementService, IExtensionGalleryService, PreferencesLocalizedLabel } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
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';
|
||||
|
@ -18,7 +18,7 @@ import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer,
|
|||
import {
|
||||
OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction,
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction,
|
||||
EnableAllAction, EnableAllWorkspaceAction, DisableAllAction, DisableAllWorkspaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction, ClearExtensionsSearchResultsAction
|
||||
EnableAllAction, EnableAllWorkspaceAction, DisableAllAction, DisableAllWorkspaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction, ClearExtensionsSearchResultsAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction
|
||||
} 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';
|
||||
|
@ -26,7 +26,7 @@ import { StatusUpdater, MaliciousExtensionChecker, ExtensionsViewletViewsContrib
|
|||
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 } from 'vs/platform/commands/common/commands';
|
||||
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';
|
||||
|
@ -62,6 +62,8 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
|
|||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { ResourceContextKey } from 'vs/workbench/common/resources';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IWorkpsaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
// Singletons
|
||||
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
||||
|
@ -929,6 +931,220 @@ class ExtensionsContributions implements IWorkbenchContribution {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, id: string): Promise<any> {
|
||||
accessor.get(IExtensionIgnoredRecommendationsService).toggleGlobalIgnoredRecommendation(id, true);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, id: string): Promise<any> {
|
||||
accessor.get(IExtensionIgnoredRecommendationsService).toggleGlobalIgnoredRecommendation(id, false);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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): Promise<any> {
|
||||
return accessor.get(IWorkpsaceExtensionsConfigService).toggleRecommendation(id);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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): Promise<any> {
|
||||
return accessor.get(IWorkpsaceExtensionsConfigService).toggleRecommendation(id);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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 workpsaceExtensionsConfigService = accessor.get(IWorkpsaceExtensionsConfigService);
|
||||
if (!(editorService.activeEditor instanceof ExtensionsInput)) {
|
||||
return;
|
||||
}
|
||||
const extensionId = editorService.activeEditor.extension.identifier.id.toLowerCase();
|
||||
const recommendations = await workpsaceExtensionsConfigService.getRecommendations();
|
||||
if (recommendations.includes(extensionId)) {
|
||||
return;
|
||||
}
|
||||
await workpsaceExtensionsConfigService.toggleRecommendation(extensionId);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<any> {
|
||||
return accessor.get(ICommandService).executeCommand('workbench.extensions.action.addToWorkspaceRecommendations');
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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 workpsaceExtensionsConfigService = accessor.get(IWorkpsaceExtensionsConfigService);
|
||||
if (!(editorService.activeEditor instanceof ExtensionsInput)) {
|
||||
return;
|
||||
}
|
||||
const extensionId = editorService.activeEditor.extension.identifier.id.toLowerCase();
|
||||
const unwatedRecommendations = await workpsaceExtensionsConfigService.getUnwantedRecommendations();
|
||||
if (unwatedRecommendations.includes(extensionId)) {
|
||||
return;
|
||||
}
|
||||
await workpsaceExtensionsConfigService.toggleUnwantedRecommendation(extensionId);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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(accessor: ServicesAccessor): Promise<any> {
|
||||
return accessor.get(ICommandService).executeCommand('workbench.extensions.action.addToWorkspaceIgnoredRecommendations');
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
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(accessor: ServicesAccessor): Promise<any> {
|
||||
return accessor.get(IInstantiationService).createInstance(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL).run();
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ConfigureWorkspaceFolderRecommendedExtensionsAction.ID,
|
||||
title: { value: ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL, original: 'Configure Recommended Extensions (Workspace Folder)' },
|
||||
category: localize('extensions', "Extensions"),
|
||||
menu: {
|
||||
id: MenuId.CommandPalette,
|
||||
when: WorkbenchStateContext.notEqualsTo('empty'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
run(accessor: ServicesAccessor): Promise<any> {
|
||||
return accessor.get(IInstantiationService).createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL).run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -936,7 +1152,6 @@ const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(Workbench
|
|||
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
||||
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
|
||||
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
|
||||
workbenchRegistry.registerWorkbenchContribution(ConfigureRecommendedExtensionsCommandsContributor, LifecyclePhase.Eventually);
|
||||
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
|
||||
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting);
|
||||
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);
|
||||
|
|
|
@ -11,12 +11,12 @@ import * as DOM from 'vs/base/browser/dom';
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import * as json from 'vs/base/common/json';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
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';
|
||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||
import { IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, INSTALL_ERROR_NOT_SUPPORTED, InstallOptions, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionIgnoredRecommendationsService, IExtensionsConfigContent } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { ExtensionRecommendationReason, IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -36,16 +36,14 @@ import { Color } from 'vs/base/common/color';
|
|||
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';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuRegistry, MenuId, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { IQuickPickItem, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
|
@ -61,7 +59,7 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/
|
|||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IViewsService } from 'vs/workbench/common/views';
|
||||
import { IActionViewItemOptions, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { EXTENSIONS_CONFIG } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
||||
import { EXTENSIONS_CONFIG, IExtensionsConfigContent } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
||||
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { ActionWithDropdownActionViewItem, IActionWithDropdownActionViewItemOptions } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';
|
||||
|
@ -834,29 +832,37 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
|
|||
}
|
||||
}
|
||||
|
||||
export function getContextMenuActions(menuService: IMenuService, contextKeyService: IContextKeyService, instantiationService: IInstantiationService, extension: IExtension | undefined | null): IAction[][] {
|
||||
const scopedContextKeyService = contextKeyService.createScoped();
|
||||
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);
|
||||
if (extension.state === ExtensionState.Installed) {
|
||||
scopedContextKeyService.createKey<string>('extensionStatus', 'installed');
|
||||
export function getContextMenuActions(extension: IExtension | undefined | null, instantiationService: IInstantiationService): IAction[][] {
|
||||
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()));
|
||||
if (extension.state === ExtensionState.Installed) {
|
||||
scopedContextKeyService.createKey<string>('extensionStatus', 'installed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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();
|
||||
|
||||
return groups;
|
||||
return groups;
|
||||
});
|
||||
}
|
||||
|
||||
export class ManageExtensionAction extends ExtensionDropDownAction {
|
||||
|
@ -870,8 +876,6 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
|||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
|
||||
super(ManageExtensionAction.ID, '', '', true, true, instantiationService);
|
||||
|
@ -911,7 +915,7 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
|||
groups.push([this.instantiationService.createInstance(UninstallAction)]);
|
||||
groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]);
|
||||
|
||||
getContextMenuActions(this.menuService, this.contextKeyService, this.instantiationService, this.extension).forEach(actions => groups.push(actions));
|
||||
getContextMenuActions(this.extension, this.instantiationService).forEach(actions => groups.push(actions));
|
||||
|
||||
groups.forEach(group => group.forEach(extensionAction => {
|
||||
if (extensionAction instanceof ExtensionAction) {
|
||||
|
@ -2134,124 +2138,6 @@ export class ChangeSortAction extends Action {
|
|||
}
|
||||
}
|
||||
|
||||
export class ConfigureRecommendedExtensionsCommandsContributor extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private workspaceContextKey = new RawContextKey<boolean>('workspaceRecommendations', true);
|
||||
private workspaceFolderContextKey = new RawContextKey<boolean>('workspaceFolderRecommendations', true);
|
||||
private addToWorkspaceRecommendationsContextKey = new RawContextKey<boolean>('addToWorkspaceRecommendations', false);
|
||||
private addToWorkspaceFolderRecommendationsContextKey = new RawContextKey<boolean>('addToWorkspaceFolderRecommendations', false);
|
||||
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService
|
||||
) {
|
||||
super();
|
||||
const boundWorkspaceContextKey = this.workspaceContextKey.bindTo(contextKeyService);
|
||||
boundWorkspaceContextKey.set(workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE);
|
||||
this._register(workspaceContextService.onDidChangeWorkbenchState(() => boundWorkspaceContextKey.set(workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));
|
||||
|
||||
const boundWorkspaceFolderContextKey = this.workspaceFolderContextKey.bindTo(contextKeyService);
|
||||
boundWorkspaceFolderContextKey.set(workspaceContextService.getWorkspace().folders.length > 0);
|
||||
this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => boundWorkspaceFolderContextKey.set(workspaceContextService.getWorkspace().folders.length > 0)));
|
||||
|
||||
const boundAddToWorkspaceRecommendationsContextKey = this.addToWorkspaceRecommendationsContextKey.bindTo(contextKeyService);
|
||||
boundAddToWorkspaceRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE);
|
||||
this._register(editorService.onDidActiveEditorChange(() => boundAddToWorkspaceRecommendationsContextKey.set(
|
||||
editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));
|
||||
this._register(workspaceContextService.onDidChangeWorkbenchState(() => boundAddToWorkspaceRecommendationsContextKey.set(
|
||||
editorService.activeEditor instanceof ExtensionsInput && workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE)));
|
||||
|
||||
const boundAddToWorkspaceFolderRecommendationsContextKey = this.addToWorkspaceFolderRecommendationsContextKey.bindTo(contextKeyService);
|
||||
boundAddToWorkspaceFolderRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput);
|
||||
this._register(editorService.onDidActiveEditorChange(() => boundAddToWorkspaceFolderRecommendationsContextKey.set(editorService.activeEditor instanceof ExtensionsInput)));
|
||||
|
||||
this.registerCommands();
|
||||
}
|
||||
|
||||
private registerCommands(): void {
|
||||
CommandsRegistry.registerCommand(ConfigureWorkspaceRecommendedExtensionsAction.ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService).createInstance(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL).run();
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: ConfigureWorkspaceRecommendedExtensionsAction.ID,
|
||||
title: { value: ConfigureWorkspaceRecommendedExtensionsAction.LABEL, original: 'Configure Recommended Extensions (Workspace)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.workspaceContextKey
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService).createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL).run();
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: ConfigureWorkspaceFolderRecommendedExtensionsAction.ID,
|
||||
title: { value: ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL, original: 'Configure Recommended Extensions (Workspace Folder)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.workspaceFolderContextKey
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(AddToWorkspaceRecommendationsAction.ADD_ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService)
|
||||
.createInstance(AddToWorkspaceRecommendationsAction, AddToWorkspaceRecommendationsAction.ADD_ID, AddToWorkspaceRecommendationsAction.ADD_LABEL)
|
||||
.run(AddToWorkspaceRecommendationsAction.ADD);
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: AddToWorkspaceRecommendationsAction.ADD_ID,
|
||||
title: { value: AddToWorkspaceRecommendationsAction.ADD_LABEL, original: 'Add to Recommended Extensions (Workspace)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.addToWorkspaceRecommendationsContextKey
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(AddToWorkspaceFolderRecommendationsAction.ADD_ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService)
|
||||
.createInstance(AddToWorkspaceFolderRecommendationsAction, AddToWorkspaceFolderRecommendationsAction.ADD_ID, AddToWorkspaceFolderRecommendationsAction.ADD_LABEL)
|
||||
.run(AddToWorkspaceRecommendationsAction.ADD);
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: AddToWorkspaceFolderRecommendationsAction.ADD_ID,
|
||||
title: { value: AddToWorkspaceFolderRecommendationsAction.ADD_LABEL, original: 'Extensions: Add to Recommended Extensions (Workspace Folder)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.addToWorkspaceFolderRecommendationsContextKey
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(AddToWorkspaceRecommendationsAction.IGNORE_ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService)
|
||||
.createInstance(AddToWorkspaceRecommendationsAction, AddToWorkspaceRecommendationsAction.IGNORE_ID, AddToWorkspaceRecommendationsAction.IGNORE_LABEL)
|
||||
.run(AddToWorkspaceRecommendationsAction.IGNORE);
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: AddToWorkspaceRecommendationsAction.IGNORE_ID,
|
||||
title: { value: AddToWorkspaceRecommendationsAction.IGNORE_LABEL, original: 'Extensions: Ignore Recommended Extension (Workspace)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.addToWorkspaceRecommendationsContextKey
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand(AddToWorkspaceFolderRecommendationsAction.IGNORE_ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService)
|
||||
.createInstance(AddToWorkspaceFolderRecommendationsAction, AddToWorkspaceFolderRecommendationsAction.IGNORE_ID, AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL)
|
||||
.run(AddToWorkspaceRecommendationsAction.IGNORE);
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: AddToWorkspaceFolderRecommendationsAction.IGNORE_ID,
|
||||
title: { value: AddToWorkspaceFolderRecommendationsAction.IGNORE_LABEL, original: 'Extensions: Ignore Recommended Extension (Workspace Folder)' },
|
||||
category: localize('extensions', "Extensions")
|
||||
},
|
||||
when: this.addToWorkspaceFolderRecommendationsContextKey
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractConfigureRecommendedExtensionsAction extends Action {
|
||||
|
||||
constructor(
|
||||
|
@ -2293,83 +2179,6 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||
}));
|
||||
}
|
||||
|
||||
protected addExtensionToWorkspaceConfig(workspaceConfigurationFile: URI, extensionId: string, shouldRecommend: boolean) {
|
||||
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
|
||||
.then(content => {
|
||||
const extensionIdLowerCase = extensionId.toLowerCase();
|
||||
const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value.toString()) || {})['extensions'] || {};
|
||||
let insertInto = shouldRecommend ? workspaceExtensionsConfigContent.recommendations || [] : workspaceExtensionsConfigContent.unwantedRecommendations || [];
|
||||
let removeFrom = shouldRecommend ? workspaceExtensionsConfigContent.unwantedRecommendations || [] : workspaceExtensionsConfigContent.recommendations || [];
|
||||
|
||||
if (insertInto.some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
insertInto.push(extensionId);
|
||||
removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);
|
||||
|
||||
return this.jsonEditingService.write(workspaceConfigurationFile,
|
||||
[{
|
||||
path: ['extensions'],
|
||||
value: {
|
||||
recommendations: shouldRecommend ? insertInto : removeFrom,
|
||||
unwantedRecommendations: shouldRecommend ? removeFrom : insertInto
|
||||
}
|
||||
}],
|
||||
true);
|
||||
});
|
||||
}
|
||||
|
||||
protected addExtensionToWorkspaceFolderConfig(extensionsFileResource: URI, extensionId: string, shouldRecommend: boolean): Promise<any> {
|
||||
return this.getOrCreateExtensionsFile(extensionsFileResource)
|
||||
.then(({ content }) => {
|
||||
const extensionIdLowerCase = extensionId.toLowerCase();
|
||||
const extensionsConfigContent: IExtensionsConfigContent = json.parse(content) || {};
|
||||
let insertInto = shouldRecommend ? extensionsConfigContent.recommendations || [] : extensionsConfigContent.unwantedRecommendations || [];
|
||||
let removeFrom = shouldRecommend ? extensionsConfigContent.unwantedRecommendations || [] : extensionsConfigContent.recommendations || [];
|
||||
|
||||
if (insertInto.some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
insertInto.push(extensionId);
|
||||
|
||||
let removeFromPromise: Promise<void> = Promise.resolve();
|
||||
if (removeFrom.some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);
|
||||
removeFromPromise = this.jsonEditingService.write(extensionsFileResource,
|
||||
[{
|
||||
path: shouldRecommend ? ['unwantedRecommendations'] : ['recommendations'],
|
||||
value: removeFrom
|
||||
}],
|
||||
true);
|
||||
}
|
||||
|
||||
return removeFromPromise.then(() =>
|
||||
this.jsonEditingService.write(extensionsFileResource,
|
||||
[{
|
||||
path: shouldRecommend ? ['recommendations'] : ['unwantedRecommendations'],
|
||||
value: insertInto
|
||||
}],
|
||||
true)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected getWorkspaceExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
||||
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
|
||||
.then(content => {
|
||||
return (json.parse(content.value.toString()) || {})['extensions'] || {};
|
||||
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
||||
}
|
||||
|
||||
protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
||||
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
|
||||
.then(content => {
|
||||
return (<IExtensionsConfigContent>json.parse(content.value.toString()) || {});
|
||||
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
||||
}
|
||||
|
||||
private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IFileContent> {
|
||||
return Promise.resolve(this.fileService.readFile(workspaceConfigurationFile))
|
||||
.then(content => {
|
||||
|
@ -2488,161 +2297,6 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac
|
|||
}
|
||||
}
|
||||
|
||||
export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction {
|
||||
static readonly ADD = true;
|
||||
static readonly IGNORE = false;
|
||||
static readonly ADD_ID = 'workbench.extensions.action.addToWorkspaceFolderRecommendations';
|
||||
static readonly ADD_LABEL = localize('addToWorkspaceFolderRecommendations', "Add to Recommended Extensions (Workspace Folder)");
|
||||
static readonly IGNORE_ID = 'workbench.extensions.action.addToWorkspaceFolderIgnoredRecommendations';
|
||||
static readonly IGNORE_LABEL = localize('addToWorkspaceFolderIgnoredRecommendations', "Ignore Recommended Extension (Workspace Folder)");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
}
|
||||
|
||||
run(shouldRecommend: boolean): Promise<void> {
|
||||
if (!(this.editorService.activeEditor instanceof ExtensionsInput) || !this.editorService.activeEditor.extension) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const folders = this.contextService.getWorkspace().folders;
|
||||
if (!folders || !folders.length) {
|
||||
this.notificationService.info(localize('AddToWorkspaceFolderRecommendations.noWorkspace', 'There are no workspace folders open to add recommendations.'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const extensionId = this.editorService.activeEditor.extension.identifier;
|
||||
const pickFolderPromise = folders.length === 1
|
||||
? Promise.resolve(folders[0])
|
||||
: this.commandService.executeCommand<IWorkspaceFolder>(PICK_WORKSPACE_FOLDER_COMMAND_ID);
|
||||
return Promise.resolve(pickFolderPromise)
|
||||
.then(workspaceFolder => {
|
||||
if (!workspaceFolder) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const configurationFile = workspaceFolder.toResource(EXTENSIONS_CONFIG);
|
||||
return this.getWorkspaceFolderExtensionsConfigContent(configurationFile).then(content => {
|
||||
const extensionIdLowerCase = extensionId.id.toLowerCase();
|
||||
if (shouldRecommend) {
|
||||
if ((content.recommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
this.notificationService.info(localize('AddToWorkspaceFolderRecommendations.alreadyExists', 'This extension is already present in this workspace folder\'s recommendations.'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId.id, shouldRecommend).then(() => {
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceFolderRecommendations.success', 'The extension was successfully added to this workspace folder\'s recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openExtensionsFile(configurationFile)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
|
||||
});
|
||||
}
|
||||
else {
|
||||
if ((content.unwantedRecommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
this.notificationService.info(localize('AddToWorkspaceFolderIgnoredRecommendations.alreadyExists', 'This extension is already present in this workspace folder\'s unwanted recommendations.'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId.id, shouldRecommend).then(() => {
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceFolderIgnoredRecommendations.success', 'The extension was successfully added to this workspace folder\'s unwanted recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openExtensionsFile(configurationFile)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class AddToWorkspaceRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction {
|
||||
static readonly ADD = true;
|
||||
static readonly IGNORE = false;
|
||||
static readonly ADD_ID = 'workbench.extensions.action.addToWorkspaceRecommendations';
|
||||
static readonly ADD_LABEL = localize('addToWorkspaceRecommendations', "Add to Recommended Extensions (Workspace)");
|
||||
static readonly IGNORE_ID = 'workbench.extensions.action.addToWorkspaceIgnoredRecommendations';
|
||||
static readonly IGNORE_LABEL = localize('addToWorkspaceIgnoredRecommendations', "Ignore Recommended Extension (Workspace)");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
}
|
||||
|
||||
run(shouldRecommend: boolean): Promise<void> {
|
||||
const workspaceConfig = this.contextService.getWorkspace().configuration;
|
||||
|
||||
if (!(this.editorService.activeEditor instanceof ExtensionsInput) || !this.editorService.activeEditor.extension || !workspaceConfig) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const extensionId = this.editorService.activeEditor.extension.identifier;
|
||||
|
||||
return this.getWorkspaceExtensionsConfigContent(workspaceConfig).then(content => {
|
||||
const extensionIdLowerCase = extensionId.id.toLowerCase();
|
||||
if (shouldRecommend) {
|
||||
if ((content.recommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
this.notificationService.info(localize('AddToWorkspaceRecommendations.alreadyExists', 'This extension is already present in workspace recommendations.'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId.id, shouldRecommend).then(() => {
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceRecommendations.success', 'The extension was successfully added to this workspace\'s recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
|
||||
}]);
|
||||
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
|
||||
});
|
||||
} else {
|
||||
if ((content.unwantedRecommendations || []).some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
this.notificationService.info(localize('AddToWorkspaceUnwantedRecommendations.alreadyExists', 'This extension is already present in workspace unwanted recommendations.'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId.id, shouldRecommend).then(() => {
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceUnwantedRecommendations.success', 'The extension was successfully added to this workspace\'s unwanted recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class StatusLabelAction extends Action implements IExtensionContainer {
|
||||
|
||||
private static readonly ENABLED_CLASS = `${ExtensionAction.TEXT_ACTION_CLASS} extension-status-label`;
|
||||
|
|
|
@ -44,7 +44,6 @@ import { IProductService } from 'vs/platform/product/common/productService';
|
|||
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
|
@ -112,7 +111,6 @@ export class ExtensionsListView extends ViewPane {
|
|||
@IProductService protected readonly productService: IProductService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService,
|
||||
) {
|
||||
|
@ -251,7 +249,7 @@ export class ExtensionsListView extends ViewPane {
|
|||
getActions: () => actions.slice(0, actions.length - 1)
|
||||
});
|
||||
} else if (e.element) {
|
||||
const groups = getContextMenuActions(this.menuService, this.contextKeyService.createScoped(), this.instantiationService, e.element);
|
||||
const groups = getContextMenuActions(e.element, this.instantiationService);
|
||||
groups.forEach(group => group.forEach(extensionAction => {
|
||||
if (extensionAction instanceof ExtensionAction) {
|
||||
extensionAction.extension = e.element!;
|
||||
|
@ -890,7 +888,6 @@ export class ServerExtensionsView extends ExtensionsListView {
|
|||
@IWorkbenchExtensioManagementService extensionManagementService: IWorkbenchExtensioManagementService,
|
||||
@IProductService productService: IProductService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IPreferencesService preferencesService: IPreferencesService,
|
||||
|
@ -898,7 +895,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
|||
options.server = server;
|
||||
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, tipsService,
|
||||
telemetryService, configurationService, contextService, experimentService, extensionManagementServerService, extensionManagementService, productService,
|
||||
contextKeyService, viewDescriptorService, menuService, openerService, preferencesService);
|
||||
contextKeyService, viewDescriptorService, openerService, preferencesService);
|
||||
this._register(onDidChangeTitle(title => this.updateTitle(title)));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ import { EXTENSION_IDENTIFIER_PATTERN, IExtensionGalleryService } from 'vs/platf
|
|||
import { distinct, flatten } from 'vs/base/common/arrays';
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IExtensionsConfigContent, ExtensionRecommendationReason } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IWorkpsaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
||||
import { IExtensionsConfigContent, IWorkpsaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig';
|
||||
|
||||
export class WorkspaceRecommendations extends ExtensionRecommendations {
|
||||
|
||||
|
@ -51,23 +51,28 @@ export class WorkspaceRecommendations extends ExtensionRecommendations {
|
|||
this.notificationService.warn(`The ${invalidRecommendations.length} extension(s) below, in workspace recommendations have issues:\n${message}`);
|
||||
}
|
||||
|
||||
this._recommendations = [];
|
||||
this._ignoredRecommendations = [];
|
||||
|
||||
for (const extensionsConfig of extensionsConfigs) {
|
||||
for (const unwantedRecommendation of extensionsConfig.unwantedRecommendations) {
|
||||
if (invalidRecommendations.indexOf(unwantedRecommendation) === -1) {
|
||||
this._ignoredRecommendations.push(unwantedRecommendation);
|
||||
if (extensionsConfig.unwantedRecommendations) {
|
||||
for (const unwantedRecommendation of extensionsConfig.unwantedRecommendations) {
|
||||
if (invalidRecommendations.indexOf(unwantedRecommendation) === -1) {
|
||||
this._ignoredRecommendations.push(unwantedRecommendation);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const extensionId of extensionsConfig.recommendations) {
|
||||
if (invalidRecommendations.indexOf(extensionId) === -1) {
|
||||
this._recommendations.push({
|
||||
extensionId,
|
||||
reason: {
|
||||
reasonId: ExtensionRecommendationReason.Workspace,
|
||||
reasonText: localize('workspaceRecommendation', "This extension is recommended by users of the current workspace.")
|
||||
}
|
||||
});
|
||||
if (extensionsConfig.recommendations) {
|
||||
for (const extensionId of extensionsConfig.recommendations) {
|
||||
if (invalidRecommendations.indexOf(extensionId) === -1) {
|
||||
this._recommendations.push({
|
||||
extensionId,
|
||||
reason: {
|
||||
reasonId: ExtensionRecommendationReason.Workspace,
|
||||
reasonText: localize('workspaceRecommendation', "This extension is recommended by users of the current workspace.")
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,12 +119,8 @@ export class WorkspaceRecommendations extends ExtensionRecommendations {
|
|||
}
|
||||
|
||||
private async onDidChangeExtensionsConfigs(): Promise<void> {
|
||||
const oldWorkspaceRecommended = this._recommendations;
|
||||
await this.fetch();
|
||||
// Suggest only if at least one of the newly added recommendations was not suggested before
|
||||
if (this._recommendations.some(current => oldWorkspaceRecommended.every(old => current.extensionId !== old.extensionId))) {
|
||||
this._onDidChangeRecommendations.fire();
|
||||
}
|
||||
this._onDidChangeRecommendations.fire();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -304,14 +304,14 @@ suite('ExtensionRecommendationsService Test', () => {
|
|||
}, null, '\t'));
|
||||
|
||||
const myWorkspace = testWorkspace(URI.from({ scheme: 'file', path: folderDir }));
|
||||
const fileService = new FileService(new NullLogService());
|
||||
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
|
||||
instantiationService.stub(IFileService, fileService);
|
||||
workspaceService = new TestContextService(myWorkspace);
|
||||
instantiationService.stub(IWorkspaceContextService, workspaceService);
|
||||
instantiationService.stub(IWorkpsaceExtensionsConfigService, instantiationService.createInstance(WorkspaceExtensionsConfigService));
|
||||
instantiationService.stub(IExtensionIgnoredRecommendationsService, instantiationService.createInstance(ExtensionIgnoredRecommendationsService));
|
||||
instantiationService.stub(IExtensionRecommendationNotificationService, instantiationService.createInstance(ExtensionRecommendationNotificationService));
|
||||
const fileService = new FileService(new NullLogService());
|
||||
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
|
||||
instantiationService.stub(IFileService, fileService);
|
||||
}
|
||||
|
||||
function testNoPromptForValidRecommendations(recommendations: string[]) {
|
||||
|
|
|
@ -7,11 +7,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
|||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export interface IExtensionsConfigContent {
|
||||
recommendations: string[];
|
||||
unwantedRecommendations: string[];
|
||||
}
|
||||
|
||||
export type DynamicRecommendation = 'dynamic';
|
||||
export type ConfigRecommendation = 'config';
|
||||
export type ExecutableRecommendation = 'executable';
|
||||
|
|
|
@ -3,20 +3,28 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { coalesce, distinct, flatten } from 'vs/base/common/arrays';
|
||||
import { distinct, flatten } from 'vs/base/common/arrays';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { parse } from 'vs/base/common/json';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
|
||||
import { FileKind, IFileService } from 'vs/platform/files/common/files';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IJSONEditingService, IJSONValue } from 'vs/workbench/services/configuration/common/jsonEditing';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
|
||||
export const EXTENSIONS_CONFIG = '.vscode/extensions.json';
|
||||
|
||||
export interface IExtensionsConfigContent {
|
||||
recommendations: string[];
|
||||
unwantedRecommendations: string[];
|
||||
recommendations?: string[];
|
||||
unwantedRecommendations?: string[];
|
||||
}
|
||||
|
||||
export const IWorkpsaceExtensionsConfigService = createDecorator<IWorkpsaceExtensionsConfigService>('IWorkpsaceExtensionsConfigService');
|
||||
|
@ -26,8 +34,11 @@ export interface IWorkpsaceExtensionsConfigService {
|
|||
|
||||
onDidChangeExtensionsConfigs: Event<void>;
|
||||
getExtensionsConfigs(): Promise<IExtensionsConfigContent[]>;
|
||||
getRecommendations(): Promise<string[]>;
|
||||
getUnwantedRecommendations(): Promise<string[]>;
|
||||
|
||||
toggleRecommendation(extensionId: string): Promise<void>;
|
||||
toggleUnwantedRecommendation(extensionId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export class WorkspaceExtensionsConfigService extends Disposable implements IWorkpsaceExtensionsConfigService {
|
||||
|
@ -40,53 +51,217 @@ export class WorkspaceExtensionsConfigService extends Disposable implements IWor
|
|||
constructor(
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IModeService private readonly modeService: IModeService,
|
||||
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
|
||||
) {
|
||||
super();
|
||||
this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(e => this._onDidChangeExtensionsConfigs.fire()));
|
||||
this._register(workspaceContextService.onDidChangeWorkspaceFolders(e => this._onDidChangeExtensionsConfigs.fire()));
|
||||
this._register(fileService.onDidFilesChange(e => {
|
||||
const workspace = workspaceContextService.getWorkspace();
|
||||
if ((workspace.configuration && e.affects(workspace.configuration))
|
||||
|| workspace.folders.some(folder => e.affects(folder.toResource(EXTENSIONS_CONFIG)))
|
||||
) {
|
||||
this._onDidChangeExtensionsConfigs.fire();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async getExtensionsConfigs(): Promise<IExtensionsConfigContent[]> {
|
||||
const workspace = this.workspaceContextService.getWorkspace();
|
||||
const result = await Promise.all([
|
||||
this.resolveWorkspaceExtensionConfig(workspace),
|
||||
...workspace.folders.map(workspaceFolder => this.resolveWorkspaceFolderExtensionConfig(workspaceFolder))
|
||||
]);
|
||||
return coalesce(result);
|
||||
const result: IExtensionsConfigContent[] = [];
|
||||
const workspaceExtensionsConfigContent = workspace.configuration ? await this.resolveWorkspaceExtensionConfig(workspace.configuration) : undefined;
|
||||
if (workspaceExtensionsConfigContent) {
|
||||
result.push(workspaceExtensionsConfigContent);
|
||||
}
|
||||
result.push(...await Promise.all(workspace.folders.map(workspaceFolder => this.resolveWorkspaceFolderExtensionConfig(workspaceFolder))));
|
||||
return result;
|
||||
}
|
||||
|
||||
async getRecommendations(): Promise<string[]> {
|
||||
const configs = await this.getExtensionsConfigs();
|
||||
return distinct(flatten(configs.map(c => c.recommendations ? c.recommendations.map(c => c.toLowerCase()) : [])));
|
||||
}
|
||||
|
||||
async getUnwantedRecommendations(): Promise<string[]> {
|
||||
const configs = await this.getExtensionsConfigs();
|
||||
return distinct(flatten(configs.map(c => c.unwantedRecommendations.map(c => c.toLowerCase()))));
|
||||
return distinct(flatten(configs.map(c => c.unwantedRecommendations ? c.unwantedRecommendations.map(c => c.toLowerCase()) : [])));
|
||||
}
|
||||
|
||||
private async resolveWorkspaceExtensionConfig(workspace: IWorkspace): Promise<IExtensionsConfigContent | null> {
|
||||
try {
|
||||
if (workspace.configuration) {
|
||||
const content = await this.fileService.readFile(workspace.configuration);
|
||||
const extensionsConfigContent = <IExtensionsConfigContent | undefined>parse(content.value.toString())['extensions'];
|
||||
return this.parseExtensionConfig(extensionsConfigContent);
|
||||
async toggleRecommendation(extensionId: string): Promise<void> {
|
||||
const workspace = this.workspaceContextService.getWorkspace();
|
||||
const workspaceExtensionsConfigContent = workspace.configuration ? await this.resolveWorkspaceExtensionConfig(workspace.configuration) : undefined;
|
||||
const workspaceFolderExtensionsConfigContents = new ResourceMap<IExtensionsConfigContent>();
|
||||
await Promise.all(workspace.folders.map(async workspaceFolder => {
|
||||
const extensionsConfigContent = await this.resolveWorkspaceFolderExtensionConfig(workspaceFolder);
|
||||
workspaceFolderExtensionsConfigContents.set(workspaceFolder.uri, extensionsConfigContent);
|
||||
}));
|
||||
|
||||
const isWorkspaceRecommended = workspaceExtensionsConfigContent && workspaceExtensionsConfigContent.recommendations?.some(r => r === extensionId);
|
||||
const recommendedWorksapceFolders = workspace.folders.filter(workspaceFolder => workspaceFolderExtensionsConfigContents.get(workspaceFolder.uri)?.recommendations?.some(r => r === extensionId));
|
||||
const isRecommended = isWorkspaceRecommended || recommendedWorksapceFolders.length > 0;
|
||||
|
||||
const workspaceOrFolders = isRecommended
|
||||
? await this.pickWorkspaceOrFolders(recommendedWorksapceFolders, isWorkspaceRecommended ? workspace : undefined, localize('select for remove', "Remove extension recommendation from"))
|
||||
: await this.pickWorkspaceOrFolders(workspace.folders, workspace.configuration ? workspace : undefined, localize('select for add', "Add extension recommendation to"));
|
||||
|
||||
for (const workspaceOrWorkspaceFolder of workspaceOrFolders) {
|
||||
if (IWorkspace.isIWorkspace(workspaceOrWorkspaceFolder)) {
|
||||
await this.addOrRemoveWorkspaceRecommendation(extensionId, workspaceOrWorkspaceFolder, workspaceExtensionsConfigContent, !isRecommended);
|
||||
} else {
|
||||
await this.addOrRemoveWorkspaceFolderRecommendation(extensionId, workspaceOrWorkspaceFolder, workspaceFolderExtensionsConfigContents.get(workspaceOrWorkspaceFolder.uri)!, !isRecommended);
|
||||
}
|
||||
} catch (e) { /* Ignore */ }
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveWorkspaceFolderExtensionConfig(workspaceFolder: IWorkspaceFolder): Promise<IExtensionsConfigContent | null> {
|
||||
async toggleUnwantedRecommendation(extensionId: string): Promise<void> {
|
||||
const workspace = this.workspaceContextService.getWorkspace();
|
||||
const workspaceExtensionsConfigContent = workspace.configuration ? await this.resolveWorkspaceExtensionConfig(workspace.configuration) : undefined;
|
||||
const workspaceFolderExtensionsConfigContents = new ResourceMap<IExtensionsConfigContent>();
|
||||
await Promise.all(workspace.folders.map(async workspaceFolder => {
|
||||
const extensionsConfigContent = await this.resolveWorkspaceFolderExtensionConfig(workspaceFolder);
|
||||
workspaceFolderExtensionsConfigContents.set(workspaceFolder.uri, extensionsConfigContent);
|
||||
}));
|
||||
|
||||
const isWorkspaceUnwanted = workspaceExtensionsConfigContent && workspaceExtensionsConfigContent.unwantedRecommendations?.some(r => r === extensionId);
|
||||
const unWantedWorksapceFolders = workspace.folders.filter(workspaceFolder => workspaceFolderExtensionsConfigContents.get(workspaceFolder.uri)?.unwantedRecommendations?.some(r => r === extensionId));
|
||||
const isUnwanted = isWorkspaceUnwanted || unWantedWorksapceFolders.length > 0;
|
||||
|
||||
const workspaceOrFolders = isUnwanted
|
||||
? await this.pickWorkspaceOrFolders(unWantedWorksapceFolders, isWorkspaceUnwanted ? workspace : undefined, localize('select for remove', "Remove extension recommendation from"))
|
||||
: await this.pickWorkspaceOrFolders(workspace.folders, workspace.configuration ? workspace : undefined, localize('select for add', "Add extension recommendation to"));
|
||||
|
||||
for (const workspaceOrWorkspaceFolder of workspaceOrFolders) {
|
||||
if (IWorkspace.isIWorkspace(workspaceOrWorkspaceFolder)) {
|
||||
await this.addOrRemoveWorkspaceUnwantedRecommendation(extensionId, workspaceOrWorkspaceFolder, workspaceExtensionsConfigContent, !isUnwanted);
|
||||
} else {
|
||||
await this.addOrRemoveWorkspaceFolderUnwantedRecommendation(extensionId, workspaceOrWorkspaceFolder, workspaceFolderExtensionsConfigContents.get(workspaceOrWorkspaceFolder.uri)!, !isUnwanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async addOrRemoveWorkspaceFolderRecommendation(extensionId: string, workspaceFolder: IWorkspaceFolder, extensionsConfigContent: IExtensionsConfigContent, add: boolean): Promise<void> {
|
||||
const values: IJSONValue[] = [];
|
||||
if (add) {
|
||||
values.push({ path: ['recommendations'], value: [...extensionsConfigContent.recommendations || [], extensionId] });
|
||||
if (extensionsConfigContent.unwantedRecommendations && extensionsConfigContent.unwantedRecommendations.some(e => e === extensionId)) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: extensionsConfigContent.unwantedRecommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (extensionsConfigContent.recommendations) {
|
||||
values.push({ path: ['recommendations'], value: extensionsConfigContent.recommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
|
||||
if (values.length) {
|
||||
return this.jsonEditingService.write(workspaceFolder.toResource(EXTENSIONS_CONFIG), values, true);
|
||||
}
|
||||
}
|
||||
|
||||
private async addOrRemoveWorkspaceRecommendation(extensionId: string, workspace: IWorkspace, extensionsConfigContent: IExtensionsConfigContent | undefined, add: boolean): Promise<void> {
|
||||
const values: IJSONValue[] = [];
|
||||
if (extensionsConfigContent) {
|
||||
if (add) {
|
||||
values.push({ path: ['recommendations'], value: [...extensionsConfigContent.recommendations || [], extensionId] });
|
||||
if (extensionsConfigContent.unwantedRecommendations && extensionsConfigContent.unwantedRecommendations.some(e => e === extensionId)) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: extensionsConfigContent.unwantedRecommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (extensionsConfigContent.recommendations) {
|
||||
values.push({ path: ['recommendations'], value: extensionsConfigContent.recommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (add) {
|
||||
values.push({ path: ['extensions'], value: { recommendations: [extensionId] } });
|
||||
}
|
||||
|
||||
if (values.length) {
|
||||
return this.jsonEditingService.write(workspace.configuration!, values, true);
|
||||
}
|
||||
}
|
||||
|
||||
private async addOrRemoveWorkspaceFolderUnwantedRecommendation(extensionId: string, workspaceFolder: IWorkspaceFolder, extensionsConfigContent: IExtensionsConfigContent, add: boolean): Promise<void> {
|
||||
const values: IJSONValue[] = [];
|
||||
if (add) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: [...extensionsConfigContent.unwantedRecommendations || [], extensionId] });
|
||||
if (extensionsConfigContent.recommendations && extensionsConfigContent.recommendations.some(e => e === extensionId)) {
|
||||
values.push({ path: ['recommendations'], value: extensionsConfigContent.recommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (extensionsConfigContent.unwantedRecommendations) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: extensionsConfigContent.unwantedRecommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
if (values.length) {
|
||||
return this.jsonEditingService.write(workspaceFolder.toResource(EXTENSIONS_CONFIG), values, true);
|
||||
}
|
||||
}
|
||||
|
||||
private async addOrRemoveWorkspaceUnwantedRecommendation(extensionId: string, workspace: IWorkspace, extensionsConfigContent: IExtensionsConfigContent | undefined, add: boolean): Promise<void> {
|
||||
const values: IJSONValue[] = [];
|
||||
if (extensionsConfigContent) {
|
||||
if (add) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: [...extensionsConfigContent.unwantedRecommendations || [], extensionId] });
|
||||
if (extensionsConfigContent.recommendations && extensionsConfigContent.recommendations.some(e => e === extensionId)) {
|
||||
values.push({ path: ['recommendations'], value: extensionsConfigContent.recommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (extensionsConfigContent.unwantedRecommendations) {
|
||||
values.push({ path: ['unwantedRecommendations'], value: extensionsConfigContent.unwantedRecommendations.filter(e => e !== extensionId) });
|
||||
}
|
||||
} else if (add) {
|
||||
values.push({ path: ['extensions'], value: { unwantedRecommendations: [extensionId] } });
|
||||
}
|
||||
|
||||
if (values.length) {
|
||||
return this.jsonEditingService.write(workspace.configuration!, values, true);
|
||||
}
|
||||
}
|
||||
|
||||
private async pickWorkspaceOrFolders(workspaceFolders: IWorkspaceFolder[], workspace: IWorkspace | undefined, placeHolder: string): Promise<(IWorkspace | IWorkspaceFolder)[]> {
|
||||
const workspaceOrFolders = workspace ? [...workspaceFolders, workspace] : [...workspaceFolders];
|
||||
if (workspaceOrFolders.length === 1) {
|
||||
return workspaceOrFolders;
|
||||
}
|
||||
|
||||
const folderPicks: (IQuickPickItem & { workspaceOrFolder: IWorkspace | IWorkspaceFolder } | IQuickPickSeparator)[] = workspaceFolders.map(workspaceFolder => {
|
||||
return {
|
||||
label: workspaceFolder.name,
|
||||
description: localize('workspace folder', "Workspace Folder"),
|
||||
workspaceOrFolder: workspaceFolder,
|
||||
iconClasses: getIconClasses(this.modelService, this.modeService, workspaceFolder.uri, FileKind.ROOT_FOLDER)
|
||||
};
|
||||
});
|
||||
|
||||
if (workspace) {
|
||||
folderPicks.push({ type: 'separator' });
|
||||
folderPicks.push({
|
||||
label: localize('workspace', "Workspace"),
|
||||
workspaceOrFolder: workspace,
|
||||
});
|
||||
}
|
||||
|
||||
const result = await this.quickInputService.pick(folderPicks, { placeHolder, canPickMany: true }) || [];
|
||||
return result.map(r => r.workspaceOrFolder!);
|
||||
}
|
||||
|
||||
private async resolveWorkspaceExtensionConfig(workspaceConfigurationResource: URI): Promise<IExtensionsConfigContent | undefined> {
|
||||
try {
|
||||
const content = await this.fileService.readFile(workspaceConfigurationResource);
|
||||
const extensionsConfigContent = <IExtensionsConfigContent | undefined>parse(content.value.toString())['extensions'];
|
||||
return extensionsConfigContent ? this.parseExtensionConfig(extensionsConfigContent) : undefined;
|
||||
} catch (e) { /* Ignore */ }
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async resolveWorkspaceFolderExtensionConfig(workspaceFolder: IWorkspaceFolder): Promise<IExtensionsConfigContent> {
|
||||
try {
|
||||
const content = await this.fileService.readFile(workspaceFolder.toResource(EXTENSIONS_CONFIG));
|
||||
const extensionsConfigContent = <IExtensionsConfigContent>parse(content.value.toString());
|
||||
return this.parseExtensionConfig(extensionsConfigContent);
|
||||
} catch (e) { /* ignore */ }
|
||||
return null;
|
||||
return {};
|
||||
}
|
||||
|
||||
private parseExtensionConfig(extensionsConfigContent: IExtensionsConfigContent | undefined): IExtensionsConfigContent | null {
|
||||
if (extensionsConfigContent) {
|
||||
return {
|
||||
recommendations: distinct((extensionsConfigContent.recommendations || []).map(e => e.toLowerCase())),
|
||||
unwantedRecommendations: distinct((extensionsConfigContent.unwantedRecommendations || []).map(e => e.toLowerCase()))
|
||||
};
|
||||
}
|
||||
return null;
|
||||
private parseExtensionConfig(extensionsConfigContent: IExtensionsConfigContent): IExtensionsConfigContent {
|
||||
return {
|
||||
recommendations: distinct((extensionsConfigContent.recommendations || []).map(e => e.toLowerCase())),
|
||||
unwantedRecommendations: distinct((extensionsConfigContent.unwantedRecommendations || []).map(e => e.toLowerCase()))
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue