Support for @recommended:languages search (#124546)

This commit is contained in:
Harald Kirschner 2021-05-27 08:41:10 -07:00 committed by GitHub
parent 9224159b00
commit b157bc7e5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 2 deletions

View file

@ -79,6 +79,7 @@ export interface IProductConfiguration {
readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; };
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
readonly keymapExtensionTips?: readonly string[];
readonly languageExtensionTips?: readonly string[];
readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; };
readonly crashReporter?: {

View file

@ -18,6 +18,7 @@ import { ExperimentalRecommendations } from 'vs/workbench/contrib/extensions/bro
import { WorkspaceRecommendations } from 'vs/workbench/contrib/extensions/browser/workspaceRecommendations';
import { FileBasedRecommendations } from 'vs/workbench/contrib/extensions/browser/fileBasedRecommendations';
import { KeymapRecommendations } from 'vs/workbench/contrib/extensions/browser/keymapRecommendations';
import { LanguageRecommendations } from 'vs/workbench/contrib/extensions/browser/languageRecommendations';
import { ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
import { ConfigBasedRecommendations } from 'vs/workbench/contrib/extensions/browser/configBasedRecommendations';
import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
@ -40,6 +41,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
private readonly exeBasedRecommendations: ExeBasedRecommendations;
private readonly dynamicWorkspaceRecommendations: DynamicWorkspaceRecommendations;
private readonly keymapRecommendations: KeymapRecommendations;
private readonly languageRecommendations: LanguageRecommendations;
public readonly activationPromise: Promise<void>;
private sessionSeed: number;
@ -66,6 +68,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
this.exeBasedRecommendations = instantiationService.createInstance(ExeBasedRecommendations);
this.dynamicWorkspaceRecommendations = instantiationService.createInstance(DynamicWorkspaceRecommendations);
this.keymapRecommendations = instantiationService.createInstance(KeymapRecommendations);
this.languageRecommendations = instantiationService.createInstance(LanguageRecommendations);
if (!this.isEnabled()) {
this.sessionSeed = 0;
@ -90,6 +93,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
this.fileBasedRecommendations.activate(),
this.experimentalRecommendations.activate(),
this.keymapRecommendations.activate(),
this.languageRecommendations.activate(),
]);
this._register(Event.any(this.workspaceRecommendations.onDidChangeRecommendations, this.configBasedRecommendations.onDidChangeRecommendations, this.extensionRecommendationsManagementService.onDidChangeIgnoredRecommendations)(() => this._onDidChangeRecommendations.fire()));
@ -127,6 +131,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
...this.fileBasedRecommendations.recommendations,
...this.workspaceRecommendations.recommendations,
...this.keymapRecommendations.recommendations,
...this.languageRecommendations.recommendations,
];
for (const { extensionId, reason } of allRecommendations) {
@ -185,6 +190,10 @@ export class ExtensionRecommendationsService extends Disposable implements IExte
return this.toExtensionRecommendations(this.keymapRecommendations.recommendations);
}
getLanguageRecommendations(): string[] {
return this.toExtensionRecommendations(this.languageRecommendations.recommendations);
}
async getWorkspaceRecommendations(): Promise<string[]> {
if (!this.isEnabled()) {
return [];

View file

@ -23,7 +23,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur
import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor, optional } from 'vs/platform/instantiation/common/instantiation';
import { KeymapExtensions } from 'vs/workbench/contrib/extensions/common/extensionsUtils';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor';
@ -73,6 +73,7 @@ import { Promises } from 'vs/base/common/async';
import { EditorExtensions } from 'vs/workbench/common/editor';
import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { ExtensionsCompletionItemsProvider } from 'vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider';
import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService';
// Singletons
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
@ -378,6 +379,8 @@ interface IExtensionActionOptions extends IAction2Options {
class ExtensionsContributions extends Disposable implements IWorkbenchContribution {
private tasExperimentService?: ITASExperimentService;
constructor(
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
@ -388,6 +391,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IDialogService private readonly dialogService: IDialogService,
@ICommandService private readonly commandService: ICommandService,
@optional(ITASExperimentService) tasExperimentService: ITASExperimentService,
) {
super();
const hasGalleryContext = CONTEXT_HAS_GALLERY.bindTo(contextKeyService);
@ -410,6 +414,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
hasWebServerContext.set(true);
}
this.tasExperimentService = tasExperimentService;
this.registerGlobalActions();
this.registerContextMenuActions();
this.registerQuickAccessProvider();
@ -501,7 +506,10 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
id: MenuId.CommandPalette,
when: CONTEXT_HAS_GALLERY
},
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@category:"programming languages" @sort:installs '))
run: async () => {
const recommended = await this.tasExperimentService?.getTreatment<boolean>('recommendedLanguages');
runAction(this.instantiationService.createInstance(SearchExtensionsAction, recommended ? '@recommended:languages ' : '@category:"programming languages" @sort:installs '));
}
});
this.registerExtensionAction({

View file

@ -739,6 +739,11 @@ export class ExtensionsListView extends ViewPane {
return this.getKeymapRecommendationsModel(query, options, token);
}
// Language recommendations
if (ExtensionsListView.isLanguageRecommendedExtensionsQuery(query.value)) {
return this.getLanguageRecommendationsModel(query, options, token);
}
// Exe recommendations
if (ExtensionsListView.isExeRecommendedExtensionsQuery(query.value)) {
return this.getExeRecommendationsModel(query, options, token);
@ -803,6 +808,14 @@ export class ExtensionsListView extends ViewPane {
return new PagedModel(installableRecommendations);
}
private async getLanguageRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/@recommended:languages/g, '').trim().toLowerCase();
const recommendations = this.extensionRecommendationsService.getLanguageRecommendations();
const installableRecommendations = (await this.getInstallableRecommendations(recommendations, { ...options, source: 'recommendations-languages' }, token))
.filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1);
return new PagedModel(installableRecommendations);
}
private async getExeRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const exe = query.value.replace(/@exe:/g, '').trim().toLowerCase();
const { important, others } = await this.extensionRecommendationsService.getExeBasedRecommendations(exe.startsWith('"') ? exe.substring(1, exe.length - 1) : exe);
@ -1035,6 +1048,10 @@ export class ExtensionsListView extends ViewPane {
return /@recommended:keymaps/i.test(query);
}
static isLanguageRecommendedExtensionsQuery(query: string): boolean {
return /@recommended:languages/i.test(query);
}
override focus(): void {
super.focus();
if (!this.list) {

View file

@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
import { IProductService } from 'vs/platform/product/common/productService';
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
export class LanguageRecommendations extends ExtensionRecommendations {
private _recommendations: ExtensionRecommendation[] = [];
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
constructor(
@IProductService private readonly productService: IProductService,
) {
super();
}
protected async doActivate(): Promise<void> {
if (this.productService.languageExtensionTips) {
this._recommendations = this.productService.languageExtensionTips.map(extensionId => (<ExtensionRecommendation>{
extensionId: extensionId.toLowerCase(),
reason: {
reasonId: ExtensionRecommendationReason.Application,
reasonText: ''
}
}));
}
}
}

View file

@ -44,6 +44,7 @@ export interface IExtensionRecommendationsService {
getConfigBasedRecommendations(): Promise<{ important: string[], others: string[] }>;
getWorkspaceRecommendations(): Promise<string[]>;
getKeymapRecommendations(): string[];
getLanguageRecommendations(): string[];
}
export type IgnoredRecommendationChangeNotification = {