feat: configurable tab labels and search nouns from plugin metadata

Script plugins can now declare tab_label and search_noun in their
plugin.toml [[providers]] section. These flow through the Provider
trait, IPC ProviderDesc, and into the UI via provider_meta::resolve().
Unknown plugins auto-generate labels from type_id instead of showing
a generic "Plugin" label.
This commit is contained in:
2026-04-09 21:16:36 +02:00
parent 34d156fb7d
commit 774b2a4700
21 changed files with 358 additions and 90 deletions

View File

@@ -34,6 +34,8 @@ fn register_provider(lua: &Lua, config: Table) -> LuaResult<()> {
.get::<Option<String>>("default_icon")?
.unwrap_or_else(|| "application-x-addon".to_string());
let prefix: Option<String> = config.get("prefix")?;
let tab_label: Option<String> = config.get("tab_label")?;
let search_noun: Option<String> = config.get("search_noun")?;
// Check if it's a dynamic provider (has query function) or static (has refresh)
let has_query: bool = config.contains_key("query")?;
@@ -70,6 +72,8 @@ fn register_provider(lua: &Lua, config: Table) -> LuaResult<()> {
default_icon,
prefix,
is_dynamic,
tab_label,
search_noun,
});
});

View File

@@ -113,6 +113,10 @@ pub struct LuaProviderInfo {
pub is_static: bool,
/// Optional prefix trigger
pub prefix: ROption<RString>,
/// Short label for UI tab button
pub tab_label: ROption<RString>,
/// Noun for search placeholder
pub search_noun: ROption<RString>,
}
/// Internal runtime state
@@ -184,6 +188,8 @@ impl LuaRuntimeState {
default_icon: RString::from(reg.default_icon.as_str()),
is_static: !reg.is_dynamic,
prefix: reg.prefix.map(RString::from).into(),
tab_label: reg.tab_label.map(RString::from).into(),
search_noun: reg.search_noun.map(RString::from).into(),
});
}
}

View File

@@ -19,6 +19,8 @@ pub struct ProviderRegistration {
pub default_icon: String,
pub prefix: Option<String>,
pub is_dynamic: bool,
pub tab_label: Option<String>,
pub search_noun: Option<String>,
}
/// A loaded plugin instance
@@ -113,6 +115,8 @@ impl LoadedPlugin {
.unwrap_or_else(|| "application-x-addon".to_string()),
prefix: decl.prefix.clone(),
is_dynamic: decl.provider_type == "dynamic",
tab_label: decl.tab_label.clone(),
search_noun: decl.search_noun.clone(),
});
}
}

View File

@@ -34,6 +34,10 @@ pub struct ProviderDecl {
pub provider_type: String,
#[serde(default)]
pub type_id: Option<String>,
#[serde(default)]
pub tab_label: Option<String>,
#[serde(default)]
pub search_noun: Option<String>,
}
fn default_provider_type() -> String {