pub struct ProviderViewRegistry { /* private fields */ }Expand description
Name → opener, registered at boot and read once per trigger.
Same wait-free shape as
ActionHandlerRegistry — copy-on-
write registration, Arc load on lookup — because it is the same
kind of thing: a table of provider-contributed closures the host
consults without knowing what is in them.
Lifetime, amended by MV.1. Native providers register once during
subsystem install(&mut boot) and live for the process, which is why
there is no RAII token. A PLUGIN’s views do not: a plugin unloads and
reloads, so unregister exists for the teardown
path. Without it a reload’s register would return false against
the plugin’s own stale opener and its views would come back dead.
§Examples
A provider registers its opener at boot; the host looks it up when
AppEffect::OpenProviderView { provider: "todo-view", .. } is applied and
calls it with itself as the ModeActivator:
use std::sync::Arc;
use lattice_core::{BufferFlags, BufferId, BufferKind};
use lattice_grammar::Args;
use lattice_mode::{
ModeActivator, ModeId, ProviderViewOpener, ProviderViewOutcome, ProviderViewRegistry,
ServiceRegistry,
};
let opener: ProviderViewOpener = Arc::new(|host: &mut dyn ModeActivator, _args: &Args| {
let view = host.ensure_named_document(
"*todos*",
ModeId::new("todo-view-mode"),
BufferFlags::default(),
);
ProviderViewOutcome::Opened { view, message: Some("3 todos".into()) }
});
let registry = ProviderViewRegistry::new();
assert!(registry.register("todo-view", opener.clone()));
assert!(!registry.register("todo-view", opener)); // first registration keeps the name
/// A stand-in for the host's `Editor`.
struct Host;
impl ModeActivator for Host {
fn activate_major_for_kind(&mut self, _: BufferId, _: BufferKind) {}
fn activate_minor_by_id(&mut self, _: BufferId, _: ModeId) {}
fn ensure_named_document(&mut self, _: &str, _: ModeId, _: BufferFlags) -> BufferId {
BufferId(42)
}
fn services(&self) -> Arc<ServiceRegistry> {
Arc::new(ServiceRegistry::new())
}
}
let open = registry.lookup("todo-view").unwrap();
let outcome = open(&mut Host, &Args::default());
assert_eq!(outcome, ProviderViewOutcome::Opened { view: BufferId(42), message: Some("3 todos".into()) });Implementations§
Source§impl ProviderViewRegistry
impl ProviderViewRegistry
Sourcepub fn new() -> Self
pub fn new() -> Self
An empty registry. The host registers one as a
ProviderViewRegistryHandle at boot.
Sourcepub fn register(
&self,
name: impl Into<String>,
opener: ProviderViewOpener,
) -> bool
pub fn register( &self, name: impl Into<String>, opener: ProviderViewOpener, ) -> bool
Register opener under name.
Returns false when name was already taken — and does NOT
replace it. Two providers claiming one name is a boot-wiring bug,
and last-write-wins would make which view :foo opens depend on
install order; refusing lets the caller log the collision while
the first registration keeps working.
Sourcepub fn unregister(&self, name: &str) -> bool
pub fn unregister(&self, name: &str) -> bool
Remove name’s opener, returning whether one was there.
MV.1: the plugin teardown path. Native providers never call it —
they outlive every unload — so an unknown name is false rather
than a warning.
Sourcepub fn lookup(&self, name: &str) -> Option<ProviderViewOpener>
pub fn lookup(&self, name: &str) -> Option<ProviderViewOpener>
Look up an opener by name. None for an unregistered provider —
the host then echoes rather than silently doing nothing.