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