retroglyph_recorder/lib.rs
1//! Input recording & replay for [retroglyph](https://github.com/crates-lurey-io/retroglyph).
2//!
3//! Two things live here, both built on `retroglyph-core`'s `testing` feature
4//! ([`retroglyph_core::testing::InputRecording`]/[`TestHarness`](retroglyph_core::testing::TestHarness)):
5//!
6//! - [`InputRecorder`]: wraps any [`Backend`](retroglyph_core::backend::Backend) and taps its
7//! input stream, so a real session (a bug report, a demo run) can be captured to a `.rgrec`
8//! file via [`InputRecorder::save`].
9//! - [`replay_live`]: drives a saved recording forward into a live `Terminal`/`App`, once, at
10//! recorded pace -- "watch it happen" on screen. For driving a recording back through a
11//! headless `App` in a test instead (no real backend, no wall-clock sleeping), use
12//! [`TestHarness::replay`](retroglyph_core::testing::TestHarness::replay) directly.
13//!
14//! [`install_panic_recorder`] wires a [`RecorderHandle`] into `std::panic`'s hook, so an
15//! in-progress recording is saved automatically if the process panics instead of being lost.
16//!
17//! A different pair records "what was shown" instead of "what happened":
18//!
19//! - [`FrameRecorder`]: wraps any [`Output`](retroglyph_core::backend::Output) backend and taps
20//! its [`DrawCell`](retroglyph_core::backend::DrawCell) diff stream, buffering owned
21//! [`CapturedFrame`]s.
22//! - [`write_cast`]: exports those frames as
23//! [asciicast v3](https://docs.asciinema.org/manual/asciicast/v3/) newline-delimited JSON, so
24//! the existing external ecosystem (`agg`, `asciinema-player`, `svg-term`) renders it --
25//! retroglyph never builds a GIF encoder or an interactive player of its own.
26//!
27//! With the `pty` feature, [`pty::capture_pty`] is a second capture source for the same
28//! [`write_cast`] path: it drives a real backend under a real pseudo-terminal (rather than a
29//! `TestHarness`-style synthetic `Headless`), aiming for the fidelity a real-terminal tool like
30//! `vhs` gets from a real terminal emulator, without one in this crate's own dependency tree.
31//!
32//! Not here: a first-class cross-backend replay helper for frame recordings (standard asciicast
33//! output already covers the common case), or embedding `asciinema-player` in the docs site
34//! (straightforward once there's a concrete need) -- both deliberately deferred, see
35//! retroglyph#1268.
36//!
37//! # Features
38//!
39//! <!-- gen-features:start -->
40//! This crate has no default features; every feature below is optional and off unless enabled.
41//!
42//! ### `pty`
43//!
44//! ⚪ Optional.
45//!
46//! A real-pseudo-terminal capture source (`pty::capture_pty`) feeding the same `write_cast` path
47//! `FrameRecorder` does, for `vhs`-like real-terminal fidelity. Adds `portable-pty`/`vt100`.
48//! <!-- gen-features:end -->
49
50// Compile the code blocks in this crate's own README as doctests so its quick start is
51// type-checked on every test run and cannot silently rot. The `cfg(doctest)` gate keeps this out
52// of the rendered crate documentation; see `retroglyph-core`'s matching include for the same
53// pattern.
54#[cfg(doctest)]
55#[doc = include_str!("../README.md")]
56struct ReadmeDoctests;
57
58mod cast;
59mod frame_recorder;
60mod input_recorder;
61mod owned_cell;
62mod panic_hook;
63#[cfg(feature = "pty")]
64pub mod pty;
65mod replay;
66mod rgrec;
67
68pub use cast::write_cast;
69pub use frame_recorder::{CapturedFrame, FrameRecorder, FrameRecorderHandle};
70pub use input_recorder::{InputRecorder, RecorderHandle};
71pub use owned_cell::OwnedCell;
72pub use panic_hook::install_panic_recorder;
73pub use replay::replay_live;
74pub use rgrec::{read, write};