Skip to main content

retroglyph_core/
lib.rs

1//! retroglyph-core: the `no_std`-compatible foundation of retroglyph.
2//!
3//! Grid, tile, style, color, text, terminal, and event types, plus the
4//! [`Output`]/[`Input`]/[`Cursor`] backend facets (bundled together as [`Backend`]) and the
5//! dependency-free [`Headless`] test backend, and the `App`/`Flow`/`Frame` game loop contract.
6//! Platform backends (`retroglyph-crossterm`, `retroglyph-software`) and drawing helpers
7//! (`retroglyph-widgets`) are separate crates that depend on this one.
8//!
9//! # Architecture
10//!
11//! [`Terminal<B>`](Terminal) owns a double-buffered [`Grid`] and the [`Backend`] lifecycle
12//! (resize, present, events). Drawing itself goes entirely through [`Surface`], handed out by
13//! [`Terminal::draw`]/[`Terminal::surface`]: a game calls `term.draw(|s| { s.put(...); ... })`
14//! once per frame, and [`present`](Terminal::present) diffs the current frame against the
15//! previous one, sending only changed cells to the [`Backend`]. `B` is the only thing that
16//! changes between a headless test and a real window or terminal:
17//!
18//! ```text
19//!               ┌───────────────────────────┐
20//!               │      App::update(...)      │  game logic, once, generic over B
21//!               └──────────────┬─────────────┘
22//!                              │ term.draw(|s| ...): writes through Surface
23//!                              ▼
24//!               ┌───────────────────────────┐
25//!               │       Terminal<B>          │  double-buffered Grid, cell diff
26//!               └──────────────┬─────────────┘
27//!                              │ draw / draw_layers / poll_event
28//!                              ▼
29//!               ┌───────────────────────────┐
30//!               │  B: Output + Input + Cursor │  the only piece that swaps out
31//!               └──────────────┬─────────────┘
32//!                              │
33//!        ┌─────────────────────┼─────────────────────┐
34//!        ▼                     ▼                      ▼
35//!  Headless (here)      Crossterm                SoftwareRenderer
36//!  in-memory grid,      (retroglyph-crossterm)   (retroglyph-software)
37//!  synthetic events     real TTY, ANSI output    winit window, pixels
38//! ```
39//!
40//! [`Headless`] stores presented content in memory and lets tests inject
41//! synthetic [`Event`]s with [`Headless::push_event`](backend::Headless::push_event);
42//! nothing here talks to a real terminal or window. Swapping `Headless` for
43//! `Crossterm` or `SoftwareRenderer` changes only the `B` type parameter --
44//! `App` implementations, [`Terminal`] calls, and game logic are unchanged.
45//! `run_blocking` drives `Terminal<Headless>` and `Terminal<Crossterm>`
46//! identically; the software backend's windowed loop drives `Terminal<SoftwareRenderer>`
47//! through the same [`App`]/[`step`] contract, inverted because winit owns the
48//! event loop instead of handing control back to a driver function.
49//!
50//! See `examples/headless.rs` (`cargo run -p retroglyph-core --example
51//! headless`) for the smallest possible use of [`Headless`], depending on
52//! nothing but this crate.
53#![cfg_attr(not(feature = "std"), no_std)]
54#![cfg_attr(docsrs, feature(doc_cfg))]
55extern crate alloc;
56
57// Compile the code blocks in this crate's own README as doctests so its quick start is
58// type-checked on every test run and cannot silently rot. The `cfg(doctest)` gate keeps this out
59// of the rendered crate documentation: see `retroglyph-crossterm`'s matching include for the
60// same pattern applied to the workspace root README.
61#[cfg(doctest)]
62#[doc = include_str!("../README.md")]
63struct ReadmeDoctests;
64
65// clippy::too_long_first_doc_paragraph is a known-noisy nursery lint (rust-lang/rust-clippy#13441)
66// that here misattributes its span across every subsequent `pub mod`/`pub use` declaration below
67// (through to the next blank line) rather than just this one doc comment, which is well under
68// its own 100-char threshold in isolation: confirmed by testing shorter wording alone, which
69// silences it despite touching nothing else in that byte range.
70#[allow(clippy::too_long_first_doc_paragraph)]
71/// Time-driven value animation: easing curves, a stateful `Tween`, and a periodic oscillator.
72pub mod animate;
73/// The `App`-driven game loop.
74pub mod app;
75/// Pluggable rendering backends.
76pub mod backend;
77/// A scrolling viewport into a world larger than the screen.
78pub mod camera;
79pub mod color;
80/// Which diagnostics a build compiles in.
81pub mod dev;
82pub mod event;
83/// Fixed-timestep accumulator for game loops.
84pub mod frame_clock;
85pub mod grid;
86#[cfg(feature = "egc")]
87pub mod layout;
88pub mod style;
89pub mod subcell;
90/// The one grid-drawing primitive: an area-clipped, single-layer view over a [`Grid`].
91pub mod surface;
92pub mod terminal;
93pub mod text;
94/// The atomic drawable unit (glyph, style, sub-cell offsets).
95pub mod tile;
96pub mod tint;
97
98pub use animate::{Easing, Tween, oscillate};
99pub use app::{App, Flow, Frame, step};
100#[cfg(feature = "std")]
101#[cfg(feature = "std")]
102pub use app::{RunOptions, run_blocking, run_blocking_with};
103pub use backend::{Backend, Cursor, CursorStyle, DrawCell, Headless, Input, Output};
104pub use camera::Camera;
105pub use color::{AnsiColor, Color, InvalidAnsiIndex};
106pub use dev::{BuildMode, DEV};
107pub use event::{
108    Event, KeyCode, KeyEvent, KeyEventKind, KeyLocation, KeyModifiers, KeyState, MouseButton,
109    MouseEvent, MouseEventKind, PhysicalPos, SystemTheme,
110};
111pub use frame_clock::FrameClock;
112#[cfg(feature = "color-space")]
113pub use grid::BlendMode;
114pub use grid::{Grid, Offset, Pos, Rect, Size};
115#[cfg(feature = "egc")]
116pub use layout::{HAlign, TextLayout, TextMetrics, VAlign};
117pub use style::Style;
118pub use subcell::{Glyph, quantize_half_block, quantize_quadrant, quantize_sextant};
119pub use surface::{StyledSurface, Surface};
120pub use terminal::Terminal;
121pub use text::{Line, Span};
122pub use tile::Tile;
123pub use tint::Tint;