Expose search provider contributions

This commit is contained in:
mirivlad 2026-06-28 01:03:36 +08:00
parent 35012025b6
commit 0c788bed80
5 changed files with 87 additions and 12 deletions

View File

@ -30,6 +30,7 @@
$: contribCounts = {
views: (contributions.views || []).filter(v => v.pluginId === pluginId).length,
commands: (contributions.commands || []).filter(c => c.pluginId === pluginId).length,
searchProviders: (contributions.searchProviders || []).filter(s => s.pluginId === pluginId).length,
sidebar: (contributions.sidebarItems || []).filter(s => s.pluginId === pluginId).length,
statusbar: (contributions.statusBarItems || []).filter(s => s.pluginId === pluginId).length,
openProviders: (contributions.openProviders || []).filter(o => o.pluginId === pluginId).length,
@ -40,6 +41,7 @@
const parts = [];
if (contribCounts.views > 0) parts.push(contribCounts.views + ' view' + (contribCounts.views !== 1 ? 's' : ''));
if (contribCounts.commands > 0) parts.push(contribCounts.commands + ' command' + (contribCounts.commands !== 1 ? 's' : ''));
if (contribCounts.searchProviders > 0) parts.push(contribCounts.searchProviders + ' searchProvider' + (contribCounts.searchProviders !== 1 ? 's' : ''));
if (contribCounts.sidebar > 0) parts.push(contribCounts.sidebar + ' sidebar' + (contribCounts.sidebar !== 1 ? 's' : ''));
if (contribCounts.statusbar > 0) parts.push(contribCounts.statusbar + ' statusbar' + (contribCounts.statusbar !== 1 ? 's' : ''));
if (contribCounts.openProviders > 0) parts.push(contribCounts.openProviders + ' openProvider' + (contribCounts.openProviders !== 1 ? 's' : ''));

View File

@ -374,19 +374,20 @@
}
function allContributions() {
var views = [], commands = [], sidebarItems = [], statusBarItems = [], settingsPanels = [], openProviders = [], workspaceItems = [];
var views = [], commands = [], searchProviders = [], sidebarItems = [], statusBarItems = [], settingsPanels = [], openProviders = [], workspaceItems = [];
for (var id in pluginStates) {
var s = pluginStates[id];
var c = (s.manifest && s.manifest.contributes) || {};
if (c.views) c.views.forEach(function (v) { views.push(Object.assign({}, v, { pluginId: id })); });
if (c.commands) c.commands.forEach(function (cmd) { commands.push(Object.assign({}, cmd, { pluginId: id })); });
if (c.searchProviders) c.searchProviders.forEach(function (sp) { searchProviders.push(Object.assign({}, sp, { pluginId: id })); });
if (c.sidebarItems) c.sidebarItems.forEach(function (sb) { sidebarItems.push(Object.assign({}, sb, { pluginId: id })); });
if (c.statusBarItems) c.statusBarItems.forEach(function (st) { statusBarItems.push(Object.assign({}, st, { pluginId: id })); });
if (c.settingsPanels) c.settingsPanels.forEach(function (sp) { settingsPanels.push(Object.assign({}, sp, { pluginId: id })); });
if (c.openProviders) c.openProviders.forEach(function (op) { openProviders.push(Object.assign({}, op, { pluginId: id })); });
if (c.workspaceItems) c.workspaceItems.forEach(function (wi) { workspaceItems.push(Object.assign({}, wi, { pluginId: id })); });
}
return { views: views, commands: commands, sidebarItems: sidebarItems, statusBarItems: statusBarItems, settingsPanels: settingsPanels, openProviders: openProviders, workspaceItems: workspaceItems };
return { views: views, commands: commands, searchProviders: searchProviders, sidebarItems: sidebarItems, statusBarItems: statusBarItems, settingsPanels: settingsPanels, openProviders: openProviders, workspaceItems: workspaceItems };
}
function requestExtension(request) {

View File

@ -80,6 +80,44 @@ export namespace api {
return a;
}
}
export class FlatSearchProvider {
pluginId: string;
id: string;
label: string;
handler: string;
static createFrom(source: any = {}) {
return new FlatSearchProvider(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.pluginId = source["pluginId"];
this.id = source["id"];
this.label = source["label"];
this.handler = source["handler"];
}
}
export class FlatStatusBarItem {
pluginId: string;
id: string;
label: string;
position?: string;
handler?: string;
static createFrom(source: any = {}) {
return new FlatStatusBarItem(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.pluginId = source["pluginId"];
this.id = source["id"];
this.label = source["label"];
this.position = source["position"];
this.handler = source["handler"];
}
}
export class FlatSidebarItem {
pluginId: string;
id: string;
@ -165,8 +203,10 @@ export namespace api {
export class ContributionSummary {
views: FlatView[];
commands: FlatCommand[];
searchProviders: FlatSearchProvider[];
settingsPanels: FlatSettingsPanel[];
sidebarItems: FlatSidebarItem[];
statusBarItems: FlatStatusBarItem[];
openProviders: FlatOpenProvider[];
workspaceItems: FlatWorkspaceItem[];
@ -178,8 +218,10 @@ export namespace api {
if ('string' === typeof source) source = JSON.parse(source);
this.views = this.convertValues(source["views"], FlatView);
this.commands = this.convertValues(source["commands"], FlatCommand);
this.searchProviders = this.convertValues(source["searchProviders"], FlatSearchProvider);
this.settingsPanels = this.convertValues(source["settingsPanels"], FlatSettingsPanel);
this.sidebarItems = this.convertValues(source["sidebarItems"], FlatSidebarItem);
this.statusBarItems = this.convertValues(source["statusBarItems"], FlatStatusBarItem);
this.openProviders = this.convertValues(source["openProviders"], FlatOpenProvider);
this.workspaceItems = this.convertValues(source["workspaceItems"], FlatWorkspaceItem);
}
@ -209,6 +251,7 @@ export namespace api {
export class SyncStatusDTO {
configured: boolean;
serverUrl: string;

View File

@ -241,6 +241,13 @@ type FlatCommand struct {
Handler string `json:"handler,omitempty"`
}
type FlatSearchProvider struct {
PluginID string `json:"pluginId"`
ID string `json:"id"`
Label string `json:"label"`
Handler string `json:"handler"`
}
type FlatStatusBarItem struct {
PluginID string `json:"pluginId"`
ID string `json:"id"`
@ -278,6 +285,7 @@ type FlatWorkspaceItem struct {
type ContributionSummary struct {
Views []FlatView `json:"views"`
Commands []FlatCommand `json:"commands"`
SearchProviders []FlatSearchProvider `json:"searchProviders"`
SettingsPanels []FlatSettingsPanel `json:"settingsPanels"`
SidebarItems []FlatSidebarItem `json:"sidebarItems"`
StatusBarItems []FlatStatusBarItem `json:"statusBarItems"`
@ -292,6 +300,7 @@ func buildContributionSummary(r *contribution.Registry) ContributionSummary {
}
regViews := r.Views()
regCmds := r.Commands()
regSearchProviders := r.SearchProviders()
regPanels := r.SettingsPanels()
regSidebar := r.SidebarItems()
regStatusBar := r.StatusBarItems()
@ -306,6 +315,10 @@ func buildContributionSummary(r *contribution.Registry) ContributionSummary {
for i, v := range regCmds {
cmds[i] = FlatCommand{PluginID: v.PluginID, ID: v.Item.ID, Title: v.Item.Title, Icon: v.Item.Icon, Handler: v.Item.Handler}
}
searchProviders := make([]FlatSearchProvider, len(regSearchProviders))
for i, v := range regSearchProviders {
searchProviders[i] = FlatSearchProvider{PluginID: v.PluginID, ID: v.Item.ID, Label: v.Item.Label, Handler: v.Item.Handler}
}
panels := make([]FlatSettingsPanel, len(regPanels))
for i, v := range regPanels {
panels[i] = FlatSettingsPanel{PluginID: v.PluginID, ID: v.Item.ID, Title: v.Item.Title, Icon: v.Item.Icon, Component: v.Item.Component}
@ -337,7 +350,7 @@ func buildContributionSummary(r *contribution.Registry) ContributionSummary {
for i, v := range regWorkspaceItems {
workspaceItems[i] = FlatWorkspaceItem{PluginID: v.PluginID, ID: v.Item.ID, Title: v.Item.Title, Icon: v.Item.Icon, Component: v.Item.Component}
}
return ContributionSummary{Views: views, Commands: cmds, SettingsPanels: panels, SidebarItems: sidebar, StatusBarItems: statusBarItems, OpenProviders: openProviders, WorkspaceItems: workspaceItems}
return ContributionSummary{Views: views, Commands: cmds, SearchProviders: searchProviders, SettingsPanels: panels, SidebarItems: sidebar, StatusBarItems: statusBarItems, OpenProviders: openProviders, WorkspaceItems: workspaceItems}
}
// GetContributions returns all registered contributions flattened for the frontend.
@ -350,8 +363,8 @@ func (a *App) GetContributions() ContributionSummary {
}
summary := buildContributionSummary(a.contribRegistry)
if a.debug {
debug.Logf("[api] GetContributions: returning views=%d commands=%d sidebar=%d statusBar=%d settings=%d openProviders=%d",
len(summary.Views), len(summary.Commands), len(summary.SidebarItems), len(summary.StatusBarItems), len(summary.SettingsPanels), len(summary.OpenProviders))
debug.Logf("[api] GetContributions: returning views=%d commands=%d searchProviders=%d sidebar=%d statusBar=%d settings=%d openProviders=%d",
len(summary.Views), len(summary.Commands), len(summary.SearchProviders), len(summary.SidebarItems), len(summary.StatusBarItems), len(summary.SettingsPanels), len(summary.OpenProviders))
}
return summary
}

View File

@ -1026,6 +1026,9 @@ func newBridgeTestApp(t *testing.T) *App {
StatusBarItems: []plugin.ContributionStatusBarItem{
{ID: "bridge.status", Label: "Bridge Ready", Position: "right", Handler: "openBridgeStatus"},
},
SearchProviders: []plugin.ContributionSearchProvider{
{ID: "bridge.search", Label: "Bridge Search", Handler: "searchVault"},
},
OpenProviders: []plugin.ContributionOpenProvider{
{
ID: "bridge.markdown",
@ -1113,6 +1116,19 @@ func TestContributionSummaryIncludesStatusBarItems(t *testing.T) {
}
}
func TestContributionSummaryIncludesSearchProviders(t *testing.T) {
app := newBridgeTestApp(t)
summary := app.GetContributions()
if len(summary.SearchProviders) != 1 {
t.Fatalf("SearchProviders count = %d, want 1", len(summary.SearchProviders))
}
provider := summary.SearchProviders[0]
if provider.PluginID != "bridge.plugin" || provider.ID != "bridge.search" || provider.Label != "Bridge Search" || provider.Handler != "searchVault" {
t.Fatalf("search provider = %+v", provider)
}
}
func TestWorkbenchOpenAndEditResourceRouteToProvider(t *testing.T) {
app := newBridgeTestApp(t)
app.contribRegistry.Register("disabled.plugin", &plugin.Contributions{