rust_expect/
interact.rs

1//! Interactive terminal sessions.
2//!
3//! This module provides functionality for interactive terminal sessions,
4//! allowing direct user interaction with spawned processes.
5//!
6//! # Pattern Hooks
7//!
8//! The interact mode supports pattern-based callbacks that are triggered
9//! when specific patterns appear in the output or input:
10//!
11//! ```ignore
12//! use rust_expect::Session;
13//!
14//! let mut session = Session::spawn("/bin/bash", &[]).await?;
15//!
16//! session.interact()
17//!     .on_output("password:", |ctx| {
18//!         ctx.send("my_password\n")
19//!     })
20//!     .on_output("logout", |_| {
21//!         InteractAction::Stop
22//!     })
23//!     .start()
24//!     .await?;
25//! ```
26//!
27//! # Hook Execution Order
28//!
29//! Understanding hook execution order is important when using multiple hooks:
30//!
31//! ## Pattern Hooks (`on_output`, `on_input`)
32//!
33//! Pattern hooks are evaluated in **registration order**. The first matching
34//! hook's action is executed:
35//!
36//! ```ignore
37//! session.interact()
38//!     .on_output("error", |_| InteractAction::Stop)      // Checked first
39//!     .on_output("warning", |_| InteractAction::Continue) // Checked second
40//!     .on_output("error.*", |_| InteractAction::Continue) // Checked third
41//!     .start()
42//! ```
43//!
44//! If output contains "error", the first hook matches and stops. The regex
45//! hook is never reached even though it also matches.
46//!
47//! ## Processing Hooks (`HookManager`)
48//!
49//! Processing hooks form a **pipeline**. Each hook receives the output of the
50//! previous hook:
51//!
52//! ```ignore
53//! let manager = HookBuilder::new()
54//!     .with_crlf()    // LF -> CRLF conversion
55//!     .with_echo()    // Echo to stdout (receives CRLF output)
56//!     .build();
57//! ```
58//!
59//! ## Resize Hooks (`on_resize`)
60//!
61//! Only one resize hook can be registered. If multiple are set, the last one
62//! wins:
63//!
64//! ```ignore
65//! session.interact()
66//!     .on_resize(|_| InteractAction::Continue)  // Overwritten
67//!     .on_resize(|ctx| {                        // This one is used
68//!         eprintln!("Resized to {}x{}", ctx.size.cols, ctx.size.rows);
69//!         InteractAction::Continue
70//!     })
71//! ```
72//!
73//! ## Event Processing Order
74//!
75//! During each iteration of the interact loop:
76//!
77//! 1. **Resize events** are processed first (Unix SIGWINCH)
78//! 2. **Session output** is read and pattern-matched
79//! 3. **User input** is read and pattern-matched
80//! 4. Actions are executed in the order above
81//!
82//! If any action is `InteractAction::Stop` or `InteractAction::Error`, the
83//! loop terminates immediately.
84//!
85//! ## Best Practices
86//!
87//! - Register specific patterns before general patterns (most specific first)
88//! - Use `InteractAction::Continue` to let multiple hooks observe data
89//! - For logging, use event hooks rather than pattern hooks
90//! - Keep hook callbacks fast to avoid blocking the event loop
91
92pub mod hooks;
93pub mod mode;
94pub mod session;
95pub mod terminal;
96
97pub use hooks::{HookBuilder, HookManager, InteractionEvent};
98pub use mode::{InputFilter, InteractionMode, OutputFilter};
99pub use session::{
100    InteractAction, InteractBuilder, InteractContext, InteractEndReason, InteractResult,
101    PatternHook, ResizeContext, ResizeHook,
102};
103pub use terminal::{Terminal, TerminalMode, TerminalSize, TerminalState};