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
//! Headless PTY test harness for CLI/TUI applications.
//!
//! `termlens` spawns your program in a **real pseudo-terminal**, feeds its
//! output through a **VT emulator** into an in-memory **screen grid**, and
//! lets tests **assert and snapshot on the rendered screen** instead of raw
//! bytes — Playwright for the terminal.
//!
//! - It is *not* an expect-style stream matcher (see `rexpect`/`expectrl`).
//! - It is *not* an SVG transcript generator for docs (see `term-transcript`).
//! - It *is*: real PTY + emulated screen + snapshot assertions.
//!
//! # Example
//!
//! ```
//! use std::time::Duration;
//! use termlens::{Key, Terminal};
//!
//! # fn main() -> termlens::Result<()> {
//! let mut t = Terminal::builder()
//! .size(80, 24)
//! .env("TERM", "xterm-256color") // the default; shown for completeness
//! .timeout(Duration::from_secs(10))
//! .args(["-c", r#"read line; echo "got: $line"; read quit"#])
//! .spawn("sh")?;
//!
//! t.send_str("hello");
//! t.send(Key::Enter);
//! t.wait_until(|screen| screen.contains("got: hello"))?;
//!
//! t.send(Key::Enter); // release `read quit`; the script finishes
//! let status = t.wait_exit()?;
//! assert!(status.success());
//! # Ok(())
//! # }
//! ```
//!
//! Every `wait_*` call runs under a deadline (builder
//! [`timeout`](TerminalBuilder::timeout), default 5s), and a timeout error
//! [embeds the screen](Error::Timeout) so a CI log alone shows what the
//! application was displaying. A background reader thread drains the PTY
//! continuously — no output is lost between waits — and answers the
//! queries a real terminal answers, so capability-probing apps run
//! instead of hanging.
//!
//! Input is mode-aware: [mouse clicks](Terminal::click),
//! [pastes](Terminal::paste), modifier [chords](Chord), and cursor keys
//! are encoded exactly as the application configured its terminal. And
//! the terminal's out-of-band state — the window title, the
//! alternate-screen flag, the input modes — is readable from every
//! [`Screen`] as plain accessors.
//!
//! With the default `insta` feature, snapshot-test whole screens:
//!
//! ```no_run
//! # fn main() -> termlens::Result<()> {
//! # let mut t = termlens::Terminal::builder().spawn("true")?;
//! insta::assert_snapshot!(t.screen()); // plain insta…
//! termlens::assert_screen_snapshot!(t.screen()); // …or the bundled macro
//! # Ok(())
//! # }
//! ```
pub use ;
pub use ;
pub use ;
pub use Signal;
pub use ;
/// Re-export of [`insta`](https://insta.rs) (feature `insta`, on by
/// default), so [`assert_screen_snapshot!`] always agrees with the `insta`
/// version doing the snapshotting.
pub use insta;
/// Snapshot-assert anything that displays like a [`Screen`].
///
/// Sugar for [`insta::assert_snapshot!`] through the re-exported `insta`;
/// accepts the same optional inline-snapshot form:
///
/// ```no_run
/// # fn main() -> termlens::Result<()> {
/// # let t = termlens::Terminal::builder().spawn("true")?;
/// termlens::assert_screen_snapshot!(t.screen());
/// # Ok(())
/// # }
/// ```