plugins::slot — the slot registry

SlotRegistry maps slot names to lists of registered renderer closures — the cosh-tui analogue of createSlotRegistry from @opentui/core. Plugins register UI fragments under named slots; the host resolves them, possibly filtering by SlotMode. This is the most functional part of the plugin system — fully implemented and synchronous.

SlotRegistry::new() -> Self

Types

pub enum SlotMode {
    SingleWinner,   // render only the first registered entry
    Replace,        // render all entries, replacing previous output
    Append,         // render all entries, appending (default)
}

pub struct ResolvedEntry {
    pub id: String,
    pub renderable: Box<dyn Renderable>,
}

pub struct PluginErrorEvent {
    pub plugin_id: String,
    pub slot_name: String,
    pub phase: String,
    pub source: String,
    pub error: String,
}

pub type SlotRenderer = Box<dyn Fn() -> Box<dyn Renderable>>;

Registering and resolving

Method Behavior
register(slot_name, id, renderer) Add a renderer under a slot name with a stable id.
resolve(slot_name, mode) -> Vec<ResolvedEntry> Build the entries: SingleWinner takes only the first; Replace/Append run all. Unknown slot → empty vec.
unregister(slot_name) Remove all entries for a slot.
has_entries(slot_name) -> bool Whether the slot has any registered renderers.
slot_count() -> usize Number of slots with entries.

Error handling

on_error(handler)              // register a callback for plugin failures
report_error(&PluginErrorEvent) // dispatch an event to all handlers

Example

use cosh_tui::solid::plugins::slot::{SlotRegistry, SlotMode};
use cosh_tui::core::renderables::text::TextRenderable;
use cosh_tui::core::lib::styled_text::string_to_styled_text;

let mut registry = SlotRegistry::new();

registry.register("statusbar", "clock", Box::new(|| -> Box<dyn Renderable> {
    Box::new(TextRenderable::new(Some(string_to_styled_text("12:00"))))
}));
registry.register("statusbar", "git", Box::new(|| -> Box<dyn Renderable> {
    Box::new(TextRenderable::new(Some(string_to_styled_text("main"))))
}));

let entries = registry.resolve("statusbar", SlotMode::Append);
assert_eq!(entries.len(), 2);
assert_eq!(entries[0].id, "clock");

// SingleWinner renders only the first plugin's fragment.
let winner = registry.resolve("statusbar", SlotMode::SingleWinner);
assert_eq!(winner.len(), 1);

Back to solid — module overview.