Files
tai/taicpp/docs/tui.md
T

439 lines
27 KiB
Markdown
Raw Normal View History

# tui parity (tai.py -> taicpp, `src/tui`)
Scope: every `Tui*` class and `tui_*` function of tai.py (framework, VT screen,
widgets, themes, chat scene, live block, keys, mouse) and every `Grr*` class and
`grr_*` function (the grr terminal client). Specs the code follows:
`../tui.md`, `../grrtui.md` (tables copied into tests, see below). The grr client
is a client of the grr server: it shows what `/api/spec` and `/locales.json` say,
no server string, color or limit is copied into the code (`GrrConst.h` holds only
what tai.py itself carries as fallback).
## Rules of the port
- Python class `TuiFoo` is C++ class `detz::tui::TuiFoo` in `TuiFoo.h` / `TuiFoo.cpp`.
Small related classes share a file pair and are named in its header comment.
- Module functions become static methods of the class that owns the data
(`tui_resolve_theme_name` is `TuiThemes::resolve_name`, `tui_demo` is `TuiDemo::demo`).
- Module constants become `constexpr` or static functions; names are kept where C++ allows.
- Text is `UStr` (`std::u32string`) so column math is by code point like python.
`TuiValue` is the dynamic JSON-like value (python dict/list/str/float formatting).
- No behaviour was invented: where python has a quirk the port has the same quirk.
## Declared differences (all invisible on screen)
| python | C++ | why |
|---|---|---|
| `__setattr__` change signals (`TuiObserved`, `TuiList`, `TuiDict`, `TuiSet`) | explicit setters call `relayout`, `restack` or `touch` | C++ has no attribute hook. A field written without its setter does not repaint; every field python watches has a setter |
| per-style cell pools (`TuiCellPool`) | cells are `(char32_t, interned style id)` | perf only, equal cells still compare by two integers |
| asyncio loop | one `poll()` loop with a self-pipe wake, timers and `offload` threads | same ordering contract: offload `work` runs on a thread, `done(result, error)` on the loop |
| `TuiTerminal` row memo | not kept | perf only |
| python exceptions in `offload` | `std::exception_ptr`, text through `TuiApp::describe` | same message as `str(exc)` |
| `http.client` (`GrrClient`, `GrrStream`) | libcurl | the repo already links libcurl; error texts for transport failures are mapped by hand (see gaps) |
| agent / store / vault used by the local chat scene | interfaces `TuiChatAgent`, `TuiChatHost`, `TuiHistoryBackend`, `TuiComplete::Sources` | the agent module is another port; the integrator writes the adapters (`wiring/tui.md`) |
| `GrrControl` threads | one accept thread, one thread per connection, jobs run on the UI loop | same protocol, same caps |
## Verification (what was run, not what is believed)
All differential runs compare the C++ binary with `tai.py` on the same input.
| what | how | result |
|---|---|---|
| `--demo-shot` frame | text, per-cell sgr and raw frame bytes at 30x100, 24x80, 10x30, 50x160, 8x20 | identical |
| framework scripts | 9 scenarios (keys, mouse, prompt and autocomplete, resize, spawn, shell feed, paste, kitty keys) at 30x100 and 12x40 | identical |
| chat rows, markdown, textwrap | 3318 cases, 65553 output lines, every span as `<sgr>text` | identical |
| local chat scene | 10 scenarios (send, commands, keys, bots, resize, history, completion, scroll, multiline, quit) at 30x100 and 14x50, a fake agent on both sides | identical |
| grr client against a real grr server | both binaries on a pty, driven by the control socket (`screen`, `key`, `type`, `click`, `goto`), server restored from one snapshot before each run | see below |
| grr spec drift | `tests/tui_spec.cpp` (routes, keys, caps, shapes, events, flags against `grrtui.md`) | ok |
Grr runs (screen text of every step plus per-cell fg, bg and attributes of the
pty stream replayed through python's `TuiVtScreen`, minute digits ignored):
| steps | size | text diffs | style diffs |
|---|---|---|---|
| 57 (every bot, computer, screen, chat route) | 30x100 | 0 | 0 |
| 128 (keys, mouse, dialogs, settings, language, composer) | 30x100, 24x80, 14x50 | 0 | 0 |
| 128 | 40x160 | 1 (spinner frame) | 2 steps (spinner frame) |
| 51 (pane tabs, composer, send, remote terminal) | 30x100 | 0 | 0 |
| 14 login screen, 14 offline screen | 30x100 | 0 | 0 |
The only differences ever seen were a wall clock, the database size shown in
Advanced, a chat title that the server generates after the fact, a spinner frame,
and ids the server creates. Each was traced to the environment, none to the port.
## Symbol table
344 python symbols (classes, `tui_*` / `grr_*` functions, `TUI_*` / `GRR_*` constants)
and where they live. Generated by matching names against `src/tui`; a hit means the
name is defined or used there, not that the behaviour is proven (that is the section above).
| kind | python | line in tai.py | C++ |
|---|---|---|---|
| class | `TuiTheme` | 22227 | `TuiTheme.h` |
| class | `TuiWatched` | 22327 | `TuiStyle.h` |
| class | `TuiStyle` | 22369 | `TuiStyle.h` |
| class | `TuiSpan` | 22490 | `TuiStyle.h` |
| class | `TuiEvent` | 22517 | `TuiEvent.h` |
| class | `TuiKey` | 22536 | `GrrControl.h`, `TuiEvent.h` |
| class | `TuiClick` | 22540 | `TuiEvent.h` |
| class | `TuiScroll` | 22544 | `TuiEvent.h` |
| class | `TuiFocus` | 22548 | `TuiEvent.h` |
| class | `TuiBlur` | 22553 | `TuiEvent.h` |
| class | `TuiResize` | 22558 | `TuiEvent.h` |
| class | `TuiTick` | 22563 | `TuiEvent.h` |
| class | `TuiModeReply` | 22568 | `TuiEvent.h` |
| class | `TuiMount` | 22576 | `TuiEvent.h` |
| class | `TuiUnmount` | 22581 | `TuiEvent.h` |
| class | `TuiSelect` | 22586 | `TuiEvent.h` |
| class | `TuiPress` | 22590 | `TuiEvent.h` |
| class | `TuiClose` | 22594 | `TuiEvent.h` |
| class | `TuiPaste` | 22598 | `TuiEvent.h` |
| class | `TuiChange` | 22602 | `TuiEvent.h` |
| class | `TuiObserved` | 22702 | replaced by explicit setters (relayout, restack, touch) and `TuiWatched` in `TuiStyle.h` |
| class | `TuiList` | 22739 | replaced by explicit setters (see TuiObserved) |
| class | `TuiDict` | 22774 | replaced by explicit setters (see TuiObserved) |
| class | `TuiSet` | 22803 | replaced by explicit setters (see TuiObserved) |
| class | `TuiPanel` | 22863 | `TuiEvent.h`, `TuiPanel.h`, `TuiStyle.h` |
| class | `TuiRows` | 23552 | `TuiPanel.h` |
| class | `TuiCols` | 23562 | `TuiPanel.h` |
| class | `TuiCellPool` | 23618 | omitted on purpose: cells are `(char32_t, style id)` values, equal cells compare as two integers; perf only |
| class | `TuiCompositor` | 23633 | `TuiCompositor.h`, `TuiPanel.h` |
| class | `TuiHitMap` | 24053 | `TuiHitMap.h` |
| class | `TuiInput` | 24383 | `TuiInput.h` |
| class | `TuiVtScreen` | 24423 | `TuiVtScreen.h` |
| class | `TuiText` | 25066 | `TuiText.h` |
| class | `TuiRich` | 25123 | `TuiRich.h` |
| class | `TuiButton` | 25164 | `TuiButton.h` |
| class | `TuiOptions` | 25216 | `TuiOptions.h` |
| class | `TuiChatList` | 25356 | `TuiChatList.h` |
| class | `TuiAutocomplete` | 25429 | `TuiAutocomplete.h` |
| class | `TuiHistory` | 25527 | `TuiHistory.h` |
| class | `TuiTextBox` | 25589 | `TuiTextBox.h` |
| class | `TuiDialog` | 25945 | `TuiDialog.h` |
| class | `TuiQuestion` | 25978 | `TuiDialog.h` |
| class | `TuiPromptDialog` | 26007 | `TuiDialog.h` |
| class | `TuiProgress` | 26027 | `TuiProgress.h` |
| class | `TuiLog` | 26050 | `TuiLog.h` |
| class | `TuiTerminal` | 26199 | `TuiApp.h`, `TuiTerminal.h` |
| class | `TuiError` | 26406 | `TuiApp.h` |
| class | `TuiDoubleTap` | 26410 | `TuiDoubleTap.h` |
| class | `TuiApp` | 26429 | `TuiApp.cpp`, `TuiApp.h`, `TuiPanel.h` |
| class | `TuiChatLog` | 27959 | `TuiChatLog.h` |
| class | `TuiChatSession` | 28022 | `TuiChatSession.h` |
| class | `TuiChatState` | 28043 | members of `TuiChatScene` plus `TuiChatSession.h` |
| class | `TuiLiveStream` | 28071 | `TuiLiveStream.h` |
| class | `TuiStdioGuard` | 28095 | `TuiStdioGuard.h` |
| class | `GrrError` | 28938 | `GrrError.h` |
| class | `GrrStrings` | 28956 | `GrrStrings.h` |
| class | `GrrPalette` | 29018 | `GrrPalette.h` |
| class | `GrrUi` | 29071 | `GrrUi.h` |
| class | `GrrFormat` | 29103 | `GrrFormat.h` |
| class | `GrrAvatar` | 29205 | `GrrAvatar.h` |
| class | `GrrClient` | 29259 | `GrrClient.h` |
| class | `GrrStream` | 29353 | `GrrStream.h` |
| class | `GrrSession` | 29453 | `GrrSession.h` |
| class | `GrrEmitter` | 29509 | `GrrEmitter.h` |
| class | `GrrStore` | 29533 | `GrrStore.h` |
| class | `GrrRoute` | 29605 | `GrrRouter.h` |
| class | `GrrRouter` | 29615 | `GrrRouter.h` |
| class | `GrrCard` | 29709 | `GrrItem.h` |
| class | `GrrItem` | 29739 | `GrrItem.h`, `GrrText.h` |
| class | `GrrSpacer` | 29799 | `GrrItems.h` |
| class | `GrrLabel` | 29808 | `GrrItems.h` |
| class | `GrrHeading` | 29820 | `GrrItems.h` |
| class | `GrrNote` | 29833 | `GrrItems.h` |
| class | `GrrRowItem` | 29849 | `GrrItems.h` |
| class | `GrrConvItem` | 29944 | `GrrItems.h` |
| class | `GrrSectionHead` | 29990 | `GrrItems.h` |
| class | `GrrButtonItem` | 30009 | `GrrItems.h` |
| class | `GrrTextCard` | 30050 | `GrrItems.h` |
| class | `GrrTabsItem` | 30077 | `GrrItems.h` |
| class | `GrrSegmentedItem` | 30144 | `GrrItems.h` |
| class | `GrrChipsItem` | 30183 | `GrrItems.h` |
| class | `GrrDividerItem` | 30222 | `GrrItems.h` |
| class | `GrrEmptyItem` | 30237 | `GrrItems.h` |
| class | `GrrKvItem` | 30256 | `GrrItems.h` |
| class | `GrrProgressItem` | 30276 | `GrrItems.h` |
| class | `GrrBarsItem` | 30303 | `GrrItems.h` |
| class | `GrrTileGridItem` | 30320 | `GrrItems.h` |
| class | `GrrPage` | 30392 | `GrrItem.h`, `GrrPage.h` |
| class | `GrrBar` | 30654 | `GrrBar.h` |
| class | `GrrTuiApp` | 30716 | `GrrTuiApp.h` |
| class | `GrrSecretBox` | 30739 | `GrrSecretBox.h` |
| class | `GrrMenu` | 30764 | `GrrMenu.h` |
| class | `GrrToast` | 30871 | `GrrMenu.h` |
| class | `GrrWelcome` | 30884 | `GrrMenu.h` |
| class | `GrrScreen` | 30907 | `GrrScreen.h` |
| class | `GrrView` | 30962 | `GrrView.h` |
| class | `GrrShell` | 31046 | `GrrChatItems.h`, `GrrControl.h`, `GrrFileViewer.h` |
| class | `GrrHome` | 31643 | `GrrHome.h`, `GrrShell.h` |
| class | `GrrBots` | 31739 | `GrrHome.h` |
| class | `GrrLoginView` | 31784 | `GrrViewsBots.h` |
| class | `GrrStripItem` | 31879 | `GrrItems.h` |
| class | `GrrBotsView` | 31931 | `GrrViewsBots.h` |
| class | `GrrProfileView` | 31970 | `GrrViewsBots.h` |
| class | `GrrHeroItem` | 32141 | `GrrItems.h` |
| class | `GrrNameCard` | 32156 | `GrrItems.h` |
| class | `GrrSwatchItem` | 32197 | `GrrItems.h` |
| class | `GrrScreenPreview` | 32235 | `GrrItems.h` |
| class | `GrrInstructionsView` | 32253 | `GrrViewsBots.h` |
| class | `GrrListView` | 32287 | `GrrViewsBots.h` |
| class | `GrrMemoriesView` | 32323 | `GrrViewsBots.h` |
| class | `GrrSkillsView` | 32341 | `GrrViewsBots.h` |
| class | `GrrMemoryView` | 32369 | `GrrViewsBots.h` |
| class | `GrrSkillView` | 32394 | `GrrViewsBots.h` |
| class | `GrrRoutineItem` | 32423 | `GrrItems.h` |
| class | `GrrAutomationsView` | 32454 | `GrrViewsAuto.h` |
| class | `GrrAutomationView` | 32550 | `GrrViewsAuto.h` |
| class | `GrrNewAutomationView` | 32612 | `GrrViewsAuto.h` |
| class | `GrrLibraryView` | 32687 | `GrrViewsLib.h` |
| class | `GrrProjectsView` | 32758 | `GrrViewsLib.h` |
| class | `GrrProjectView` | 32805 | `GrrViewsLib.h` |
| class | `GrrSearchView` | 32856 | `GrrViewsLib.h` |
| class | `GrrSettingsView` | 32941 | `GrrViewsSettings.h` |
| class | `GrrSubView` | 32989 | `GrrViewsSettings.h` |
| class | `GrrAccountView` | 33009 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrUsageView` | 33035 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrRulesView` | 33076 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrRuleView` | 33092 | `GrrViewsSettings.h` |
| class | `GrrAppearanceView` | 33143 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrLanguageView` | 33168 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrHapticsView` | 33179 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrWidgetView` | 33187 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrComputersView` | 33198 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrConnectorsView` | 33232 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrAdvancedView` | 33245 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrBuilderView` | 33297 | declared with the `GRR_SUBVIEW` macro in `GrrViewsSettings.h` |
| class | `GrrFeedbackView` | 33335 | `GrrViewsSettings.h` |
| class | `GrrTimezoneView` | 33369 | `GrrViewsSettings.h` |
| class | `GrrTemplateView` | 33399 | `GrrViewsSettings.h` |
| class | `GrrTemplatePartView` | 33445 | `GrrViewsSettings.h` |
| class | `GrrPublicTemplateView` | 33465 | `GrrViewsSettings.h` |
| class | `GrrShellExtras` | 33485 | `GrrShell::copy_text`, `open_url`, `open_file` in `GrrShell.h` |
| class | `GrrFileViewer` | 33515 | `GrrFileViewer.h` |
| class | `GrrControlsItem` | 33606 | `GrrChatItems.h` |
| class | `GrrMessageItem` | 33628 | `GrrChatItems.h` |
| class | `GrrApprovalItem` | 33740 | `GrrChatItems.h` |
| class | `GrrQuestionItem` | 33793 | `GrrChatItems.h` |
| class | `GrrFileMsgItem` | 33841 | `GrrChatItems.h` |
| class | `GrrFilesMsgItem` | 33870 | `GrrChatItems.h` |
| class | `GrrTemplateMsgItem` | 33909 | `GrrChatItems.h` |
| class | `GrrRemoteTerminal` | 33952 | `GrrChatItems.h` |
| class | `GrrProcessItem` | 34055 | `GrrChatItems.h` |
| class | `GrrComposerBox` | 34229 | `GrrChat.h` |
| class | `GrrChatView` | 34250 | `GrrChat.h`, `GrrChatItems.h`, `GrrPane.h` |
| class | `GrrComputerView` | 34946 | `GrrChat.h` |
| class | `GrrScreenView` | 35011 | `GrrChat.h` |
| class | `GrrPane` | 35044 | `GrrChat.h`, `GrrPane.h` |
| class | `GrrPaneTab` | 35168 | `GrrPane.h` |
| class | `GrrPaneFiles` | 35193 | `GrrPane.h` |
| class | `GrrPanePreview` | 35337 | `GrrPane.h` |
| class | `GrrPaneDeploy` | 35469 | `GrrPane.h` |
| class | `GrrControl` | 35492 | `GrrControl.h`, `GrrShell.h` |
| const | `TUI_FPS` | 22199 | `TuiApp.h` |
| const | `TUI_INPUT_PAINT_GAP` | 22202 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_GEOMETRY` | 22204 | geometry setters of `TuiPanel` (`set_x`, `set_y`, `set_w`, `set_h`) |
| const | `TUI_DECLRMM` | 22205 | `TuiApp.cpp`, `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_CELL_KEY` | 22206 | `TuiCell::key` in `TuiCell.h` |
| const | `TUI_SWITCH_COST` | 22207 | `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_MOVE_COST` | 22208 | `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_SCROLL_SLACK` | 22209 | `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_MIN_ROWS` | 22211 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_MIN_COLS` | 22213 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_LAYERS` | 22215 | layer to z base in `TuiPanel.cpp` (base 0, panel 10, dialog 20, toast 30) |
| const | `TUI_COLORS` | 22217 | color name table in `TuiStyle.cpp` and `TuiVtScreen.cpp` |
| const | `TUI_THEME_ROLES` | 22219 | `TuiTheme.h` |
| const | `TUI_THEME_DEFAULT` | 22224 | `TuiTheme.h` |
| const | `TUI_THEMES` | 22240 | `TuiTheme.h` |
| const | `TUI_THEME` | 22296 | `TuiThemes::current()` / `TuiThemes::set()` in `TuiTheme.h` |
| const | `TUI_OBSERVE_DEPTH` | 22699 | not needed (no observation proxies) |
| const | `TUI_PLAIN` | 22816 | not needed (no observation proxies) |
| const | `TUI_OBSERVING` | 22818 | not needed (no observation proxies) |
| const | `TUI_SYNC_START` | 23572 | `TuiApp.cpp`, `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_SYNC_END` | 23574 | `TuiApp.cpp`, `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_MOUSE_ENABLE` | 23576 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_MOUSE_DISABLE` | 23578 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_ALT_ENTER` | 23580 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_ALT_LEAVE` | 23582 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_KITTY_ENABLE` | 23584 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_KITTY_DISABLE` | 23586 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_PASTE_ENABLE` | 23588 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_PASTE_DISABLE` | 23590 | `TuiApp.cpp`, `TuiApp.h` |
| const | `TUI_PASTE_OPEN` | 23592 | `TuiInput::PASTE_OPEN` |
| const | `TUI_PASTE_CLOSE` | 23594 | `TuiInput::PASTE_CLOSE` |
| const | `TUI_PASTE_CAP` | 23596 | `TuiInput::PASTE_CAP` |
| const | `TUI_COMPLETE_MAXH` | 23598 | `TuiTextBox.cpp` |
| const | `TUI_BLANK_KEY` | 23601 | `TuiCell.h` |
| const | `TUI_BLANK` | 23603 | `TuiCell::blank()` in `TuiCell.h` |
| const | `TUI_POOL_KEYS` | 23605 | omitted with TuiCellPool |
| const | `TUI_POOL_CHARS` | 23607 | omitted with TuiCellPool |
| const | `TUI_SGR_CAP` | 23609 | `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_DAMAGE_RECTS` | 23611 | `TuiApp.cpp`, `TuiCompositor.h` |
| const | `TUI_ROW_MEMO` | 23613 | `TuiLog.cpp`, `TuiLog.h` |
| const | `TUI_SCROLLS` | 23615 | `TuiCompositor.cpp`, `TuiCompositor.h` |
| const | `TUI_CSI_KEYS` | 24114 | `TuiInput::csi_keys()` |
| const | `TUI_TILDE_KEYS` | 24116 | `TuiInput::tilde_keys()` |
| const | `TUI_SS3_KEYS` | 24120 | `TuiInput::ss3_keys()` |
| const | `TUI_KITTY_NAMED` | 24122 | `kitty_named()` in `TuiInput.cpp` |
| const | `TUI_KITTY_MODS` | 24126 | `kitty_mods()` in `TuiInput.cpp` |
| const | `TUI_KITTY_PAD` | 24129 | `kitty_pad()` in `TuiInput.cpp` |
| const | `TUI_KITTY_US_SHIFT` | 24133 | `kitty_us_shift()` in `TuiInput.cpp` |
| const | `TUI_AVATAR_ROLES` | 25348 | `TuiChatList.h` |
| const | `TUI_COMMAND_HELP` | 25450 | `TuiComplete::command_help()` / `reset_command_help()` |
| const | `TUI_TERM_KEYS` | 26190 | `TuiTerminal.h` |
| const | `TUI_CHAT_SIDEBAR_MIN` | 27608 | `TuiChatRows.cpp`, `TuiChatRows.h` |
| const | `TUI_CHAT_SIDEBAR_MAX` | 27609 | `TuiChatRows.cpp`, `TuiChatRows.h` |
| const | `TUI_CHAT_NARROW_COLS` | 27610 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_INPUT_CAP` | 27611 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_HISTORY` | 27612 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_LINE_CAP` | 27613 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_ANSI_RE` | 27615 | `TuiMarkdown.h` |
| const | `TUI_CHAT_BUBBLE_MAX` | 27626 | `TuiChatRows.cpp`, `TuiChatRows.h` |
| const | `TUI_CHAT_SPINNER` | 27627 | `TuiChatRows.h` |
| const | `TUI_CHAT_ONLINE_GLYPH` | 27628 | `TuiChatRows.h` |
| const | `TUI_CHAT_TYPE_ANSWER` | 27629 | `TuiChatRows.h`, `TuiValue.h` |
| const | `TUI_CHAT_PROMPT_TIMEOUT` | 27630 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_PROMPT_CHARS` | 27631 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_REVEAL_TICK` | 27632 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_REVEAL_STEPS` | 27633 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_TICK_SEND` | 27634 | `TuiChatRows.h` |
| const | `TUI_CHAT_TICK_SENT` | 27635 | `TuiChatRows.h` |
| const | `TUI_CHAT_TICK_READ` | 27636 | `TuiChatRows.h` |
| const | `TUI_MD_INLINE_RE` | 27639 | `TuiMarkdown.h` |
| const | `TUI_MD_LIST_RE` | 27640 | `TuiMarkdown.h` |
| const | `TUI_CHAT_PAD` | 27765 | `TuiChatRows.cpp`, `TuiChatRows.h` |
| const | `TUI_STDIO_GUARD` | 28124 | `TuiStdioGuard.h` |
| const | `TUI_CHAT_BLOCK_CAP` | 28125 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `TUI_CHAT_LIVE_ROWS` | 28126 | `TuiChatRows.cpp`, `TuiChatRows.h` |
| const | `TUI_CHAT_LIVE_KEEP` | 28127 | `TuiChatRows.h`, `TuiLiveStream.cpp` |
| const | `TUI_CHAT_LIVE_TICK` | 28128 | `TuiChatRows.h`, `TuiChatScene.cpp` |
| const | `GRR_DEFAULT_URL` | 28869 | `GrrClient.cpp`, `GrrClient.h`, `GrrConst.h` |
| const | `GRR_HTTP_TIMEOUT` | 28870 | `GrrClient.h`, `GrrConst.h` |
| const | `GRR_SSE_TIMEOUT` | 28871 | `GrrConst.h`, `GrrStream.cpp` |
| const | `GRR_SSE_RETRY` | 28872 | `GrrConst.h`, `GrrStream.cpp`, `GrrStream.h` |
| const | `GRR_SSE_LINE_MAX` | 28873 | `GrrConst.h`, `GrrStream.cpp`, `GrrStream.h` |
| const | `GRR_BODY_MAX` | 28874 | `GrrClient.cpp`, `GrrConst.h`, `GrrFileViewer.cpp` |
| const | `GRR_SIDE_W` | 28875 | `GrrConst.h`, `GrrShell.cpp` |
| const | `GRR_SIDE_MIN_COLS` | 28876 | `GrrConst.h`, `GrrShell.cpp` |
| const | `GRR_PANE_MIN_COLS` | 28877 | `GrrConst.h`, `GrrPane.cpp` |
| const | `GRR_PANE_MIN_W` | 28878 | `GrrConst.h`, `GrrPane.cpp` |
| const | `GRR_PANE_MAX_W` | 28879 | `GrrConst.h`, `GrrPane.cpp` |
| const | `GRR_MESSAGE_KEEP` | 28880 | `GrrChat.cpp`, `GrrConst.h` |
| const | `GRR_TOAST_SECS` | 28881 | `GrrConst.h`, `GrrShell.cpp` |
| const | `GRR_BANNER_SECS` | 28882 | `GrrConst.h`, `GrrShell.cpp` |
| const | `GRR_TOAST_MAX` | 28883 | `GrrConst.h`, `GrrShell.cpp` |
| const | `GRR_COMPOSER_MAX_ROWS` | 28884 | `GrrChat.cpp`, `GrrConst.h` |
| const | `GRR_VIEWER_MAX_BYTES` | 28885 | `GrrClient.h`, `GrrConst.h`, `GrrFileViewer.cpp` |
| const | `GRR_PROMPT_QUIET` | 28886 | `GrrChatItems.cpp`, `GrrConst.h` |
| const | `GRR_PROMPT_ASKS` | 28887 | `GrrChatItems.cpp`, `GrrConst.h` |
| const | `GRR_PROMPT_MAX` | 28888 | `GrrChat.cpp`, `GrrConst.h` |
| const | `GRR_DRAFT_KEEP` | 28889 | `GrrChat.cpp`, `GrrConst.h` |
| const | `GRR_LIST_MORE` | 28890 | `GrrConst.h`, `GrrViewsBots.cpp`, `GrrViewsBots.h` |
| const | `GRR_MENU_MAX_H` | 28891 | `GrrConst.h`, `GrrMenu.cpp` |
| const | `GRR_PALETTE_FALLBACK` | 28893 | `GrrConst.h` |
| const | `GRR_SHAPES` | 28907 | `GrrConst.h` |
| const | `GRR_AVATAR_ROWS` | 28910 | `GrrConst.h` |
| const | `GRR_ICONS` | 28925 | `GrrConst.h` |
| const | `GRR_STRING_FALLBACK` | 28953 | `GrrConst.h` |
| const | `GRR_KEYS` | 30635 | `GrrConst.h` |
| const | `GRR_LANG_NAMES` | 31613 | `GrrConst.h` |
| const | `GRR_TEMPLATE_ASK` | 31615 | `GrrConst.h` |
| const | `GRR_FILE_ICON` | 32684 | `GrrConst.h` |
| const | `GRR_TEXT_MIMES` | 33482 | `GrrConst.h` |
| const | `GRR_CONTROL_JOBS` | 35479 | `GrrConst.h`, `GrrControl.h` |
| const | `GRR_CONTROL_LINE` | 35480 | `GrrConst.h` |
| const | `GRR_CONTROL_WAIT` | 35481 | `GrrConst.h` |
| const | `GRR_CONTROL_WAIT_MAX` | 35482 | `GrrConst.h` |
| const | `GRR_CONTROL_KEYS_MAX` | 35483 | `GrrConst.h` |
| const | `GRR_ROUTES` | 35713 | `GrrConst.h`, `GrrViews.cpp` |
| func | `tui_register_theme` | 22243 | `TuiTheme.h` |
| func | `tui_theme` | 22299 | `GrrPalette.cpp`, `GrrPalette.h`, `TuiTheme.h` |
| func | `tui_set_theme` | 22303 | `TuiTheme.h` |
| func | `tui_resolve_theme_name` | 22311 | `TuiTheme.h` |
| func | `tui_cycle_theme_name` | 22320 | `TuiTheme.h` |
| func | `tui_ease` | 22499 | `TuiApp.h` |
| func | `tui_int` | 22607 | `TuiInput.cpp` |
| func | `tui_flatten` | 22614 | `TuiStyle.h` |
| func | `tui_runs` | 22622 | `TuiStyle.h` |
| func | `tui_pad_spans` | 22641 | `TuiStyle.h` |
| func | `tui_span_width` | 22645 | `TuiStyle.h` |
| func | `tui_slice_spans` | 22652 | `TuiStyle.h` |
| func | `tui_watch` | 22726 | `GrrViewsLib.cpp`, `GrrViewsLib.h`, `TuiApp.cpp` |
| func | `tui_observe` | 22821 | replaced by explicit setters (see TuiObserved) |
| func | `tui_item` | 22848 | `GrrChat.cpp`, `GrrChat.h`, `GrrChatItems.h` |
| func | `tui_watchable` | 22859 | replaced by explicit setters (see TuiObserved) |
| func | `tui_utf8_head` | 24093 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_modifiers` | 24138 | `TuiEvent.h`, `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_parse_mouse_sgr` | 24152 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_parse_mouse_legacy` | 24179 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_parse_kitty` | 24193 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_paste_head` | 24260 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_parse_paste` | 24268 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_parse_one` | 24284 | `TuiInput.cpp`, `TuiInput.h` |
| func | `tui_avatar_role` | 25351 | `TuiChatList.h`, `TuiComplete.h` |
| func | `tui_command_help` | 25453 | `TuiComplete.h` |
| func | `tui_complete_mention` | 25466 | `TuiComplete.h` |
| func | `tui_complete_command` | 25489 | `TuiComplete.h` |
| func | `tui_build_demo` | 27413 | `TuiDemo.h` |
| func | `tui_demo` | 27581 | `TuiDemo.h` |
| func | `tui_demo_shot` | 27594 | `TuiDemo.h` |
| func | `tui_strip_ansi` | 27618 | `TuiMarkdown.h` |
| func | `tui_chat_sidebar_w` | 27622 | `TuiChatRows.h` |
| func | `tui_md_inline` | 27643 | `TuiMarkdown.h` |
| func | `tui_md_blocks` | 27663 | `TuiMarkdown.h` |
| func | `tui_wrap_segs` | 27700 | `TuiMarkdown.h` |
| func | `tui_chat_styles` | 27737 | `TuiChatRows.h` |
| func | `tui_chat_body_rows` | 27768 | `TuiChatRows.h` |
| func | `tui_chat_bubble_rows` | 27802 | `TuiChatRows.h` |
| func | `tui_chat_tool_summary` | 27859 | `TuiChatRows.h` |
| func | `tui_chat_tool_row` | 27871 | `TuiChatRows.h` |
| func | `tui_chat_live_rows` | 27887 | `TuiChatRows.h` |
| func | `tui_chat_note_rows` | 27913 | `TuiChatRows.h` |
| func | `tui_chat_pill_row` | 27929 | `TuiChatRows.h` |
| func | `tui_chat_welcome_rows` | 27936 | `TuiChatRows.h` |
| func | `tui_spawn_agent` | 28131 | `TuiChatAgent.h` |
| func | `tui_build_chat` | 28148 | `TuiChatAgent.h`, `TuiChatScene.h` |
| func | `tui_chat` | 28840 | `TuiChatScene.h` |
| func | `tui_merge_spans` | 29248 | `GrrText.h` |
| func | `grr_text` | 29682 | `GrrText.h` |
| func | `grr_clip` | 29687 | `GrrText.h` |
| func | `grr_wrap` | 29694 | `GrrText.h` |
| func | `grr_line` | 29701 | `GrrText.h` |
| func | `grr_margin` | 29705 | `GrrText.h` |
| func | `grr_group` | 29936 | `GrrHome.cpp`, `GrrItems.cpp`, `GrrItems.h` |
| func | `grr_bot_avatar` | 31618 | `GrrAvatar.h` |
| func | `grr_user_avatar` | 31622 | `GrrAvatar.h` |
| func | `grr_group_avatar` | 31630 | `GrrAvatar.h` |
| func | `grr_schedule_dialog` | 32487 | `GrrViewsAuto.h` |
| func | `grr_hero_items` | 33432 | `GrrViewsSettings.cpp`, `GrrViewsSettings.h` |
| func | `grr_bubble_styles` | 33598 | `GrrChatItems.cpp`, `GrrChatItems.h` |
| func | `grr_card_rows` | 33734 | `GrrItem.h` |
| func | `grr_control_path` | 35486 | `GrrControl.h` |
| func | `grr_control_call` | 35689 | `GrrControl.h` |
| func | `grr_shell_call_quiet` | 35726 | `GrrShell::client_call_quiet` |
| func | `grr_router_rewrite` | 35731 | `GrrRouter::rewrite` |
| func | `grr_tui` | 35741 | `GrrTui.h` |
## Gaps (not verified, listed next to what would close them)
- Paths with no differential run: approval cards and question cards answered by a
bot, live process cards (`GrrProcessItem` stream, transcript replay, Type and
Expand), file and files messages, the file viewer, the Preview and Files pane
against a bot that has files, template sharing. They compile, and the screens
that open them match, but need a bot that produces them (a real model call).
Closing it: `tests/grr_tui.py` equivalent driven against the C++ binary.
- The remote terminal (`GrrRemoteTerminal`) was driven against a bot computer that
was not running on the test server for the echo step: the typed text never reached
a shell. The two screens matched while it showed the prompt; typing into a live
shell and the resize path are not verified.
- Local chat scene threads: the offload, reveal and prompter paths run on the
loop in the tests with a fake agent. A real agent adapter is not written here.
- Transport error text: `GrrClient::offline_reason` maps libcurl results to python's
wording for timeout, unresolvable host, empty reply and OS errors (refused matched
python on the offline screen). Other curl errors show curl's own text.
- `GrrTimezoneView` reads `/usr/share/zoneinfo` (python: `zoneinfo.available_timezones()`);
verified equal on this machine (486 zones), not on a machine with `tzdata` from pip.
- `GrrFormat`, `GrrText`, `GrrStrings`, `GrrRouter::parse` and `GrrPalette` have no
direct unit diff; they are covered through the screens above.
- Opening a link or file spawns the desktop opener and does not reap it (same as
python, which leaves the child to init).