| 10 |
10 |
|
//! corcovado (mio 0.6) coupling entirely.
|
| 11 |
11 |
|
|
| 12 |
12 |
|
use std::ffi::CString;
|
| 13 |
|
- |
use std::io;
|
|
13 |
+ |
use std::fs::File;
|
|
14 |
+ |
use std::io::{self, Write};
|
| 14 |
15 |
|
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
|
|
16 |
+ |
use std::path::Path;
|
| 15 |
17 |
|
|
| 16 |
18 |
|
use nix::fcntl::{FcntlArg, OFlag, fcntl};
|
| 17 |
19 |
|
use nix::libc;
|
| 44 |
46 |
|
pub struct Pty {
|
| 45 |
47 |
|
master: OwnedFd,
|
| 46 |
48 |
|
child: Pid,
|
|
49 |
+ |
recorder: Option<File>,
|
| 47 |
50 |
|
}
|
| 48 |
51 |
|
|
| 49 |
52 |
|
impl Pty {
|
| 75 |
78 |
|
Ok(Self {
|
| 76 |
79 |
|
master: pair.master,
|
| 77 |
80 |
|
child,
|
|
81 |
+ |
recorder: None,
|
| 78 |
82 |
|
})
|
| 79 |
83 |
|
}
|
| 80 |
84 |
|
ForkResult::Child => {
|
| 104 |
108 |
|
|
| 105 |
109 |
|
/// Nonblocking read. Returns `Ok(0)` on EOF, `WouldBlock` when there's
|
| 106 |
110 |
|
/// nothing to read yet.
|
|
111 |
+ |
///
|
|
112 |
+ |
/// If a recorder is attached (see [`set_recorder`](Self::set_recorder)),
|
|
113 |
+ |
/// bytes read here are teed to it byte-for-byte before returning.
|
|
114 |
+ |
/// Recorder write errors are swallowed — the terminal must not die
|
|
115 |
+ |
/// because a debug capture failed.
|
| 107 |
116 |
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
| 108 |
|
- |
nix::unistd::read(&self.master, buf).map_err(io::Error::from)
|
|
117 |
+ |
let n = nix::unistd::read(&self.master, buf).map_err(io::Error::from)?;
|
|
118 |
+ |
if n > 0 {
|
|
119 |
+ |
if let Some(f) = self.recorder.as_ref() {
|
|
120 |
+ |
let _ = (&*f).write_all(&buf[..n]);
|
|
121 |
+ |
}
|
|
122 |
+ |
}
|
|
123 |
+ |
Ok(n)
|
|
124 |
+ |
}
|
|
125 |
+ |
|
|
126 |
+ |
/// Tee every subsequent successful [`read`](Self::read) to `path`. The
|
|
127 |
+ |
/// file is created (or truncated if it exists) up front, so a bad path
|
|
128 |
+ |
/// surfaces here rather than mid-session.
|
|
129 |
+ |
///
|
|
130 |
+ |
/// Meant for capturing the PTY byte stream for feeding into the
|
|
131 |
+ |
/// `kitty-graphics-testkit` corpus. See `capture-apc`.
|
|
132 |
+ |
pub fn set_recorder(&mut self, path: impl AsRef<Path>) -> io::Result<()> {
|
|
133 |
+ |
self.recorder = Some(File::create(path)?);
|
|
134 |
+ |
Ok(())
|
| 109 |
135 |
|
}
|
| 110 |
136 |
|
|
| 111 |
137 |
|
/// Write bytes to the shell (e.g. keystrokes).
|