1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-04 17:45:23 +03:00
wezterm/pty/examples/whoami.rs
Wez Furlong e6421d1b72 pty: try_clone_writer -> take_writer
This breaking API change allows us to explicitly generate EOF when the
taken writer is dropped.

The examples have been updated to show how to manage read, write
and waiting without deadlock for both linux and windows.
Need to confirm that this is still good on macOS, but my
confidence is high.

I've also removed ssh2 support from this crate as part of this
change. We haven't used it directly in wezterm in a long while
and removing it from here means that there is slightly less code
to keep compiling over and over.

refs: https://github.com/wez/wezterm/discussions/2392
refs: https://github.com/wez/wezterm/issues/1396
2022-08-12 07:56:46 -07:00

82 lines
2.9 KiB
Rust

//! This is a conceptually simple example that spawns the `whoami` program
//! to print your username. It is made more complex because there are multiple
//! pipes involved and it is easy to get blocked/deadlocked if care and attention
//! is not paid to those pipes!
use portable_pty::{CommandBuilder, NativePtySystem, PtySize, PtySystem};
use std::sync::mpsc::channel;
fn main() {
let pty_system = NativePtySystem::default();
let pair = pty_system
.openpty(PtySize {
rows: 24,
cols: 80,
pixel_width: 0,
pixel_height: 0,
})
.unwrap();
let cmd = CommandBuilder::new("whoami");
let mut child = pair.slave.spawn_command(cmd).unwrap();
// Release any handles owned by the slave: we don't need it now
// that we've spawned the child.
drop(pair.slave);
{
// Obtain the writer.
// When the writer is dropped, EOF will be sent to
// the program that was spawned.
// It is important to take the writer even if you don't
// send anything to its stdin so that EOF can be
// generated, otherwise you risk deadlocking yourself.
let mut writer = pair.master.take_writer().unwrap();
// This example doesn't need to write anything, but if you
// want to send data to the child, you'd set `to_write` to
// that data and do it like this:
let to_write = "";
if !to_write.is_empty() {
// To avoid deadlock, wrt. reading and waiting, we send
// data to the stdin of the child in a different thread.
std::thread::spawn(move || {
writer.write_all(to_write.as_bytes()).unwrap();
});
}
}
// Read the output in another thread.
// This is important because it is easy to encounter a situation
// where read/write buffers fill and block either your process
// or the spawned process.
let (tx, rx) = channel();
let mut reader = pair.master.try_clone_reader().unwrap();
std::thread::spawn(move || {
// Consume the output from the child
let mut s = String::new();
reader.read_to_string(&mut s).unwrap();
tx.send(s).unwrap();
});
// Wait for the child to complete
println!("child status: {:?}", child.wait().unwrap());
// Take care to drop the master after our processes are
// done, as some platforms get unhappy if it is dropped
// sooner than that.
drop(pair.master);
// Now wait for the output to be read by our reader thread
let output = rx.recv().unwrap();
// We print with escapes escaped because the windows conpty
// implementation synthesizes title change escape sequences
// in the output stream and it can be confusing to see those
// printed out raw in another terminal.
print!("output: ");
for c in output.escape_debug() {
print!("{}", c);
}
}