kui_core/runtime/fills.rs
1//! Slots on the core's side (`docs/adr/0014-slots-an-extension-fills-in-place.md`):
2//! declaring one (`begin_slot`), and the bounded, namespaced fill an
3//! extension draws into (`fill`). The loop over extensions is
4//! `crate::slot`'s; what is here is what only the core can do, because
5//! it owns the node stack and the keys.
6
7use super::*;
8use crate::slot::Slot;
9
10impl Core {
11 /// Declares a slot under its full name at the cursor and returns its
12 /// key — `parent.str(name)`, recorded for `key_of` — or `None` when it
13 /// cannot be declared: outside a frame, or a second time in one
14 /// frame, which is the `duplicate-slot` warning.
15 ///
16 /// An extension may declare one too, and its key nests under the slot
17 /// the extension is itself filling, like any of its nodes. Names stay
18 /// frame-wide because namespaces are: there is one extension called
19 /// `todos` however deep the thing that loaded it sat, so `todos/panel`
20 /// is one slot and declaring it twice is the same warning wherever
21 /// the two declarations came from.
22 pub fn begin_slot(&mut self, name: &str) -> Option<Key> {
23 if self.tree.is_empty() {
24 return None;
25 }
26 if self.slot_labels.find(name).next().is_some() {
27 self.diag.raise(crate::diag::duplicate_slot(name));
28 return None;
29 }
30 let key = self.parent_key().str(name);
31 self.slot_labels.push(key, name, self.origin);
32 self.key_labels.push(key, name, self.origin);
33 Some(key)
34 }
35
36 /// Whether the full name `name` was declared this frame so far — or
37 /// is the slot of a devtools tab declared this frame, which counts
38 /// whether or not the panel mounted it, so a plugin whose only slot
39 /// is a tab is quiet with the panel off (ADR 0032, decision 5).
40 pub fn slot_declared(&self, name: &str) -> bool {
41 self.slot_labels.find(name).next().is_some() || self.devtools_tab_slot(name)
42 }
43
44 /// Runs `f` as the fill of `slot` under `origin`: every node it opens
45 /// is tagged `origin`, keyed as a child of `slot.key` (the namespace
46 /// of ADR 0014 decision 4 — an extension's keys depend on the slot's
47 /// full name, which the host's namespace makes its own, and on
48 /// nothing the host built around them), counted from zero, and
49 /// closed for it if it returns with any open (decision 5, with the
50 /// `unbalanced-extension` warning). The host's origin, counter and
51 /// namespace are what they were when `f` returns, so the host's next
52 /// child is keyed as if the fill had not happened.
53 pub fn fill(&mut self, slot: &Slot<'_>, origin: OriginId, f: impl FnOnce(&mut Ui<'_>)) {
54 self.fill_within(slot, origin, None, f);
55 }
56
57 /// `fill`, with `filler` answering the slots the fill itself declares
58 /// — what `Extensions::fill_one` hands in, so an extension can host
59 /// extensions of its own (see `crate::slot`). `None` is plain `fill`:
60 /// nothing answers, so a slot declared inside draws nothing.
61 pub fn fill_within(
62 &mut self,
63 slot: &Slot<'_>,
64 origin: OriginId,
65 filler: Option<&mut dyn crate::slot::Fill>,
66 f: impl FnOnce(&mut Ui<'_>),
67 ) {
68 if self.tree.is_empty() {
69 return;
70 }
71 let depth = self.stack.len();
72 let saved_counter = self.counters.last().copied().unwrap_or(0);
73 if let Some(c) = self.counters.last_mut() {
74 *c = 0;
75 }
76 let saved_origin = self.origin;
77 let saved_ns = (self.ns_depth, self.ns_key);
78 self.origin = origin;
79 self.ns_depth = depth;
80 self.ns_key = slot.key;
81 let first = self.tree.len() as u32;
82
83 match filler {
84 Some(filler) => f(&mut Ui::with_filler(self, filler)),
85 None => f(&mut Ui::new(self)),
86 }
87 // After the fills inside it, so the innermost is found first.
88 self.tree
89 .fills
90 .push((slot.key, first, self.tree.len() as u32));
91
92 if self.stack.len() > depth {
93 let open = self.stack.len() - depth;
94 self.diag.raise(crate::diag::unbalanced_extension(
95 &slot.full_name(),
96 slot.key,
97 open,
98 ));
99 self.stack.truncate(depth);
100 self.counters.truncate(depth);
101 }
102 if let Some(c) = self.counters.last_mut() {
103 *c = saved_counter;
104 }
105 self.origin = saved_origin;
106 (self.ns_depth, self.ns_key) = saved_ns;
107 }
108}