From bf7a2338d3a8c2f41c6778adfa552d0960558883 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 22 Nov 2016 11:48:17 -0800 Subject: [PATCH] Add keymaps the top-level Preferences menu (fixes #15159) --- src/vs/code/electron-main/menus.ts | 2 + .../common/extensionEnablementService.ts | 14 +++--- .../common/extensionManagement.ts | 4 +- src/vs/platform/product.ts | 1 + .../browser/extensionTipsService.ts | 4 ++ .../extensions/browser/extensionsActions.ts | 28 +++++++++++ .../extensions.contribution.ts | 7 ++- .../electron-browser/extensionsViewlet.ts | 19 +++++++- .../node/extensionsWorkbenchService.ts | 46 +++++++++++++++++-- .../extensionsWorkbenchService.test.ts | 6 ++- .../extensions/test/extensionsActions.test.ts | 6 ++- 11 files changed, 122 insertions(+), 15 deletions(-) rename src/vs/workbench/parts/extensions/test/{node => electron-browser}/extensionsWorkbenchService.test.ts (98%) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 7484c4dc5fe..ad20e8b6cb9 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -388,6 +388,7 @@ export class VSCodeMenu { const userSettings = this.createMenuItem(nls.localize({ key: 'miOpenSettings', comment: ['&& denotes a mnemonic'] }, "&&User Settings"), 'workbench.action.openGlobalSettings'); const workspaceSettings = this.createMenuItem(nls.localize({ key: 'miOpenWorkspaceSettings', comment: ['&& denotes a mnemonic'] }, "&&Workspace Settings"), 'workbench.action.openWorkspaceSettings'); const kebindingSettings = this.createMenuItem(nls.localize({ key: 'miOpenKeymap', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts"), 'workbench.action.openGlobalKeybindings'); + const keymapExtensions = this.createMenuItem(nls.localize({ key: 'miOpenKeymapExtensions', comment: ['&& denotes a mnemonic'] }, "&&Keymaps"), 'workbench.extensions.action.showRecommendedKeymapExtensions'); const snippetsSettings = this.createMenuItem(nls.localize({ key: 'miOpenSnippets', comment: ['&& denotes a mnemonic'] }, "User &&Snippets"), 'workbench.action.openSnippets'); const colorThemeSelection = this.createMenuItem(nls.localize({ key: 'miSelectColorTheme', comment: ['&& denotes a mnemonic'] }, "&&Color Theme"), 'workbench.action.selectTheme'); const iconThemeSelection = this.createMenuItem(nls.localize({ key: 'miSelectIconTheme', comment: ['&& denotes a mnemonic'] }, "File &&Icon Theme"), 'workbench.action.selectIconTheme'); @@ -397,6 +398,7 @@ export class VSCodeMenu { preferencesMenu.append(workspaceSettings); preferencesMenu.append(__separator__()); preferencesMenu.append(kebindingSettings); + preferencesMenu.append(keymapExtensions); preferencesMenu.append(__separator__()); preferencesMenu.append(snippetsSettings); preferencesMenu.append(__separator__()); diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index 42207bc9ae7..00c29ad522f 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -93,12 +93,12 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return TPromise.wrap(false); } - private enableExtension(identifier: string, scope: StorageScope): TPromise { + private enableExtension(identifier: string, scope: StorageScope, fireEvent = true): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); const index = disabledExtensions.indexOf(identifier); if (index !== -1) { disabledExtensions.splice(index, 1); - this.setDisabledExtensions(disabledExtensions, scope, identifier); + this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); return TPromise.wrap(true); } return TPromise.wrap(false); @@ -112,20 +112,22 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return value ? distinct(value.split(',')) : []; } - private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string): void { + private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string, fireEvent = true): void { if (disabledExtensions.length) { this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions.join(','), scope); } else { this.storageService.remove(DISABLED_EXTENSIONS_STORAGE_PATH, scope); } - this._onEnablementChanged.fire(extension); + if (fireEvent) { + this._onEnablementChanged.fire(extension); + } } private onDidUninstallExtension({id, error}: DidUninstallExtensionEvent): void { if (!error) { id = stripVersion(id); - this.enableExtension(id, StorageScope.WORKSPACE); - this.enableExtension(id, StorageScope.GLOBAL); + this.enableExtension(id, StorageScope.WORKSPACE, false); + this.enableExtension(id, StorageScope.GLOBAL, false); } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 60e4f5af93a..65a9c4c8e73 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -286,7 +286,9 @@ export interface IExtensionTipsService { _serviceBrand: any; getRecommendations(): string[]; getWorkspaceRecommendations(): TPromise; + getKeymapRecommendations(): string[]; } export const ExtensionsLabel = localize('extensions', "Extensions"); -export const ExtensionsChannelId = 'extensions'; \ No newline at end of file +export const ExtensionsChannelId = 'extensions'; +export const PreferencesLabel = localize('preferences', "Preferences"); \ No newline at end of file diff --git a/src/vs/platform/product.ts b/src/vs/platform/product.ts index 78040cb6490..d7b5a292652 100644 --- a/src/vs/platform/product.ts +++ b/src/vs/platform/product.ts @@ -26,6 +26,7 @@ export interface IProductConfiguration { }; extensionTips: { [id: string]: string; }; extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; + keymapExtensionTips: string[]; crashReporter: Electron.CrashReporterStartOptions; welcomePage: string; enableTelemetry: boolean; diff --git a/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts index 25a32c65c39..8dd390481f3 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionTipsService.ts @@ -75,6 +75,10 @@ export class ExtensionTipsService implements IExtensionTipsService { return Object.keys(this._recommendations); } + getKeymapRecommendations(): string[] { + return product.keymapExtensionTips || []; + } + private _suggestTips() { const extensionTips = product.extensionTips; if (!extensionTips) { diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index b9460ee942f..bf21df60c44 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -1009,6 +1009,34 @@ export class ShowWorkspaceRecommendedExtensionsAction extends Action { } } +export class ShowRecommendedKeymapExtensionsAction extends Action { + + static ID = 'workbench.extensions.action.showRecommendedKeymapExtensions'; + static LABEL = localize('showRecommendedKeymapExtensions', "Show Recommended Keymaps"); + static SHORT_LABEL = localize('showRecommendedKeymapExtensionsShort', "Keymaps"); + + constructor( + id: string, + label: string, + @IViewletService private viewletService: IViewletService + ) { + super(id, label, null, true); + } + + run(): TPromise { + return this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search('@recommended:keymaps '); + viewlet.focus(); + }); + } + + protected isEnabled(): boolean { + return true; + } +} + export class ChangeSortAction extends Action { private query: Query; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 89cde057706..de5042685a0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -9,7 +9,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/platform'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel, ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel, ExtensionsChannelId, PreferencesLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/browser/extensionTipsService'; @@ -21,7 +21,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { VIEWLET_ID, IExtensionsWorkbenchService } from '../common/extensions'; import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { - OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, + OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, UpdateAllAction, ConfigureWorkspaceRecommendedExtensionsAction, EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; @@ -106,6 +106,9 @@ actionRegistry.registerWorkbenchAction(listOutdatedActionDescriptor, 'Extensions const recommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(recommendationsActionDescriptor, 'Extensions: Show Recommended Extensions', ExtensionsLabel); +const keymapRecommendationsActionDescriptor = new SyncActionDescriptor(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.SHORT_LABEL); +actionRegistry.registerWorkbenchAction(keymapRecommendationsActionDescriptor, 'Preferences: Keymaps', PreferencesLabel); + const workspaceRecommendationsActionDescriptor = new SyncActionDescriptor(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, ShowWorkspaceRecommendedExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(workspaceRecommendationsActionDescriptor, 'Extensions: Show Workspace Recommended Extensions', ExtensionsLabel); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 1b0329f9542..1fdf9f1ad71 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -31,7 +31,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { Delegate, Renderer } from 'vs/workbench/parts/extensions/browser/extensionsList'; import { IExtensionsWorkbenchService, IExtension, IExtensionsViewlet, VIEWLET_ID, ExtensionState } from '../common/extensions'; import { - ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, + ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { InstallVSIXAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; @@ -170,6 +170,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL), this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL), this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, ShowWorkspaceRecommendedExtensionsAction.LABEL), + this.instantiationService.createInstance(ShowRecommendedKeymapExtensionsAction, ShowRecommendedKeymapExtensionsAction.ID, ShowRecommendedKeymapExtensionsAction.LABEL), this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL), new Separator(), this.instantiationService.createInstance(ChangeSortAction, 'extensions.sort.install', localize('sort by installs', "Sort By: Install Count"), this.onSearchChange, 'installs', undefined), @@ -263,6 +264,8 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { if (/@recommended:workspace/i.test(query.value)) { return this.getWorkspaceRecommendationsModel(query, options); + } else if (/@recommended:keymaps/i.test(query.value)) { + return this.getKeymapRecommendationsModel(query, options); } else if (/@recommended/i.test(query.value)) { return this.getRecommendationsModel(query, options); } @@ -316,6 +319,20 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { }); } + private getKeymapRecommendationsModel(query: Query, options: IQueryOptions): TPromise> { + const value = query.value.replace(/@recommended:keymaps/g, '').trim().toLowerCase(); + const names = this.tipsService.getKeymapRecommendations() + .filter(name => name.toLowerCase().indexOf(value) > -1); + this.telemetryService.publicLog('extensionKeymapRecommendations:open', { count: names.length }); + + if (!names.length) { + return TPromise.as(new PagedModel([])); + } + + return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) + .then(result => new PagedModel(result)); + } + private openExtension(extension: IExtension): void { this.extensionsWorkbenchService.open(extension).done(null, err => this.onError(err)); } diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index a884dfa5045..3d9d80e2093 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -5,6 +5,7 @@ 'use strict'; +import nls = require('vs/nls'); import { readFile } from 'vs/base/node/pfs'; import * as semver from 'semver'; import * as path from 'path'; @@ -14,19 +15,19 @@ import { LinkedMap as Map } from 'vs/base/common/map'; import { assign } from 'vs/base/common/objects'; import { isUUID } from 'vs/base/common/uuid'; import { ThrottledDelayer } from 'vs/base/common/async'; -import { isPromiseCanceledError } from 'vs/base/common/errors'; +import { isPromiseCanceledError, onUnexpectedError, canceled } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, - InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService + InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionTelemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IMessageService } from 'vs/platform/message/common/message'; +import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; @@ -314,8 +315,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IMessageService private messageService: IMessageService, + @IChoiceService private choiceService: IChoiceService, @IURLService urlService: IURLService, @IExtensionEnablementService private extensionEnablementService: IExtensionEnablementService, + @IExtensionTipsService private tipsService: IExtensionTipsService, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, ) { this.stateProvider = ext => this.getExtensionState(ext); @@ -565,6 +568,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { installed.local = local; } else { this.installed.push(extension); + this.checkForOtherKeymaps(extension) + .then(null, onUnexpectedError); } } } @@ -576,6 +581,39 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { this._onChange.fire(); } + private checkForOtherKeymaps(extension: Extension): TPromise { + if (!extension.disabledGlobally && this.isKeymapExtension(extension)) { + const otherKeymaps = this.installed.filter(ext => ext.identifier !== extension.identifier && + !ext.disabledGlobally && + this.isKeymapExtension(ext)); + if (otherKeymaps.length) { + return this.promptForDisablingOtherKeymaps(otherKeymaps); + } + } + return TPromise.as(undefined); + } + + private isKeymapExtension(extension: Extension): boolean { + const cats = extension.local.manifest.categories; + return cats && cats.indexOf('Keymaps') !== -1 || this.tipsService.getKeymapRecommendations().indexOf(extension.identifier) !== -1; + } + + private promptForDisablingOtherKeymaps(keymaps: Extension[]): TPromise { + const message = nls.localize('disableOtherKeymapsConfirmation', "Disable other keymaps to avoid conflicts between keybindings?"); + const options = [ + nls.localize('yes', "Yes"), + nls.localize('no', "No") + ]; + return this.choiceService.choose(Severity.Info, message, options, false) + .then(value => { + if (value === 0) { + return TPromise.join(keymaps.map(keymap => { + return this.setEnablement(keymap, false); + })); + } + }, error => TPromise.wrapError(canceled())); + } + private onUninstallExtension(id: string): void { const extension = this.installed.filter(e => e.local.id === id)[0]; const newLength = this.installed.filter(e => e.local.id !== id).length; @@ -618,6 +656,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.identifier) !== -1; extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.identifier) !== -1; this._onChange.fire(); + this.checkForOtherKeymaps(extension) + .then(null, onUnexpectedError); } } diff --git a/src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts similarity index 98% rename from src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts rename to src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index c2973c189a1..46c9b6ce933 100644 --- a/src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -13,10 +13,11 @@ import { generateUuid } from 'vs/base/common/uuid'; import { IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/parts/extensions/common/extensions'; import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { - IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, ILocalExtension, LocalExtensionType, IGalleryExtension, + IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionTipsService } from 'vs/workbench/parts/extensions/browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { IURLService } from 'vs/platform/url/common/url'; @@ -54,6 +55,9 @@ suite('ExtensionsWorkbenchService Test', () => { instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + + instantiationService.stub(IExtensionTipsService, ExtensionTipsService); + instantiationService.stub(IExtensionTipsService, 'getKeymapRecommendations', () => []); }); setup(() => { diff --git a/src/vs/workbench/parts/extensions/test/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/extensionsActions.test.ts index 731312830e4..3b09abb1afa 100644 --- a/src/vs/workbench/parts/extensions/test/extensionsActions.test.ts +++ b/src/vs/workbench/parts/extensions/test/extensionsActions.test.ts @@ -13,10 +13,11 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/commo import * as ExtensionsActions from 'vs/workbench/parts/extensions/browser/extensionsActions'; import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { - IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, ILocalExtension, LocalExtensionType, IGalleryExtension, + IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionTipsService } from 'vs/workbench/parts/extensions/browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { IURLService } from 'vs/platform/url/common/url'; @@ -55,6 +56,9 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + + instantiationService.stub(IExtensionTipsService, ExtensionTipsService); + instantiationService.stub(IExtensionTipsService, 'getKeymapRecommendations', () => []); }); setup(() => { -- GitLab