use std::cell::Cell;
use crate::reactive::{create_root, Scope, Signal};
use crate::term::Capabilities;
thread_local! {
static CAPS_SIGNAL: Cell<Option<Signal<Capabilities>>> = const { Cell::new(None) };
}
fn caps_signal() -> Signal<Capabilities> {
CAPS_SIGNAL.with(|slot| {
if let Some(sig) = slot.get() {
return sig;
}
let (root, sig) = create_root(|cx| cx.signal(Capabilities::default()));
std::mem::forget(root);
slot.set(Some(sig));
sig
})
}
pub fn use_caps(_cx: Scope) -> Signal<Capabilities> {
caps_signal()
}
pub fn current_caps() -> Capabilities {
caps_signal().get_untracked()
}
pub(super) fn publish_caps(caps: &Capabilities) {
let sig = caps_signal();
if sig.get_untracked() != *caps {
sig.set(caps.clone());
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reactive::flush_effects;
#[test]
fn publish_flips_subscribers_once_per_real_change() {
let (root, runs) = create_root(|cx| {
let runs = cx.signal(0u32);
let caps = use_caps(cx);
cx.effect(move || {
let _ = caps.get(); runs.update(|r| *r += 1);
});
runs
});
flush_effects();
let base = runs.get_untracked();
let upgraded = Capabilities::with(|c| c.kitty_keyboard = true);
publish_caps(&upgraded);
flush_effects();
assert_eq!(runs.get_untracked(), base + 1, "real change: one flip");
publish_caps(&upgraded); flush_effects();
assert_eq!(runs.get_untracked(), base + 1, "no-op publish: no flip");
publish_caps(&Capabilities::default());
root.dispose();
}
}