Expand description
Components from plugins (0.0.14 workstream 4): a
PluginComponent that a plugin
registered by name with PluginRegistrar::component, mounted as a
Component beside the built-ins.
A plugin depends on rs-rich-plugin-api and core only, so its components
speak that crate’s small contract: keys by name, text answers. A
PluginView translates both ways. Its output is the text the plugin
answers with; map it into a container’s
output like any other child. Its keys are listed under the registered
name, so a help overlay shows them and configuration rebinds them
(counter.up = k).
A plugin component that panics does not take the app down: the view shows what went wrong, stops taking focus and ignores events.
use std::sync::Arc;
use rich_ext::plugin::component::{
ComponentContext, ComponentEvent, ComponentFlow, ComponentView, PluginComponent,
};
use rich_ext::plugin::{Plugin, PluginError, PluginMetadata, PluginRegistrar};
use rich_ext::registry::ExtensionRegistry;
use rich_interact::compose::{ComponentExt, Split};
use rich_interact::plugin::PluginView;
use rich_interact::{headless, Flow, Outcome, Select};
#[derive(Default)]
struct Counter(u32);
impl PluginComponent for Counter {
fn handle(&mut self, event: &ComponentEvent, _: &ComponentContext<'_>) -> ComponentFlow {
match event.key() {
Some("up") => self.0 += 1,
Some("enter") => return ComponentFlow::Done(self.0.to_string()),
_ => return ComponentFlow::Ignored,
}
ComponentFlow::Continue
}
fn render(&self, context: &ComponentContext<'_>) -> ComponentView {
ComponentView::new(context.markup(&format!("count {}", self.0)))
}
}
struct Counters;
impl Plugin for Counters {
fn metadata(&self) -> PluginMetadata {
PluginMetadata::new("counters", "Counters", "1.0.0")
}
fn register(&self, registrar: &mut dyn PluginRegistrar) -> Result<(), PluginError> {
registrar.component("counter", Arc::new(|| Box::new(Counter::default())));
Ok(())
}
}
let mut registry = ExtensionRegistry::new();
registry.add_plugin(&Counters).unwrap();
let counter = PluginView::mount(®istry, "counter").unwrap();
let app = Split::horizontal(
counter.map(Flow::Done),
Select::new("Pick", ["a", "b"]).map(|pick| Flow::Done(pick.to_string())),
);
let script = headless::Script::new().keys("up up enter");
let (outcome, _) = headless::run(app, script, 40, 4);
assert_eq!(outcome.unwrap(), Outcome::Done("2".to_string()));Structs§
- Plugin
View - A plugin’s component as a
Componentwhose answer is the plugin’s text. See the module. - Unknown
Component - No component is registered under a name, or its factory failed.