diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 7484c4dc5fe2c99fbb4ae9f75d0754a28c49d5e8..ad20e8b6cb9c66b29fd5255784d34f23342c0ed0 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 42207bc9ae7c25271aed6a41fee591ead731b288..00c29ad522f6ad13274b16c92210e2a0ab64922f 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 60e4f5af93aae529e68050a7bec96ebb14415448..65a9c4c8e735843646a8b4bfea794ab13529a6e7 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 78040cb64908c6c3f9e8a249878683f1b613443a..d7b5a2926520741638c1d482991d7935e4370f45 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 25a32c65c39102a77cd8831a7bb2d58b52e46d98..8dd390481f3caa9fab907845108d4879b65381f4 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 b9460ee942faf0e336444dd0866a27fda86fa182..bf21df60c442a6d90894149d1ce5a6c9aaa195a4 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 89cde057706c0a3c42f8e35a1883ee9c3ad6abe1..de5042685a0e9904884fd32c6363715a704f0500 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 1b0329f95424cbbae7ff2b9389596febdd333b8e..1fdf9f1ad717aaa0034db87b802b5e2143eee82f 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 a884dfa504501e5cf9fd053630276403ad305082..3d9d80e20935ea44528eacc5c328de62c6b6559a 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 c2973c189a180e77ac271df7da5889e7eeae1779..46c9b6ce93373a6c51637cffd6bc86ccd8c14e2c 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 731312830e41316a9083af79509343817f7d5005..3b09abb1afa73a0a748b7b5b41e973adc1a50864 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(() => {