1mod buffer;
32mod child;
33mod pty;
34mod signals;
35
36use std::ffi::OsStr;
37
38pub use buffer::PtyBuffer;
39pub use child::{UnixPtyChild, spawn_child};
40pub use pty::{UnixPtyMaster, open_slave};
41pub use signals::{
42 PtySignalEvent, SignalHandle, is_sigchld, is_sigwinch, on_window_change, sigchld, sigwinch,
43 start_signal_handler,
44};
45
46use crate::config::PtyConfig;
47use crate::error::Result;
48use crate::traits::PtySystem;
49
50#[derive(Debug, Clone, Copy, Default)]
54pub struct UnixPtySystem;
55
56impl PtySystem for UnixPtySystem {
57 type Master = UnixPtyMaster;
58 type Child = UnixPtyChild;
59
60 async fn spawn<S, I>(
61 program: S,
62 args: I,
63 config: &PtyConfig,
64 ) -> Result<(Self::Master, Self::Child)>
65 where
66 S: AsRef<OsStr> + Send,
67 I: IntoIterator + Send,
68 I::Item: AsRef<OsStr>,
69 {
70 let (master, slave_path) = UnixPtyMaster::open()?;
72
73 let window_size = config.window_size.into();
75 master.set_window_size(window_size)?;
76
77 let slave_fd = open_slave(&slave_path)?;
79
80 let child = spawn_child(slave_fd, program, args, config).await?;
82
83 Ok((master, child))
84 }
85}
86
87pub type NativePtySystem = UnixPtySystem;
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[tokio::test]
95 async fn spawn_shell() {
96 let config = PtyConfig::default();
97 let result = UnixPtySystem::spawn_shell(&config).await;
98
99 if let Ok((mut master, mut child)) = result {
101 assert!(master.is_open());
102 assert!(child.is_running());
103
104 child.kill().ok();
106 master.close().ok();
107 }
108 }
109
110 #[tokio::test]
111 async fn spawn_echo() {
112 let config = PtyConfig::default();
113 let result = UnixPtySystem::spawn("echo", ["hello"], &config).await;
114
115 if let Ok((mut master, mut child)) = result {
116 let status = child.wait().await;
118 assert!(status.is_ok());
119
120 master.close().ok();
121 }
122 }
123}