//! This crate wraps `tokio-pty-process` in order to provide a simpler API as //! a single stream object. //! //! # Overview //! //! When you need to interact with an interactive program as part of an //! asynchronous application, it can be tricky to figure out the way to //! structure the different parts that are required. This crate simplifies the //! API down to just providing the input via an `AsyncRead` object, and then //! getting updates about what the program is doing via results generated by a //! stream. //! //! # Synopsis //! //! This is an example of how to run an interactive program and have it behave //! identically to running it in the shell. Note that we have to use our own //! `Stdin` implementation here because `tokio::io::stdin()` is actually //! blocking, and so polling it as part of an interactive application doesn't //! work correctly. The implementation of `Stdin` is elided here, but you can //! see the full implementation in `examples/shell.rs` in the repository. //! //! ```no_run //! # use futures::future::Future as _; //! # use futures::stream::Stream as _; //! # use std::io::{Read as _, Write as _}; //! # //! let mut argv = std::env::args(); //! argv.next().unwrap(); //! let cmd = argv.next().unwrap(); //! let args: Vec<_> = argv.collect(); //! //! let process = //! tokio_pty_process_stream::Process::new(&cmd, &args, Stdin::new()); //! let process = tokio_pty_process_stream::ResizingProcess::new(process); //! //! let _raw = crossterm::RawScreen::into_raw_mode().unwrap(); //! tokio::run( //! process //! .for_each(|ev| { //! match ev { //! tokio_pty_process_stream::Event::CommandStart { //! .. //! } => {} //! tokio_pty_process_stream::Event::Output { data } => { //! let stdout = std::io::stdout(); //! let mut stdout = stdout.lock(); //! stdout.write_all(&data).unwrap(); //! stdout.flush().unwrap(); //! } //! tokio_pty_process_stream::Event::CommandExit { //! .. //! } => {} //! tokio_pty_process_stream::Event::Resize { .. } => {} //! } //! futures::future::ok(()) //! }) //! .map_err(|e| panic!(e)), //! ); //! # //! # struct EventedStdin; //! # //! # const STDIN: i32 = 0; //! # //! # impl std::io::Read for EventedStdin { //! # fn read(&mut self, buf: &mut [u8]) -> std::io::Result { //! # let stdin = std::io::stdin(); //! # let mut stdin = stdin.lock(); //! # stdin.read(buf) //! # } //! # } //! # //! # impl mio::Evented for EventedStdin { //! # fn register( //! # &self, //! # poll: &mio::Poll, //! # token: mio::Token, //! # interest: mio::Ready, //! # opts: mio::PollOpt, //! # ) -> std::io::Result<()> { //! # let fd = STDIN as std::os::unix::io::RawFd; //! # let eventedfd = mio::unix::EventedFd(&fd); //! # eventedfd.register(poll, token, interest, opts) //! # } //! # //! # fn reregister( //! # &self, //! # poll: &mio::Poll, //! # token: mio::Token, //! # interest: mio::Ready, //! # opts: mio::PollOpt, //! # ) -> std::io::Result<()> { //! # let fd = STDIN as std::os::unix::io::RawFd; //! # let eventedfd = mio::unix::EventedFd(&fd); //! # eventedfd.reregister(poll, token, interest, opts) //! # } //! # //! # fn deregister(&self, poll: &mio::Poll) -> std::io::Result<()> { //! # let fd = STDIN as std::os::unix::io::RawFd; //! # let eventedfd = mio::unix::EventedFd(&fd); //! # eventedfd.deregister(poll) //! # } //! # } //! # //! # pub struct Stdin { //! # input: tokio::reactor::PollEvented2, //! # } //! # //! # impl Stdin { //! # pub fn new() -> Self { //! # Default::default() //! # } //! # } //! # //! # impl Default for Stdin { //! # fn default() -> Self { //! # Self { //! # input: tokio::reactor::PollEvented2::new(EventedStdin), //! # } //! # } //! # } //! # //! # impl std::io::Read for Stdin { //! # fn read(&mut self, buf: &mut [u8]) -> std::io::Result { //! # self.input.read(buf) //! # } //! # } //! # //! # impl tokio::io::AsyncRead for Stdin { //! # fn poll_read( //! # &mut self, //! # buf: &mut [u8], //! # ) -> std::result::Result, tokio::io::Error> { //! # let ready = mio::Ready::readable(); //! # futures::try_ready!(self.input.poll_read_ready(ready)); //! # //! # let res = self.read(buf)?; //! # self.input.clear_read_ready(ready)?; //! # Ok(futures::Async::Ready(res)) //! # } //! # } //! ``` // XXX this is broken with ale // #![warn(clippy::cargo)] #![warn(clippy::pedantic)] #![warn(clippy::nursery)] #![allow(clippy::missing_const_for_fn)] #![allow(clippy::multiple_crate_versions)] #![allow(clippy::type_complexity)] mod error; pub use error::Error; mod process; pub use process::Event; pub use process::Process; mod resize; pub use resize::ResizingProcess;