1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! retroglyph-core: the `no_std`-compatible foundation of retroglyph.
//!
//! Grid, tile, style, color, text, terminal, and event types, plus the
//! [`Output`](crate::backend::Output)/[`Input`](crate::backend::Input)/[`Cursor`](crate::backend::Cursor) backend
//! facets (bundled together as [`Backend`](crate::backend::Backend)) and the dependency-free
//! [`Headless`](crate::backend::Headless) test backend, and the `App`/`Flow`/`Frame` game loop contract.
//! Platform backends (`retroglyph-crossterm`, `retroglyph-software`) and drawing helpers
//! (`retroglyph-ui`) are separate crates that depend on this one.
//!
//! # Features
//!
//! <!-- gen-features:start -->
//! Default features: `egc`, `std`.
//!
//! ### `dev`
//!
//! ⚪ Optional.
//!
//! Forces `BuildMode::Dev` on in a build that would otherwise resolve to `Release`.
//!
//! Can be used so an optimized build still reports development diagnostics (see the [`dev`]
//! module).
//!
//! ### `egc`
//!
//! 🟢 Enabled by default.
//!
//! Enables grapheme-cluster-aware text handling (via `unicode-segmentation`) for EGC-correct cell
//! diffing and layout.
//!
//! ### `libm`
//!
//! ⚪ Optional.
//!
//! Uses `libm`'s software float implementation (`roundf`/`fmaf`/`sinf`/`cosf`/`powf`) for
//! the separable [`BlendMode`](crate::grid::BlendMode) channel math, via this crate's own
//! `math` shim -- the `no_std` side of that split. See `std` below for the alternative that prefers
//! the platform's own float intrinsics when available; a build needs exactly one of the two.
//!
//! ### `serde`
//!
//! ⚪ Optional.
//!
//! Adds `Serialize`/`Deserialize` impls for [`Color`](crate::color::Color), [`Style`](crate::color::Style), `Size`,
//! `Offset`, and (via `ixy`) `Pos`/`Rect`, so a config file can round-trip a saved camera position,
//! window geometry, sub-cell pixel offset, or theme color.
//!
//! [`Color`](crate::color::Color) serializes through its `Display`/`FromStr` round trip (e.g. `"bright-red"`,
//! `"#ff8000"`) rather than a derived structural form, so hand-edited TOML/JSON stays legible.
//!
//! ### `std`
//!
//! 🟢 Enabled by default.
//!
//! Enables `gem/std` and `alpha-blend/std`, and uses `std`'s float intrinsics (via this crate's
//! `math` shim) instead of `libm`'s software implementation for the separable
//! [`BlendMode`](crate::grid::BlendMode) channel math.
//!
//! Disabling this feature (`--no-default-features`) builds this crate `no_std`, and then needs
//! `libm` above as the float backend instead: see the crate-level `compile_error!` in `src/lib.rs`.
//!
//! ### `testing`
//!
//! ⚪ Optional.
//!
//! Enables `testing`'s `TestHarness`, which drives an [`App`](crate::app::App) against
//! [`Headless`](crate::backend::Headless) for tests, with
//! synthetic input queuing and frame-settling helpers.
//!
//! Test-only surface, `no_std` + `alloc` compatible, off by default so it never ships in a release
//! build by accident.
//! <!-- gen-features:end -->
//!
//! # Architecture
//!
//! [`Terminal<B>`](crate::terminal::Terminal) owns a double-buffered [`Grid`](crate::grid::Grid) and the
//! [`Backend`](crate::backend::Backend) lifecycle (resize, present, events). Drawing itself goes entirely
//! through [`Surface`](crate::surface::Surface), handed out by
//! [`Terminal::draw`](crate::terminal::Terminal::draw)/[`Terminal::surface`](crate::terminal::Terminal::surface):
//! a game calls `term.draw(|s| { s.put(...); ... })`
//! once per frame, and [`present`](crate::terminal::Terminal::present) diffs the current frame against the
//! previous one, sending only changed cells to the [`Backend`](crate::backend::Backend). `B` is the only thing that
//! changes between a headless test and a real window or terminal:
//!
//! ```text
//! ┌───────────────────────────┐
//! │ App::update(...) │ game logic, once, generic over B
//! └──────────────┬─────────────┘
//! │ term.draw(|s| ...): writes through Surface
//! ▼
//! ┌───────────────────────────┐
//! │ Terminal<B> │ double-buffered Grid, cell diff
//! └──────────────┬─────────────┘
//! │ draw / draw_layers / poll_event
//! ▼
//! ┌───────────────────────────┐
//! │ B: Output + Input + Cursor │ the only piece that swaps out
//! └──────────────┬─────────────┘
//! │
//! ┌─────────────────────┼─────────────────────┐
//! ▼ ▼ ▼
//! Headless (here) Crossterm SoftwareRenderer
//! in-memory grid, (retroglyph-crossterm) (retroglyph-software)
//! synthetic events real TTY, ANSI output winit window, pixels
//! ```
//!
//! [`Headless`](crate::backend::Headless) stores presented content in memory and lets tests inject
//! synthetic [`Event`](crate::event::Event)s with [`Headless::push_event`](crate::backend::Headless::push_event);
//! nothing here talks to a real terminal or window. Swapping `Headless` for
//! `Crossterm` or `SoftwareRenderer` changes only the `B` type parameter --
//! `App` implementations, [`Terminal`](crate::terminal::Terminal) calls, and game logic are unchanged.
//! `run_blocking` drives `Terminal<Headless>` and `Terminal<Crossterm>`
//! identically; the software backend's windowed loop drives `Terminal<SoftwareRenderer>`
//! through the same [`App`](crate::app::App) contract, inverted because winit owns the
//! event loop instead of handing control back to a driver function.
//!
//! See `examples/headless.rs` (`cargo run -p retroglyph-core --example
//! headless`) for the smallest possible use of [`Headless`](crate::backend::Headless), depending on
//! nothing but this crate.
// A `pub mod` line's own outer doc comment and its target module's inner `//!` doc concatenate
// into one rendered page, but intra-doc links in that combined block resolve against the scope
// where the *outer* comment lives (this file, the crate root) rather than the module's own scope.
// Every module doc below that also carries an outer doc comment on its `pub mod` line therefore
// needs fully qualified links even for types the module defines itself, which then reads as
// "redundant" from the module file's own point of view. Rather than track that split per link,
// every intra-doc link in this crate is fully qualified and this lint is off crate-wide.
extern crate alloc;
// A float backend is not optional (retroglyph#903): the separable `BlendMode` channel math
// dispatches through `crate::math`, which has nothing to dispatch *to* without one, and
// `Color`'s color-space conversions go through `gem/space`, which needs `gem/std` or `gem/libm`
// for the same reason. Failing here names the two features that fix it, ahead of the same build
// failing as an unresolved `libm::` path inside `math.rs` or inside `gem::space`'s own
// `compile_error!`.
compile_error!;
// Compile the code blocks in this crate's own README as doctests so its quick start is
// type-checked on every test run and cannot silently rot. The `cfg(doctest)` gate keeps this out
// of the rendered crate documentation: see `retroglyph-crossterm`'s matching include for the
// same pattern applied to the workspace root README.
;
/// The `App`-driven game loop.
// See the `too_long_first_doc_paragraph` comment above `animate`: same noisy-lint mis-attribution,
// here because this module's own first doc paragraph grew past the threshold once its intra-doc
// links became fully qualified (retroglyph#1035).
/// Pluggable rendering backends.
// See the `too_long_first_doc_paragraph` comment above `animate`: same noisy-lint mis-attribution.
/// Which diagnostics a build compiles in.
// See the `too_long_first_doc_paragraph` comment above `animate`: same noisy-lint mis-attribution.
/// `FrameClock`/`FrameStats` accumulators for the `App`/`Frame` game loop.
// `pub` so `retroglyph-ui` can share this crate's one std-or-libm dispatch point instead of
// vendoring its own copy, `#[doc(hidden)]` so that sharing costs no public API surface:
// `cargo-semver-checks` ignores hidden items (see the module's own doc comment for the traps that
// come with that). Never add a `pub use` that re-exports its contents through a non-hidden path,
// and never `#[deprecated]` it, both of which would make it public API again despite the hiding.
// See the `too_long_first_doc_paragraph` comment above `animate`: same noisy-lint mis-attribution.
/// The one grid-drawing primitive: an area-clipped, single-layer view over a [`Grid`](crate::grid::Grid).
/// Border, gridline, and partial-block `char` data shared by widgets and backends.
// See the `too_long_first_doc_paragraph` comment above `animate`: same noisy-lint mis-attribution.
/// Headless test harness driving an `App` with synthetic input.
/// The atomic drawable unit (glyph, style, sub-cell offsets).
// No root re-exports below this line by design (retroglyph#1035): every public item lives at its
// module path, matching `ratatui-core`. `dev_only!` (`dev.rs`) and `spans!` (`text.rs`) still
// resolve at the crate root regardless, since `#[macro_export]` always places a macro there; that's
// a macro-export constraint, not a re-export choice.