1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum Cell {
26 Is(&'static str),
31 As(&'static str),
35 No(&'static str),
37}
38
39pub struct Door {
41 pub rust: &'static str,
45 pub c: Cell,
46 pub odin: Cell,
51 pub node: Cell,
52 pub lua: Cell,
53 pub doc: &'static str,
54}
55
56use Cell::{As, Is, No};
57
58pub const GUEST: &str = "a script is a guest in the host's frame (ADR 0014): its env is the view's reading, and registering, driving, pacing and reading back are the host's";
63
64const NO_HANDLE: &str = "a script owns no handle: the host registers and the script names the id it was given (`image { id = }`, `font = id`, `audio { src = id }`)";
66
67const ODIN_IS_C: &str =
71 "Odin's doors are kui.h's (packages/odin): C has none, for the reason in C's cell";
72
73const NEVER_PAINTS: &str = "a Node host never paints: the renderer behind `KuiWindow` is the runner's, and a headless `Ctx` has none";
76
77pub const DOORS: &[Door] = &[
78 Door {
80 rust: "SharedResources::add_image",
81 c: Is("kui_image_add"),
82 odin: Is("image_add"),
83 node: Is("addImage"),
84 lua: No(NO_HANDLE),
85 doc: "Registers RGBA pixels and mints an id for `<image src>`.",
86 },
87 Door {
88 rust: "Core::update_image",
89 c: Is("kui_image_update"),
90 odin: Is("image_update"),
91 node: Is("updateImage"),
92 lua: No(NO_HANDLE),
93 doc: "Replaces the pixels behind a live id, keeping the id (ADR 0025).",
94 },
95 Door {
96 rust: "Core::remove_image",
97 c: Is("kui_image_remove"),
98 odin: Is("image_remove"),
99 node: Is("removeImage"),
100 lua: No(NO_HANDLE),
101 doc: "Drops an image; every window's atlas lets it go (backlog AR8).",
102 },
103 Door {
104 rust: "Core::image_pixels",
105 c: Is("kui_image_pixels"),
106 odin: Is("image_pixels"),
107 node: No(NEVER_PAINTS),
108 lua: No(NO_HANDLE),
109 doc: "The pixels behind a handle, for a renderer meeting a texture quad.",
110 },
111 Door {
112 rust: "Core::parse_path",
113 c: Is("kui_path_parse"),
114 odin: Is("path_parse"),
115 node: As("`d` on `<path>` is the string; the addon hands it to this parser"),
116 lua: As("`d` on `path { }` is the string; the host hands it to this parser"),
117 doc: "SVG path data to the flat op form a `path` draws (ADR 0040): one parser, so every binding draws the same shape.",
118 },
119 Door {
120 rust: "Core::add_fragment",
121 c: Is("kui_fragment_add"),
122 odin: Is("fragment_add"),
123 node: Is("addFragment"),
124 lua: No(NO_HANDLE),
125 doc: "Registers a WGSL function and mints an id for `<fragment src>` (ADR 0015).",
126 },
127 Door {
128 rust: "Core::remove_fragment",
129 c: Is("kui_fragment_remove"),
130 odin: Is("fragment_remove"),
131 node: Is("removeFragment"),
132 lua: No(NO_HANDLE),
133 doc: "Drops a fragment; the renderer drops its pipelines (backlog AR8).",
134 },
135 Door {
136 rust: "Core::fragment_module_source",
137 c: Is("kui_fragment_source"),
138 odin: Is("fragment_source"),
139 node: No(NEVER_PAINTS),
140 lua: No(NO_HANDLE),
141 doc: "The whole WGSL module behind a handle, which is what a renderer compiles.",
142 },
143 Door {
144 rust: "Core::add_font_data",
145 c: Is("kui_font_add"),
146 odin: Is("font_add"),
147 node: Is("addFont"),
148 lua: No(NO_HANDLE),
149 doc: "Registers a font's bytes and mints an id for `font`.",
150 },
151 Door {
152 rust: "Core::add_system_font",
153 c: Is("kui_font_add_system"),
154 odin: Is("font_add_system"),
155 node: Is("addSystemFont"),
156 lua: No(NO_HANDLE),
157 doc: "Registers an installed family by name.",
158 },
159 Door {
160 rust: "Core::load_font_file",
161 c: Is("kui_font_load_file"),
162 odin: Is("font_load_file"),
163 node: Is("loadFontFile"),
164 lua: No(NO_HANDLE),
165 doc: "Registers a font file by path.",
166 },
167 Door {
168 rust: "Core::load_fonts_dir",
169 c: Is("kui_font_load_dir"),
170 odin: Is("font_load_dir"),
171 node: Is("loadFontsDir"),
172 lua: No(NO_HANDLE),
173 doc: "Registers every font file in a directory.",
174 },
175 Door {
176 rust: "Core::reload_system_fonts",
177 c: Is("kui_font_reload_system"),
178 odin: Is("font_reload_system"),
179 node: Is("reloadSystemFonts"),
180 lua: No(GUEST),
181 doc: "Scans the system's fonts again, so a font installed while the app runs is found (the scan is otherwise once a process); returns how many faces came and went.",
182 },
183 Door {
184 rust: "Core::set_fallback_fonts",
185 c: Is("kui_font_set_fallback"),
186 odin: Is("font_set_fallback"),
187 node: Is("setFallbackFonts"),
188 lua: No(NO_HANDLE),
189 doc: "The fonts asked, in order, for a character the text's own family lacks, before the platform's fallback list (backlog F121).",
190 },
191 Door {
192 rust: "Core::fallback_fonts",
193 c: No("the list is the one the host set"),
194 odin: No(ODIN_IS_C),
195 node: No("the list is the one the host set"),
196 lua: No(NO_HANDLE),
197 doc: "The families `set_fallback_fonts` named, in order.",
198 },
199 Door {
200 rust: "Core::remove_font",
201 c: Is("kui_font_remove"),
202 odin: Is("font_remove"),
203 node: Is("removeFont"),
204 lua: No(NO_HANDLE),
205 doc: "Drops a font.",
206 },
207 Door {
208 rust: "Core::system_font_families",
209 c: Is("kui_font_families"),
210 odin: Is("font_families"),
211 node: Is("systemFontFamilies"),
212 lua: No(NO_HANDLE),
213 doc: "The installed family names `add_system_font` accepts.",
214 },
215 Door {
216 rust: "Core::system_fonts",
217 c: Is("kui_system_fonts"),
218 odin: Is("system_fonts"),
219 node: Is("systemFonts"),
220 lua: No(NO_HANDLE),
221 doc: "The same families, each with what the font database read off its faces: `monospaced` (every face fixed-pitch), `weights`, `italic` (backlog F97) — a font picker's monospaced-first list without a file loaded or a glyph shaped.",
222 },
223 Door {
224 rust: "Core::add_sound",
225 c: Is("kui_sound_add"),
226 odin: Is("sound_add"),
227 node: Is("addSound"),
228 lua: No(NO_HANDLE),
229 doc: "Registers a sound's bytes and mints an id for `<audio src>`, `clickSound` and `play`.",
230 },
231 Door {
232 rust: "Core::remove_sound",
233 c: Is("kui_sound_remove"),
234 odin: Is("sound_remove"),
235 node: Is("removeSound"),
236 lua: No(NO_HANDLE),
237 doc: "Drops a sound.",
238 },
239 Door {
240 rust: "Core::set_text_cache_budget",
241 c: Is("kui_set_text_cache_budget"),
242 odin: Is("set_text_cache_budget"),
243 node: Is("setTextCacheBudget"),
244 lua: No(GUEST),
245 doc: "The shaped-text cache's byte budget (backlog C16).",
246 },
247 Door {
248 rust: "Core::text_cache_bytes",
249 c: Is("kui_text_cache_bytes"),
250 odin: Is("text_cache_bytes"),
251 node: Is("textCacheBytes"),
252 lua: No(GUEST),
253 doc: "What the shaped-text cache holds.",
254 },
255 Door {
257 rust: "Ui::play",
258 c: Is("kui_play"),
259 odin: Is("play"),
260 node: Is("play"),
261 lua: No(
262 "a script owns no sound handle, and its env is the view's: a playback started there would start again every frame — `audio { src = id }` is the declarative form, and what a script has",
263 ),
264 doc: "Starts a playback of a registered sound, outside any node; answers the playback id.",
265 },
266 Door {
267 rust: "Core::stop",
268 c: Is("kui_stop"),
269 odin: Is("stop"),
270 node: Is("stop"),
271 lua: No("as `play`: a script declares `audio { }` and stops it by not declaring it"),
272 doc: "Stops a playback, with an optional fade.",
273 },
274 Door {
275 rust: "Core::set_volume",
276 c: Is("kui_set_volume"),
277 odin: Is("set_volume"),
278 node: Is("setVolume"),
279 lua: As("`audio { volume = }` applies live"),
280 doc: "A playback's volume, with an optional tween.",
281 },
282 Door {
283 rust: "Core::pause",
284 c: Is("kui_pause"),
285 odin: Is("pause"),
286 node: Is("pause"),
287 lua: As("`audio { paused = true }` applies live"),
288 doc: "Pauses a playback.",
289 },
290 Door {
291 rust: "Core::resume",
292 c: Is("kui_resume"),
293 odin: Is("resume"),
294 node: Is("resume"),
295 lua: As("`audio { paused = false }`"),
296 doc: "Resumes a paused playback.",
297 },
298 Door {
299 rust: "Core::set_master_volume",
300 c: Is("kui_set_master_volume"),
301 odin: Is("set_master_volume"),
302 node: Is("setMasterVolume"),
303 lua: No(GUEST),
304 doc: "The device's master volume, with an optional tween.",
305 },
306 Door {
308 rust: "Ui::announce",
309 c: Is("kui_announce"),
310 odin: Is("announce"),
311 node: Is("announce"),
312 lua: Is("announce"),
313 doc: "Says something once with no node behind it (ADR 0001).",
314 },
315 Door {
316 rust: "Core::take_announcements",
317 c: Is("kui_take_announcements"),
318 odin: Is("take_announcements"),
319 node: Is("Ctx.announcements"),
320 lua: No(GUEST),
321 doc: "Drains what was announced, for a host bridging assistive technology; a `KuiWindow`'s bridge is the runner's.",
322 },
323 Door {
324 rust: "Core::access_tree",
325 c: Is("kui_access_tree"),
326 odin: Is("access_tree"),
327 node: Is("accessTree"),
328 lua: No(GUEST),
329 doc: "The access tree of the last finished frame (ADR 0001).",
330 },
331 Door {
333 rust: "Ui::focus",
334 c: Is("kui_focus"),
335 odin: Is("focus"),
336 node: Is("focus"),
337 lua: Is("set_focus"),
338 doc: "Moves focus to a node now; an app's move stands over a modal's restore (backlog AR17). `keyFocus` is the declarative, edge-triggered form.",
339 },
340 Door {
341 rust: "Ui::blur",
342 c: As("`kui_focus(ctx, 0)`"),
343 odin: As("`focus(ui, 0)`"),
344 node: Is("blur"),
345 lua: Is("blur"),
346 doc: "Drops focus.",
347 },
348 Door {
349 rust: "Ui::focus_next",
350 c: Is("kui_focus_next"),
351 odin: Is("focus_next"),
352 node: Is("focusNext"),
353 lua: Is("focus_next"),
354 doc: "Steps the Tab ring forward (ADR 0002).",
355 },
356 Door {
357 rust: "Ui::focus_prev",
358 c: As("`kui_focus_next(ctx, false)`"),
359 odin: As("`focus_next(ui, false)`"),
360 node: Is("focusPrev"),
361 lua: Is("focus_prev"),
362 doc: "Steps the Tab ring backward.",
363 },
364 Door {
365 rust: "Ui::focus_region",
366 c: Is("kui_focus_region"),
367 odin: Is("focus_region"),
368 node: Is("focusRegion"),
369 lua: Is("focus_region"),
370 doc: "Enters a `focusRegion`'s ring, or leaves it for the main one (ADR 0022).",
371 },
372 Door {
373 rust: "Ui::region",
374 c: Is("kui_region"),
375 odin: Is("region"),
376 node: Is("region"),
377 lua: As("`env.region`, a reading"),
378 doc: "The region in effect.",
379 },
380 Door {
381 rust: "Ui::focused",
382 c: Is("kui_focused"),
383 odin: Is("focused"),
384 node: Is("focused"),
385 lua: As("`env.focus`, a reading"),
386 doc: "The focused node's key.",
387 },
388 Door {
389 rust: "Ui::is_focused",
390 c: Is("kui_is_focused"),
391 odin: Is("is_focused"),
392 node: Is("isFocused"),
393 lua: Is("is_focused"),
394 doc: "Whether a node has focus.",
395 },
396 Door {
397 rust: "Ui::focus_visible",
398 c: Is("kui_focus_visible"),
399 odin: Is("focus_visible"),
400 node: Is("focusVisible"),
401 lua: As("`env.focus_visible`, a reading"),
402 doc: "Whether focus came from the keyboard and the ring should show.",
403 },
404 Door {
405 rust: "Ui::key_of",
406 c: Is("kui_key_of"),
407 odin: Is("key_of"),
408 node: Is("keyOf"),
409 lua: As("every query and verb takes the label itself (`key_query`)"),
410 doc: "The key a label names this frame.",
411 },
412 Door {
413 rust: "Core::label_of",
414 c: No(
415 "the label is the app's own word for the node, and every door names a node by it or by the key an event carried; the one reader is the devtools' inspector, in the core",
416 ),
417 odin: No(ODIN_IS_C),
418 node: No("the same reason as C's"),
419 lua: No("the same reason as C's"),
420 doc: "The label a key was opened under.",
421 },
422 Door {
423 rust: "Ui::caret_visible",
424 c: Is("kui_caret_visible"),
425 odin: Is("caret_visible"),
426 node: Is("caretVisible"),
427 lua: As("`env.caret_visible`, a reading"),
428 doc: "The blink phase a custom editor draws its caret on.",
429 },
430 Door {
431 rust: "Core::set_caret_visible",
432 c: Is("kui_set_caret_visible"),
433 odin: Is("set_caret_visible"),
434 node: Is("setCaretVisible"),
435 lua: No(GUEST),
436 doc: "The host's blink clock writes the phase.",
437 },
438 Door {
439 rust: "Core::has_caret",
440 c: Is("kui_has_caret"),
441 odin: Is("has_caret"),
442 node: Is("hasCaret"),
443 lua: No(GUEST),
444 doc: "Whether anything focused draws a caret to blink — a `caretSolid` line's is not one — which arms a host's blink clock.",
445 },
446 Door {
447 rust: "Core::caret_stamp",
448 c: Is("kui_caret_stamp"),
449 odin: Is("caret_stamp"),
450 node: As(
451 "the loop in `index.js` runs the blink from `nextDeadlineMs`; a headless `Ctx` never blinks",
452 ),
453 lua: No(GUEST),
454 doc: "Changes when the caret moves or focus does, which re-arms the clock solid.",
455 },
456 Door {
458 rust: "Ui::is_hovered",
459 c: Is("kui_is_hovered"),
460 odin: Is("is_hovered"),
461 node: Is("isHovered"),
462 lua: Is("is_hovered"),
463 doc: "Whether the pointer is over a node.",
464 },
465 Door {
466 rust: "Ui::is_pressed",
467 c: Is("kui_is_pressed"),
468 odin: Is("is_pressed"),
469 node: Is("isPressed"),
470 lua: Is("is_pressed"),
471 doc: "Whether a press started on a node and the pointer is still over it.",
472 },
473 Door {
474 rust: "Ui::is_drop_target",
475 c: Is("kui_is_drop_target"),
476 odin: Is("is_drop_target"),
477 node: Is("isDropTarget"),
478 lua: Is("is_drop_target"),
479 doc: "Whether files dragged in from the OS are over a node (ADR 0031) — for drop-dependent layout; the colour is `drop_bg`.",
480 },
481 Door {
482 rust: "Core::drop_target",
483 c: Is("kui_drop_target"),
484 odin: Is("drop_target"),
485 node: Is("dropTarget"),
486 lua: Is("drop_target"),
487 doc: "The drop zone the dragged files are over, if any — what a driver answers the OS with, and what a test reads to say a zone was found (ADR 0031, decision 5).",
488 },
489 Door {
490 rust: "Ui::is_group_hovered",
491 c: As(
492 "`hoverBg` / `pressedBg` on a `hoverGroup` member paint it; the reader is what the Rust widgets ask when they paint by hand",
493 ),
494 odin: As("`hover_bg` / `pressed_bg` on a `hover_group` member paint it"),
495 node: As("the same form as C's"),
496 lua: As("the same form as C's"),
497 doc: "Whether any member of a hover group is hovered (`is_group_pressed` the same for a press).",
498 },
499 Door {
500 rust: "Core::cursor",
501 c: No("the pointer's position is the driver's own fact — it injected it"),
502 odin: No(ODIN_IS_C),
503 node: No("the same reason as C's"),
504 lua: No("the same reason as C's, one step removed"),
505 doc: "Where the pointer is, in logical viewport px.",
506 },
507 Door {
508 rust: "Core::cursor_shape",
509 c: Is("kui_cursor_shape"),
510 odin: Is("cursor_shape"),
511 node: Is("cursorShape"),
512 lua: No(GUEST),
513 doc: "The pointer shape the frame asks for, which the host sets on its window.",
514 },
515 Door {
516 rust: "Ui::layout_of",
517 c: Is("kui_layout_of"),
518 odin: Is("layout_of"),
519 node: Is("layoutOf"),
520 lua: Is("layout_of"),
521 doc: "Where layout put a node last frame (backlog C26).",
522 },
523 Door {
524 rust: "Ui::scroll_offset",
525 c: Is("kui_scroll_offset"),
526 odin: Is("scroll_offset"),
527 node: Is("scrollOffset"),
528 lua: Is("scroll_offset"),
529 doc: "A scrolling node's offset.",
530 },
531 Door {
532 rust: "Ui::scroll_geometry",
533 c: Is("kui_scroll_geometry"),
534 odin: Is("scroll_geometry"),
535 node: Is("scrollGeometry"),
536 lua: Is("scroll_geometry"),
537 doc: "A scrolling node's viewport and content sizes.",
538 },
539 Door {
540 rust: "Ui::set_scroll",
541 c: Is("kui_set_scroll"),
542 odin: Is("set_scroll"),
543 node: Is("setScroll"),
544 lua: Is("set_scroll"),
545 doc: "Scrolls a node to an offset.",
546 },
547 Door {
548 rust: "Ui::shift_scroll",
549 c: Is("kui_shift_scroll"),
550 odin: Is("shift_scroll"),
551 node: Is("shiftScroll"),
552 lua: Is("shift_scroll"),
553 doc: "Moves a node's scroll by content that moved under it, with no ease: a variable-height list's anchor (backlog C46).",
554 },
555 Door {
556 rust: "Ui::reveal",
557 c: Is("kui_reveal"),
558 odin: Is("reveal"),
559 node: Is("reveal"),
560 lua: Is("reveal"),
561 doc: "Scrolls whatever encloses a node until it is in view.",
562 },
563 Door {
564 rust: "Ui::text_hit",
565 c: Is("kui_text_hit"),
566 odin: Is("text_hit"),
567 node: Is("textHit"),
568 lua: Is("text_hit"),
569 doc: "The byte and line under a point in a node's text (backlog C18).",
570 },
571 Door {
572 rust: "Ui::caret_rect",
573 c: Is("kui_caret_rect"),
574 odin: Is("caret_rect"),
575 node: Is("caretRect"),
576 lua: Is("caret_rect"),
577 doc: "The caret rect for a byte offset in a node's text.",
578 },
579 Door {
580 rust: "Core::ime_rect",
581 c: Is("kui_ime_rect"),
582 odin: Is("ime_rect"),
583 node: Is("imeRect"),
584 lua: No(GUEST),
585 doc: "Where the OS candidate window goes, which the host hands to the platform (backlog C17).",
586 },
587 Door {
588 rust: "Ui::measure_text",
589 c: Is("kui_measure_text"),
590 odin: Is("measure_text"),
591 node: Is("measureText"),
592 lua: Is("measure_text"),
593 doc: "Shapes text in a style at a width and answers its size and line count.",
594 },
595 Door {
596 rust: "Ui::measure_rich_text",
597 c: Is("kui_measure_rich_text"),
598 odin: Is("measure_rich_text"),
599 node: As("`measureText` takes spans too"),
600 lua: As("`measure_text` takes spans too"),
601 doc: "The same for spans, shaped as one paragraph.",
602 },
603 Door {
604 rust: "Ui::edit_text",
605 c: Is("kui_edit_text"),
606 odin: Is("edit_text"),
607 node: Is("editText"),
608 lua: Is("edit_text"),
609 doc: "An editor's text, by key or by label.",
610 },
611 Door {
612 rust: "Ui::set_edit_text",
613 c: Is("kui_edit_set_text"),
614 odin: Is("edit_set_text"),
615 node: Is("setEditText"),
616 lua: Is("set_edit_text"),
617 doc: "Replaces an editor's text, caret at the end.",
618 },
619 Door {
620 rust: "Ui::set_edit_text_by_label",
621 c: Is("kui_edit_set_text_label"),
622 odin: Is("edit_set_text_label"),
623 node: As("`setEditText` takes the label too"),
624 lua: As("`set_edit_text` takes the label too"),
625 doc: "The same by the label an editor's `key` declares, which reaches one the frame is about to declare (backlog AR26).",
626 },
627 Door {
628 rust: "Core::animating",
629 c: Is("kui_animating"),
630 odin: Is("animating"),
631 node: Is("animating"),
632 lua: No(GUEST),
633 doc: "Whether the last frame left a transition mid-flight, so the host draws another without waiting for input.",
634 },
635 Door {
636 rust: "Core::owed",
637 c: Is("kui_owed"),
638 odin: Is("owed"),
639 node: Is("owed"),
640 lua: No(GUEST),
641 doc: "The same by kind — a finite transition, a keyframe cycle, a departing ghost, a requested frame, an autoscroll — so a test can wait for the transitions to run out under a cycle that never ends; Node's loop has `quiet()` for that wait (backlog F64).",
642 },
643 Door {
644 rust: "Core::set_frame_trace",
645 c: Is("kui_set_frame_trace"),
646 odin: Is("set_frame_trace"),
647 node: Is("setFrameTrace"),
648 lua: No(GUEST),
649 doc: "Turns on the trace of why frames run: who holds an owed frame, and whether a frame changed what is drawn (backlog F111).",
650 },
651 Door {
652 rust: "Core::frame_cause",
653 c: Is("kui_frame_cause"),
654 odin: Is("frame_cause"),
655 node: Is("frameCause"),
656 lua: No(GUEST),
657 doc: "Why the frame being built runs: the input it answers by kind, what the driver noted, and `owed` after a frame that owed one (backlog F111).",
658 },
659 Door {
660 rust: "Core::begin_frame_cause",
661 c: No(
662 "a C host's view runs between `kui_frame_begin` and `kui_frame_finish`, inside the frame it builds, so it reads that frame already",
663 ),
664 odin: No(ODIN_IS_C),
665 node: Is("Ctx.beginFrameCause"),
666 lua: No(GUEST),
667 doc: "Starts the next frame's record ahead of its `begin_frame`, for a driver whose view runs before the frame it is for — Node's loop — so `frame_cause` and `owed_by` read from the view answer that frame (backlog RG81).",
668 },
669 Door {
670 rust: "Core::note_frame_cause",
671 c: Is("kui_note_frame_cause"),
672 odin: Is("note_frame_cause"),
673 node: No(
674 "the drivers that note a reason are kui-native's, which a `KuiWindow` runs on; a `Ctx` driven by hand has nothing but the input the core already records",
675 ),
676 lua: No(GUEST),
677 doc: "A driver adds a reason the core cannot see — a wake, a resize, a blink, a retry — to the next frame's (backlog F111).",
678 },
679 Door {
680 rust: "Core::owed_by",
681 c: No(
682 "lists of named holders are strings the library would own across calls, an [out-array] struct and an ABI bump for a reading that is a debugging aid; a C host reads the kinds from `kui_owed`",
683 ),
684 odin: No(ODIN_IS_C),
685 node: Is("owedBy"),
686 lua: No(GUEST),
687 doc: "Who holds the frame the last one left owed: `owed` with the nodes, slots and calling lines named (backlog F111).",
688 },
689 Door {
690 rust: "Core::frame_unchanged",
691 c: Is("kui_frame_unchanged"),
692 odin: Is("frame_unchanged"),
693 node: Is("frameUnchanged"),
694 lua: No(GUEST),
695 doc: "Whether the last finished frame drew exactly what the one before drew, traced (backlog F111).",
696 },
697 Door {
698 rust: "Ui::request_frame",
699 c: As("`animate` on a node, and `kui_animating` for the driver to read"),
700 odin: As("`animate` on a node, and `animating` for the driver to read"),
701 node: As("the same form as C's"),
702 lua: As("the same form as C's"),
703 doc: "Asks for a frame after this one; the driver paces off `animating()`.",
704 },
705 Door {
706 rust: "Ui::modifiers",
707 c: No(
708 "the held modifiers ride on every key and pointer event's `mods`; the reader is what the stock editor's Shift-drag asks, inside the core",
709 ),
710 odin: No(ODIN_IS_C),
711 node: No("the same reason as C's"),
712 lua: No("the same reason as C's"),
713 doc: "The modifier keys held now.",
714 },
715 Door {
717 rust: "Ui::selection_text",
718 c: Is("kui_selection_text"),
719 odin: Is("selection_text"),
720 node: Is("selectionText"),
721 lua: Is("selection_text"),
722 doc: "The window's selected text — a scope's, a grid's or the focused editor's.",
723 },
724 Door {
725 rust: "Ui::selection_html",
726 c: Is("kui_selection_html"),
727 odin: Is("selection_html"),
728 node: Is("selectionHtml"),
729 lua: Is("selection_html"),
730 doc: "The same with the formatting the text declared.",
731 },
732 Door {
733 rust: "Ui::selection_ends",
734 c: Is("kui_selection_ends"),
735 odin: Is("selection_ends"),
736 node: Is("selectionEnds"),
737 lua: Is("selection_ends"),
738 doc: "A text selection's anchor and focus as row indices and bytes (ADR 0029).",
739 },
740 Door {
741 rust: "Ui::cell_selection",
742 c: Is("kui_cell_selection"),
743 odin: Is("cell_selection"),
744 node: Is("cellSelection"),
745 lua: Is("cell_selection"),
746 doc: "A `cells` grid's selection: its ends as absolute lines and columns, and whether it is a block (ADR 0017 §4).",
747 },
748 Door {
749 rust: "Ui::select_all_in",
750 c: Is("kui_select_all_in"),
751 odin: Is("select_all_in"),
752 node: Is("selectAllIn"),
753 lua: Is("select_all_in"),
754 doc: "Select All, scoped to a `selectable` node or a grid.",
755 },
756 Door {
757 rust: "Ui::clear_selection",
758 c: Is("kui_clear_selection"),
759 odin: Is("clear_selection"),
760 node: Is("clearSelection"),
761 lua: Is("clear_selection"),
762 doc: "Drops the window's selection.",
763 },
764 Door {
765 rust: "Ui::request_copy",
766 c: Is("kui_request_copy"),
767 odin: Is("request_copy"),
768 node: Is("requestCopy"),
769 lua: Is("request_copy"),
770 doc: "Asks for the selection as a copy, which may come back as a `selectionrange` question.",
771 },
772 Door {
773 rust: "Ui::answer_selection_range",
774 c: Is("kui_answer_selection_range"),
775 odin: Is("answer_selection_range"),
776 node: Is("answerSelectionRange"),
777 lua: Is("answer_selection_range"),
778 doc: "The app's answer to that question.",
779 },
780 Door {
781 rust: "Ui::set_clipboard",
782 c: Is("kui_set_clipboard"),
783 odin: Is("set_clipboard"),
784 node: Is("setClipboard"),
785 lua: Is("set_clipboard"),
786 doc: "A key sink's own Ctrl-C: posts a clipboard action for the host (backlog C33).",
787 },
788 Door {
789 rust: "Ui::set_clipboard_secret",
790 c: Is("kui_set_clipboard_secret"),
791 odin: Is("set_clipboard_secret"),
792 node: Is("setClipboardSecret"),
793 lua: Is("set_clipboard_secret"),
794 doc: "Posts a secret for the clipboard, which the host writes marked concealed and transient the way a password manager does, so no clipboard manager shows or keeps it (backlog F84).",
795 },
796 Door {
797 rust: "Ui::request_paste",
798 c: Is("kui_request_paste"),
799 odin: Is("request_paste"),
800 node: Is("requestPaste"),
801 lua: Is("request_paste"),
802 doc: "A key sink's own Ctrl-V: the clipboard comes back as a commit, marked `concealed` / `transient` when the pasteboard said so (backlog F84). One ask at a time — a second while one is unanswered is dropped.",
803 },
804 Door {
805 rust: "Ui::awaiting_paste",
806 c: Is("kui_awaiting_paste"),
807 odin: Is("awaiting_paste"),
808 node: Is("awaitingPaste"),
809 lua: Is("awaiting_paste"),
810 doc: "Whether a paste asked for is still unanswered (backlog AR34).",
811 },
812 Door {
813 rust: "Ui::request_files",
814 c: Is("kui_request_files"),
815 odin: Is("request_files"),
816 node: Is("requestFiles"),
817 lua: Is("request_files"),
818 doc: "Asks for the platform's Open, Save or folder dialog; the answer is a `files` event to whoever asked. One at a time — a second while one is out is dropped (backlog C51).",
819 },
820 Door {
821 rust: "Ui::awaiting_files",
822 c: Is("kui_awaiting_files"),
823 odin: Is("awaiting_files"),
824 node: Is("awaitingFiles"),
825 lua: Is("awaiting_files"),
826 doc: "Whether a file dialog asked for is still unanswered.",
827 },
828 Door {
829 rust: "Core::take_file_requests",
830 c: As("`kui_take_file_request`, then `kui_file_request_filter` per filter"),
831 odin: As("`take_file_request`, then `file_request_filter` per filter"),
832 node: Is("takeFileRequests"),
833 lua: No(GUEST),
834 doc: "Drains the dialog asked for, for a host that shows it itself; the runner does. The answer goes back as input (`Ctx.answerFiles`, `kui_input_files`).",
835 },
836 Door {
837 rust: "Core::set_lookup_available",
838 c: Is("kui_set_lookup_available"),
839 odin: Is("set_lookup_available"),
840 node: Is("setLookupAvailable"),
841 lua: No(GUEST),
842 doc: "Whether the host can show the platform's definition panel, which decides whether Look Up is offered.",
843 },
844 Door {
846 rust: "Ui::open_menu",
847 c: Is("kui_open_menu"),
848 odin: Is("open_menu"),
849 node: Is("openMenu"),
850 lua: Is("open_menu"),
851 doc: "Opens a context menu on a node at a point.",
852 },
853 Door {
854 rust: "Ui::close_menu",
855 c: Is("kui_close_menu"),
856 odin: Is("close_menu"),
857 node: Is("closeMenu"),
858 lua: Is("close_menu"),
859 doc: "Closes it.",
860 },
861 Door {
862 rust: "Core::take_menu_actions",
863 c: Is("kui_take_menu_action"),
864 odin: Is("take_menu_action"),
865 node: Is("takeMenuActions"),
866 lua: As(
867 "a chosen row comes back as a `menu` event on the node; the clipboard actions are the host's",
868 ),
869 doc: "Drains what a menu (or a chord, or the standard bar) asked of the host: a clipboard write, a paste, a Look Up.",
870 },
871 Door {
872 rust: "Core::menu",
873 c: As(
874 "`kui_menu_item_count` / `kui_menu_item`, one row at a time, and a submenu's by path with `kui_menu_submenu_count` / `kui_menu_item_path`",
875 ),
876 odin: As(
877 "`menu_item_count` / `menu_item`, one row at a time, and a submenu's by path with `menu_submenu_count` / `menu_item_path`",
878 ),
879 node: Is("menu"),
880 lua: No(GUEST),
881 doc: "The open menu, for a host showing it natively.",
882 },
883 Door {
884 rust: "Core::set_native_menus",
885 c: Is("kui_set_native_menus"),
886 odin: Is("set_native_menus"),
887 node: Is("setNativeMenus"),
888 lua: No(GUEST),
889 doc: "Whether the host shows menus itself; the core then draws none.",
890 },
891 Door {
892 rust: "Core::activate_menu_item",
893 c: Is("kui_activate_menu_item"),
894 odin: Is("activate_menu_item"),
895 node: Is("activateMenuItem"),
896 lua: No(GUEST),
897 doc: "Reports that the host's own menu chose a row; a row that cannot be chosen (disabled, a separator) is refused and the menu stays open.",
898 },
899 Door {
900 rust: "Core::activate_menu_path",
901 c: Is("kui_activate_menu_path"),
902 odin: Is("activate_menu_path"),
903 node: Is("activateMenuPath"),
904 lua: No(GUEST),
905 doc: "`activate_menu_item` for a row inside a submenu, by its path through the rows' submenus (backlog F128); a row that opens a submenu is refused.",
906 },
907 Door {
908 rust: "Core::menu_bar",
909 c: As(
910 "`kui_menu_bar_menu_count` / `kui_menu_bar_menu` / `kui_menu_bar_item`, one row at a time, and a submenu's by path with `kui_menu_bar_submenu_count` / `kui_menu_bar_item_path`",
911 ),
912 odin: As(
913 "`menu_bar_menu_count` / `menu_bar_menu` / `menu_bar_item`, one row at a time, and a submenu's by path with `menu_bar_submenu_count` / `menu_bar_item_path`",
914 ),
915 node: Is("menuBar"),
916 lua: No(GUEST),
917 doc: "The declared menu bar, for a host handing it to the OS.",
918 },
919 Door {
920 rust: "Core::set_native_menu_bar",
921 c: Is("kui_set_native_menu_bar"),
922 odin: Is("set_native_menu_bar"),
923 node: Is("setNativeMenuBar"),
924 lua: No(GUEST),
925 doc: "Whether the host owns the bar; the core then draws no strip.",
926 },
927 Door {
928 rust: "Core::activate_menu_bar_item",
929 c: Is("kui_activate_menu_bar_item"),
930 odin: Is("activate_menu_bar_item"),
931 node: Is("activateMenuBarItem"),
932 lua: No(GUEST),
933 doc: "Reports that the OS bar chose a row.",
934 },
935 Door {
936 rust: "Core::activate_menu_bar_path",
937 c: Is("kui_activate_menu_bar_path"),
938 odin: Is("activate_menu_bar_path"),
939 node: Is("activateMenuBarPath"),
940 lua: No(GUEST),
941 doc: "`activate_menu_bar_item` for a row inside a submenu, by its path (backlog F128).",
942 },
943 Door {
945 rust: "Ui::window",
946 c: Is("kui_window_declare"),
947 odin: Is("window_declare"),
948 node: As("the root's `windows` prop"),
949 lua: As("the root's `windows` field"),
950 doc: "Declares that a named window exists this frame (ADR 0003 step 3).",
951 },
952 Door {
953 rust: "Core::windows",
954 c: As("the ids arrive on `KUI_CMD_OPEN`; a host keeps the list it opened"),
955 odin: As(
956 "the ids arrive on `take_window_command`'s `.Open`; a host keeps the list it opened",
957 ),
958 node: Is("windows"),
959 lua: No(GUEST),
960 doc: "The names of the windows open now.",
961 },
962 Door {
963 rust: "Ui::window_name",
964 c: Is("kui_ctx_window_name"),
965 odin: Is("ctx_window_name"),
966 node: Is("windowName"),
967 lua: As("`env.window.name`, a reading"),
968 doc: "The name of the window this context draws.",
969 },
970 Door {
971 rust: "Ui::set_window_size",
972 c: Is("kui_set_window_size"),
973 odin: Is("set_window_size"),
974 node: Is("setWindowSize"),
975 lua: Is("set_window_size"),
976 doc: "Asks the driver to resize a window.",
977 },
978 Door {
979 rust: "Ui::focus_window",
980 c: Is("kui_focus_window"),
981 odin: Is("focus_window"),
982 node: Is("focusWindow"),
983 lua: Is("focus_window"),
984 doc: "Asks the driver to bring a window to the front.",
985 },
986 Door {
987 rust: "Ui::window_title",
988 c: Is("kui_window_title"),
989 odin: Is("window_title"),
990 node: As("the root's `title` prop"),
991 lua: As("the root's `title` field"),
992 doc: "Declares the window's title this frame.",
993 },
994 Door {
995 rust: "Ui::always_on_top",
996 c: Is("kui_set_always_on_top"),
997 odin: Is("set_always_on_top"),
998 node: As("the root's `alwaysOnTop` prop"),
999 lua: As("the root's `always_on_top` field"),
1000 doc: "Declares that the window sits above every other app's this frame (backlog C30).",
1001 },
1002 Door {
1003 rust: "Ui::secure_input",
1004 c: Is("kui_set_secure_input"),
1005 odin: Is("set_secure_input"),
1006 node: As("the root's `secureInput` prop"),
1007 lua: As("the root's `secure_input` field"),
1008 doc: "Declares that this frame wants secure keyboard entry while the window has the keyboard — a password prompt (backlog F85).",
1009 },
1010 Door {
1011 rust: "Ui::option_as_alt",
1012 c: Is("kui_set_option_as_alt"),
1013 odin: Is("set_option_as_alt"),
1014 node: As("the root's `optionAsAlt` prop"),
1015 lua: As("the root's `option_as_alt` field"),
1016 doc: "Declares which Option keys act as Alt in this window on macOS, so a dead key like ⌥u arrives as `<A-u>` (backlog F113).",
1017 },
1018 Door {
1019 rust: "Ui::ime_off",
1020 c: Is("kui_set_ime_off"),
1021 odin: Is("set_ime_off"),
1022 node: As("the root's `imeOff` prop"),
1023 lua: As("the root's `ime_off` field"),
1024 doc: "Declares that this window takes the keyboard as keys, with the input method off — no composition, and on a Mac no dead keys and no press-and-hold, so a held letter repeats (backlog F125).",
1025 },
1026 Door {
1027 rust: "Ui::window_command",
1028 c: As(
1029 "the chrome roles (`KuiSpec.window_role`) are the door; the verb is what `widgets::window_buttons` lowers to",
1030 ),
1031 odin: As("`window` on a node (`Spec.window`, the chrome roles) is the door"),
1032 node: As(
1033 "`KuiWindow.close()` for the one command the runner takes from outside a frame; the rest are `windowRole`",
1034 ),
1035 lua: As("`window_role`"),
1036 doc: "Minimize, toggle-maximize, start-drag, close — what a chrome node asks for on a press.",
1037 },
1038 Door {
1039 rust: "Core::window_title",
1040 c: Is("kui_window_title_get"),
1041 odin: Is("window_title_get"),
1042 node: Is("Ctx.windowTitle"),
1043 lua: No(GUEST),
1044 doc: "What the frame declared, for a driver applying it; a `KuiWindow` applies its own.",
1045 },
1046 Door {
1047 rust: "Core::always_on_top",
1048 c: Is("kui_always_on_top_get"),
1049 odin: Is("always_on_top_get"),
1050 node: Is("Ctx.alwaysOnTop"),
1051 lua: As("`env.window.always_on_top`, a reading"),
1052 doc: "The same for the level.",
1053 },
1054 Door {
1055 rust: "Core::secure_input",
1056 c: Is("kui_secure_input_get"),
1057 odin: Is("secure_input_get"),
1058 node: Is("Ctx.secureInput"),
1059 lua: No(GUEST),
1060 doc: "The same for the secure-input ask: what a driver with its own loop reads to make the platform call; the runner makes it for a `KuiWindow` and `kui_run`.",
1061 },
1062 Door {
1063 rust: "Core::option_as_alt",
1064 c: Is("kui_option_as_alt_get"),
1065 odin: Is("option_as_alt_get"),
1066 node: Is("Ctx.optionAsAlt"),
1067 lua: No(GUEST),
1068 doc: "The same for the Option-as-Alt ask: what a driver with its own loop reads to apply it to its window; the runner applies it for a `KuiWindow` and `kui_run`.",
1069 },
1070 Door {
1071 rust: "Core::ime_off",
1072 c: Is("kui_ime_off_get"),
1073 odin: Is("ime_off_get"),
1074 node: Is("Ctx.imeOff"),
1075 lua: No(GUEST),
1076 doc: "The same for the input-method ask: what a driver with its own loop reads to apply it to its window; the runner applies it for a `KuiWindow` and `kui_run`.",
1077 },
1078 Door {
1079 rust: "Core::take_window_commands",
1080 c: Is("kui_take_window_command"),
1081 odin: Is("take_window_command"),
1082 node: Is("Ctx.windowCommands"),
1083 lua: No(GUEST),
1084 doc: "Drains what the frame asked of the driver: open, close, resize, focus, redraw.",
1085 },
1086 Door {
1087 rust: "Core::window_closed",
1088 c: Is("kui_window_closed"),
1089 odin: Is("window_closed"),
1090 node: Is("Ctx.windowClosed"),
1091 lua: No(GUEST),
1092 doc: "The driver reports a window gone.",
1093 },
1094 Door {
1095 rust: "Core::dismiss_window",
1096 c: Is("kui_window_dismissed"),
1097 odin: Is("window_dismissed"),
1098 node: Is("Ctx.windowDismissed"),
1099 lua: No(GUEST),
1100 doc: "The driver reports a popup dismissed, with why (ADR 0003 step 4).",
1101 },
1102 Door {
1104 rust: "Core::set_theme",
1105 c: Is("kui_theme_set"),
1106 odin: Is("theme_set"),
1107 node: Is("setTheme"),
1108 lua: No("read-only: the palette is the host's (ADR 0019)"),
1109 doc: "Pins a whole palette.",
1110 },
1111 Door {
1112 rust: "Core::set_accent",
1113 c: Is("kui_theme_set_accent"),
1114 odin: Is("theme_set_accent"),
1115 node: Is("setAccent"),
1116 lua: No("as `set_theme`"),
1117 doc: "Pins an accent and keeps the OS's base.",
1118 },
1119 Door {
1120 rust: "Ui::theme",
1121 c: Is("kui_theme"),
1122 odin: Is("theme"),
1123 node: Is("theme"),
1124 lua: As("`env.theme`, a reading"),
1125 doc: "The palette in effect (`THEME_ROLES`).",
1126 },
1127 Door {
1128 rust: "Core::set_metrics",
1129 c: Is("kui_metrics_set"),
1130 odin: Is("metrics_set"),
1131 node: Is("setMetrics"),
1132 lua: No("as `set_theme` (backlog T2)"),
1133 doc: "Pins the stock widgets' sizes.",
1134 },
1135 Door {
1136 rust: "Ui::metrics",
1137 c: Is("kui_metrics"),
1138 odin: Is("metrics"),
1139 node: Is("metrics"),
1140 lua: As("`env.metrics`, a reading"),
1141 doc: "The sizes in effect (`METRIC_ROLES`).",
1142 },
1143 Door {
1144 rust: "Ui::set_tokens",
1145 c: Is("kui_tokens_set"),
1146 odin: Is("tokens_set"),
1147 node: Is("setTokens"),
1148 lua: Is("set_tokens"),
1149 doc: "Declares the origin's colour and length tokens (ADR 0027).",
1150 },
1151 Door {
1152 rust: "Tokens::derive",
1153 c: Is("kui_tokens_derive"),
1154 odin: Is("tokens_derive"),
1155 node: As("a colour with `from` in `setTokens`"),
1156 lua: As("a colour with `from` in `set_tokens`"),
1157 doc: "Adds derived colours to the declared ones (ADR 0028).",
1158 },
1159 Door {
1160 rust: "Ui::tokens",
1161 c: As("`kui_token_color` / `kui_token_length`, one name at a time"),
1162 odin: As("`token_color` / `token_length`, one name at a time"),
1163 node: Is("tokens"),
1164 lua: As("`env.tokens`, a reading"),
1165 doc: "The tokens in effect, resolved for the appearance.",
1166 },
1167 Door {
1168 rust: "Core::tokens_declared",
1169 c: No(
1170 "a plugin declares in every `kui_ext_view` and pays the parse; a reader that lets it skip the second is one line, once a plugin asks for it",
1171 ),
1172 odin: No(ODIN_IS_C),
1173 node: No("an app declares once, before its loop"),
1174 lua: No("the `tokens` global is declared once, at load"),
1175 doc: "Whether an origin declared tokens.",
1176 },
1177 Door {
1179 rust: "Core::set_diagnostics",
1180 c: Is("kui_set_diagnostics"),
1181 odin: Is("set_diagnostics"),
1182 node: Is("setDiagnostics"),
1183 lua: No(GUEST),
1184 doc: "Turns the per-frame checks on.",
1185 },
1186 Door {
1187 rust: "Core::take_warnings",
1188 c: Is("kui_take_warnings"),
1189 odin: Is("take_warnings"),
1190 node: Is("warnings"),
1191 lua: No("the host drains and the Lua runner prints"),
1192 doc: "Drains the warnings raised since the last call.",
1193 },
1194 Door {
1195 rust: "Core::warnings_raised",
1196 c: No(
1197 "the C smoke round drains `kui_take_warnings` after each frame; a non-draining reader waits for a C harness that needs one",
1198 ),
1199 odin: No(ODIN_IS_C),
1200 node: Is("warningsRaised"),
1201 lua: No(GUEST),
1202 doc: "The warnings raised so far, undrained, which is what an example's self-check reads (ADR 0021).",
1203 },
1204 Door {
1205 rust: "Core::set_devtools",
1206 c: Is("kui_set_devtools"),
1207 odin: Is("set_devtools"),
1208 node: Is("setDevtools"),
1209 lua: No(GUEST),
1210 doc: "Turns the devtools panel on.",
1211 },
1212 Door {
1213 rust: "Core::devtools",
1214 c: Is("kui_devtools"),
1215 odin: Is("devtools"),
1216 node: Is("devtools"),
1217 lua: No(GUEST),
1218 doc: "Whether it is on.",
1219 },
1220 Door {
1221 rust: "Core::set_devtools_dock",
1222 c: Is("kui_set_devtools_dock"),
1223 odin: Is("set_devtools_dock"),
1224 node: Is("setDevtoolsDock"),
1225 lua: No(GUEST),
1226 doc: "Where it sits.",
1227 },
1228 Door {
1229 rust: "Core::devtools_dock",
1230 c: Is("kui_devtools_dock"),
1231 odin: Is("devtools_dock"),
1232 node: Is("devtoolsDock"),
1233 lua: No(GUEST),
1234 doc: "Where it sits, read back.",
1235 },
1236 Door {
1237 rust: "Core::host_rect",
1238 c: Is("kui_host_rect"),
1239 odin: Is("host_rect"),
1240 node: Is("hostArea"),
1241 lua: No(GUEST),
1242 doc: "Where the frame laid the host out in the window, logical px: the viewport with its origin, which is what tells the app's quads from the dock's (backlog F92).",
1243 },
1244 Door {
1245 rust: "Core::set_devtools_theme",
1246 c: Is("kui_set_devtools_theme"),
1247 odin: Is("set_devtools_theme"),
1248 node: Is("setDevtoolsTheme"),
1249 lua: No(GUEST),
1250 doc: "Seeds the panel's theme override.",
1251 },
1252 Door {
1253 rust: "Core::set_devtools_key",
1254 c: Is("kui_set_devtools_key"),
1255 odin: Is("set_devtools_key"),
1256 node: Is("setDevtoolsKey"),
1257 lua: No(GUEST),
1258 doc: "Respells the chord that moves the keyboard into the panel (`Ctrl+Shift+I` by default).",
1259 },
1260 Door {
1261 rust: "Core::devtools_key",
1262 c: Is("kui_devtools_key"),
1263 odin: Is("devtools_key"),
1264 node: Is("devtoolsKey"),
1265 lua: No(GUEST),
1266 doc: "That chord, read back in its portable spelling.",
1267 },
1268 Door {
1269 rust: "Ui::devtools_tab",
1270 c: Is("kui_devtools_tab"),
1271 odin: Is("devtools_tab"),
1272 node: As("`<devtoolsTab name label slot/>`"),
1273 lua: As("`devtools_tab { name=, label=, slot= }`"),
1274 doc: "Declares a devtools tab an extension fills through the slot named (ADR 0032).",
1275 },
1276 Door {
1277 rust: "Ui::devtools_tab_with",
1278 c: Is("kui_devtools_tab_open"),
1279 odin: Is("devtools_tab_open"),
1280 node: As(
1281 "`<devtoolsTab name label>{() => …}</devtoolsTab>`, the function child called only while the tab is on show",
1282 ),
1283 lua: As(
1284 "`devtools_tab { name=, label=, view = function(env) … end }`, called only while the tab is on show",
1285 ),
1286 doc: "Declares a devtools tab the host draws itself, and draws it only while it is on show.",
1287 },
1288 Door {
1289 rust: "Core::devtools_shown_tab",
1290 c: No(
1291 "a C host's open answers whether the tab is on show (`kui_devtools_tab_open`); nothing encodes ahead of the core there",
1292 ),
1293 odin: No(ODIN_IS_C),
1294 node: Is("devtoolsShownTab"),
1295 lua: No("the runner's converter reads it for the script (ADR 0032, decision 3)"),
1296 doc: "The declared devtools tab on show, which a data binding reads once a frame to call the tab's function.",
1297 },
1298 Door {
1299 rust: "Core::devtools_selected",
1300 c: Is("kui_devtools_selected"),
1301 odin: Is("devtools_selected"),
1302 node: Is("devtoolsSelected"),
1303 lua: No(GUEST),
1304 doc: "The node the panel's tree tab has selected (ADR 0032, decision 4).",
1305 },
1306 Door {
1307 rust: "Core::devtools_hovered",
1308 c: Is("kui_devtools_hovered"),
1309 odin: Is("devtools_hovered"),
1310 node: Is("devtoolsHovered"),
1311 lua: No(GUEST),
1312 doc: "The tree row under the pointer.",
1313 },
1314 Door {
1315 rust: "Core::devtools_picked",
1316 c: Is("kui_devtools_picked"),
1317 odin: Is("devtools_picked"),
1318 node: Is("devtoolsPicked"),
1319 lua: No(GUEST),
1320 doc: "The node the picker is over.",
1321 },
1322 Door {
1323 rust: "Core::set_devtools_pick",
1324 c: Is("kui_set_devtools_pick"),
1325 odin: Is("set_devtools_pick"),
1326 node: Is("setDevtoolsPick"),
1327 lua: No(GUEST),
1328 doc: "Raises the panel's picker from outside it, or puts it away; raised from a declared tab, the pick lands in `devtools_selected` and the tab stays up.",
1329 },
1330 Door {
1331 rust: "Core::devtools_picking",
1332 c: Is("kui_devtools_picking"),
1333 odin: Is("devtools_picking"),
1334 node: Is("devtoolsPicking"),
1335 lua: No(GUEST),
1336 doc: "Whether the picker is up.",
1337 },
1338 Door {
1339 rust: "Core::set_devtools_selected",
1340 c: Is("kui_set_devtools_selected"),
1341 odin: Is("set_devtools_selected"),
1342 node: Is("setDevtoolsSelected"),
1343 lua: No(GUEST),
1344 doc: "Selects and reveals a node in the tree tab from outside the panel.",
1345 },
1346 Door {
1347 rust: "Core::set_devtools_tab",
1348 c: Is("kui_set_devtools_tab"),
1349 odin: Is("set_devtools_tab"),
1350 node: Is("setDevtoolsTab"),
1351 lua: No(GUEST),
1352 doc: "Shows the panel's tab named — one of its own, in any case, or a declared one, as declared — from outside the panel, as the strip's click does; a hidden panel comes back docked.",
1353 },
1354 Door {
1355 rust: "Core::devtools_current_tab",
1356 c: Is("kui_devtools_current_tab"),
1357 odin: Is("devtools_current_tab"),
1358 node: Is("devtoolsCurrentTab"),
1359 lua: No(GUEST),
1360 doc: "The tab the panel is on, by name.",
1361 },
1362 Door {
1363 rust: "Core::set_devtools_legend",
1364 c: Is("kui_set_devtools_legend"),
1365 odin: Is("set_devtools_legend"),
1366 node: Is("setDevtoolsLegend"),
1367 lua: No(GUEST),
1368 doc: "The key legend the panel's facts tab shows.",
1369 },
1370 Door {
1371 rust: "Core::set_inspect",
1372 c: Is("kui_set_inspect"),
1373 odin: Is("set_inspect"),
1374 node: Is("setInspect"),
1375 lua: No(GUEST),
1376 doc: "Turns the per-frame node snapshot behind `nodes` on.",
1377 },
1378 Door {
1379 rust: "Core::nodes",
1380 c: Is("kui_nodes"),
1381 odin: Is("nodes"),
1382 node: Is("nodes"),
1383 lua: No(GUEST),
1384 doc: "The last frame's nodes with what layout and the declarations made of them — a tree view's and an inspector's data.",
1385 },
1386 Door {
1388 rust: "Ui::add_extension",
1389 c: Is("kui_ctx_add_extension"),
1390 odin: Is("ctx_add_extension"),
1391 node: Is("Ctx.addExtension"),
1392 lua: Is("add_extension"),
1393 doc: "Loads a plugin under a namespace; a `KuiWindow` takes its list at construction (`extensions`).",
1394 },
1395 Door {
1396 rust: "Launcher::extensions",
1397 c: As("`kui_ctx_extension_count` / `kui_ctx_extension_namespace`, one at a time"),
1398 odin: As("`ctx_extension_count` / `ctx_extension_namespace`, one at a time"),
1399 node: Is("Ctx.extensionNamespaces"),
1400 lua: Is("extension_namespaces"),
1401 doc: "The namespaces loaded.",
1402 },
1403 Door {
1407 rust: "Core::frame",
1408 c: As("`kui_frame_begin` … `kui_frame_finish`"),
1409 odin: As("`frame_begin` … `frame_finish`, or `kui.frame` around a view"),
1410 node: Is("Ctx.frame"),
1411 lua: No(GUEST),
1412 doc: "Runs one frame: the view, layout, the draw list; `KuiWindow.setView` is the windowed form, the runner calling it.",
1413 },
1414 Door {
1415 rust: "Core::output",
1416 c: Is("kui_draw_data"),
1417 odin: Is("draw_data"),
1418 node: Is("quads"),
1419 lua: No(GUEST),
1420 doc: "The draw list: quads, clips, fragment and texture draws (`clips`, `fragmentDraws`, `textureDraws` beside `quads` in Node) and the frame's stats.",
1421 },
1422 Door {
1423 rust: "Core::take_pending_events",
1424 c: Is("kui_poll_event"),
1425 odin: Is("poll_event"),
1426 node: Is("pollEvents"),
1427 lua: As("`on_event(ev)`, pushed after each frame"),
1428 doc: "What the frame and the input since produced, for `update`.",
1429 },
1430 Door {
1431 rust: "Core::set_time",
1432 c: Is("kui_set_time"),
1433 odin: Is("set_time"),
1434 node: Is("Ctx.setTime"),
1435 lua: No(GUEST),
1436 doc: "The clock the tweens read; a window's runner sets it from the display.",
1437 },
1438 Door {
1439 rust: "Core::env",
1440 c: As("`kui_env_set` and its four siblings, `ENV_FIELDS`' C column"),
1441 odin: As("`env_set` and its four siblings"),
1442 node: Is("Ctx.setEnv"),
1443 lua: No(GUEST),
1444 doc: "The host facts written in (the `env` field); a `KuiWindow`'s runner writes its own.",
1445 },
1446 Door {
1447 rust: "Ui::env",
1448 c: No("C is the host, so it writes the facts and has no reading (`ENV_FIELDS`)"),
1449 odin: No(ODIN_IS_C),
1450 node: Is("env"),
1451 lua: As("`env`, the view's argument"),
1452 doc: "The facts read back, `ENV_FIELDS` row for row.",
1453 },
1454 Door {
1455 rust: "Core::handle_input",
1456 c: As("`kui_input_cursor` … `kui_input_access`, one per `InputEvent`"),
1457 odin: As(
1458 "`input_cursor` … `input_access`, one per input event; `click` and `press` for a drive",
1459 ),
1460 node: As(
1461 "`Ctx.cursor` … `Ctx.access`, one per `InputEvent`; a `KuiWindow` refuses injection",
1462 ),
1463 lua: No(GUEST),
1464 doc: "Pointer, wheel, key, text, IME, assistive and OS file-drag input; a wheel gesture's latching is `scroll_gesture` (`kui_input_scroll_gesture`, `Ctx.scrollGesture`, backlog F107); `press` / `release` are a click by label (`kui_input_press`, `Ctx.press`); the file drag is `drag_files` / `drop_files` / `drag_cancel` (ADR 0031); a file dialog's answer is `answer_files` (`kui_input_files`, `Ctx.answerFiles`, backlog C51); the documents the OS asked the app to open are `InputEvent::Open` (`kui_input_open`, `Ctx.openDocuments`, backlog F124).",
1465 },
1466 Door {
1467 rust: "Core::modifiers",
1468 c: Is("kui_input_modifiers"),
1469 odin: Is("input_modifiers"),
1470 node: Is("Ctx.modifiers"),
1471 lua: No(GUEST),
1472 doc: "The modifier state, reported on its own when the OS does (backlog AR22).",
1473 },
1474 Door {
1475 rust: "Core::release_held_keys",
1476 c: Is("kui_release_held_keys"),
1477 odin: Is("release_held_keys"),
1478 node: As(
1479 "`Ctx.setEnv({focused: false})` releases, as losing the keyboard does for every driver (ADR 0020)",
1480 ),
1481 lua: No(GUEST),
1482 doc: "Lets go of every key the focused sink holds.",
1483 },
1484 Door {
1485 rust: "Core::set_subpixel_text",
1486 c: Is("kui_set_subpixel_text"),
1487 odin: Is("set_subpixel_text"),
1488 node: No(NEVER_PAINTS),
1489 lua: No(GUEST),
1490 doc: "LCD subpixel coverage for outline glyphs, for a renderer that blends per channel.",
1491 },
1492 Door {
1493 rust: "Core::take_audio_commands",
1494 c: Is("kui_take_audio_commands"),
1495 odin: Is("take_audio_commands"),
1496 node: Is("Ctx.audioCommands"),
1497 lua: No(GUEST),
1498 doc: "Drains what the frame asked of the audio device; a `KuiWindow`'s device is the runner's.",
1499 },
1500 Door {
1501 rust: "Core::audio_ended",
1502 c: Is("kui_audio_ended"),
1503 odin: Is("audio_ended"),
1504 node: Is("Ctx.audioEnded"),
1505 lua: No(GUEST),
1506 doc: "The device reports a playback over.",
1507 },
1508 Door {
1509 rust: "Core::audio_truncated",
1510 c: Is("kui_audio_truncated"),
1511 odin: Is("audio_truncated"),
1512 node: Is("Ctx.audioTruncated"),
1513 lua: No(GUEST),
1514 doc: "The device reports a stop that cut a playback short — a one-shot node's removal becomes `truncated-playback`.",
1515 },
1516 Door {
1517 rust: "Core::audio_refused",
1518 c: Is("kui_audio_refused"),
1519 odin: Is("audio_refused"),
1520 node: Is("Ctx.audioRefused"),
1521 lua: No(GUEST),
1522 doc: "The device reports a play it would not take — a `refused` sound event and `playback-refused`.",
1523 },
1524 Door {
1528 rust: "Launcher::size",
1529 c: As("`width` / `height` in the `KuiRunConfig` `kui_run_with` takes"),
1530 odin: As("`width` / `height` in the `Run_Config` `kui.run` takes"),
1531 node: As("`width` / `height` in `WindowOptions`"),
1532 lua: No(GUEST),
1533 doc: "The window's opening size; `min_size` / `max_size` / `chrome` / `text_aa` / `diagnostics` / `frame_latency` are the rest of the set, and each binding's form carries them all (`min_w`, `chrome`, `text_aa`, `diagnostics`, `frame_latency` in C; `minWidth`, `chrome`, `textAa`, `diagnostics`, `frameLatency` in Node). `Launcher::devtools` and `Launcher::core` are the two the others reach another way: `kui_set_devtools` / `setDevtools` on the context, and the context handed to `kui_run_with` *is* the core.",
1534 },
1535 Door {
1536 rust: "Launcher::icon",
1537 c: Is("kui_set_icon"),
1538 odin: Is("set_icon"),
1539 node: As("`icon` in `WindowOptions`"),
1540 lua: No(GUEST),
1541 doc: "The icon every window of the app is created with — RGBA pixels and their size — shown by Windows in the title bar, Alt-Tab and the taskbar and by X11's window manager; macOS (the bundle's `.icns`) and Wayland (the `.desktop` file's) have no window icon (backlog F86). `Launcher::icon_resource` is the Windows executable's own icon resource, which wins there — C's `resource` argument, Node's `icon.resource`. C's is a free function called before `kui_run`, for `kui_on_teardown`'s reason.",
1542 },
1543 Door {
1544 rust: "App::teardown",
1545 c: Is("kui_on_teardown"),
1546 odin: As("the `teardown` procedure `kui.run` takes"),
1547 node: Is("KuiWindow.onTeardown"),
1548 lua: No(GUEST),
1549 doc: "The window going for good — its close button, Quit from the menu or the dock, a close command on it, a pumped runner ended — heard once, before `run` returns or the process exits, with nothing drawing: the place to keep what the app would lose with the window (backlog F74, the other two hosts under RG1). On macOS a Quit ends the process from inside the loop, so this is the only thing an app runs on ⌘Q — nothing after `run`, `kui_run` or `await runWindowed(...)` does, not even `process.on('exit')`. C's is a free function called before `kui_run`, with the run's `user`, since `kui_run`'s app is three arguments and not a struct. Node's is the window's door, called from inside the pump that saw the window go; `runWindowed` registers its config's `teardown(model)` there, and `createApp`'s `app.teardown()` runs the same one for a headless drive.",
1550 },
1551];
1552
1553#[cfg(test)]
1554mod tests {
1555 use super::*;
1556
1557 #[test]
1565 fn every_rust_spelling_is_a_public_fn() {
1566 let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
1567 let read = |p: std::path::PathBuf| std::fs::read_to_string(&p).unwrap_or_default();
1568 let mut runtime = read(root.join("runtime.rs"));
1569 for dir in ["runtime", "runtime/devtools"] {
1570 for entry in std::fs::read_dir(root.join(dir)).unwrap() {
1571 let p = entry.unwrap().path();
1572 if p.extension().is_some_and(|e| e == "rs") {
1573 runtime.push_str(&read(p));
1574 }
1575 }
1576 }
1577 let ui = read(root.join("ui.rs"));
1578 let session = read(root.join("session.rs"));
1579 let tokens = read(root.join("tokens.rs"));
1580 let launcher = read(root.join("../../kui-native/src/lib.rs"));
1581 let app_trait = launcher
1584 .split_once("pub trait App {")
1585 .map(|(_, rest)| rest.split_once("\n}\n").map_or(rest, |(body, _)| body))
1586 .unwrap_or_default();
1587 for d in DOORS {
1588 let (ty, name) = d.rust.split_once("::").expect(d.rust);
1589 let src = match ty {
1590 "Ui" => &ui,
1591 "Core" => &runtime,
1592 "SharedResources" => &session,
1593 "Tokens" => &tokens,
1594 "Launcher" => &launcher,
1595 "App" => app_trait,
1596 other => panic!("{}: {other} is not a prefix the table knows", d.rust),
1597 };
1598 let (public, any) = (
1599 format!("{}fn {name}(", if ty == "App" { "" } else { "pub " }),
1600 format!("fn {name}("),
1601 );
1602 assert!(
1603 src.contains(&public) || (ty == "Core" && name == "env"),
1604 "{}: no `{public}` in {ty}'s sources{}",
1605 d.rust,
1606 if src.contains(&any) {
1607 " (a private fn is)"
1608 } else {
1609 ""
1610 }
1611 );
1612 }
1613 }
1614
1615 #[test]
1619 fn rows_are_unique_and_every_no_has_a_reason() {
1620 let mut seen = std::collections::BTreeSet::new();
1621 for d in DOORS {
1622 assert!(seen.insert(d.rust), "{} is two rows", d.rust);
1623 assert!(!d.doc.is_empty(), "{} has no doc", d.rust);
1624 for (binding, cell) in [("C", d.c), ("Node", d.node), ("Lua", d.lua)] {
1625 match cell {
1626 Is(name) => assert!(
1627 !name.is_empty() && !name.contains(' '),
1628 "{} in {binding}: {name:?} is not a name",
1629 d.rust
1630 ),
1631 As(how) | No(how) => assert!(
1632 how.len() >= 12,
1633 "{} in {binding}: {how:?} is not a reason",
1634 d.rust
1635 ),
1636 }
1637 }
1638 }
1639 }
1640
1641 #[test]
1646 fn cells_are_spelled_in_their_bindings_case() {
1647 let snake = |s: &str| {
1648 s.bytes()
1649 .all(|b| b.is_ascii_lowercase() || b == b'_' || b.is_ascii_digit())
1650 };
1651 for d in DOORS {
1652 if let Is(c) = d.c {
1653 assert!(
1654 c.starts_with("kui_") && snake(c),
1655 "{}: C cell {c:?}",
1656 d.rust
1657 );
1658 }
1659 if let Is(n) = d.node {
1660 let n = n
1661 .strip_prefix("Ctx.")
1662 .or_else(|| n.strip_prefix("KuiWindow."))
1663 .unwrap_or(n);
1664 assert!(
1665 !n.contains('_') && n.starts_with(|c: char| c.is_ascii_lowercase()),
1666 "{}: Node cell {n:?}",
1667 d.rust
1668 );
1669 }
1670 if let Is(l) = d.lua {
1671 assert!(snake(l), "{}: Lua cell {l:?}", d.rust);
1672 }
1673 }
1674 }
1675}