aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib.rs
blob: 9a19ed872b28c8df9760633e1c78b89e70f7bf69 (plain) (tree)
































                                                                              
                                                                          

















                                                                         
                                                                        
























































































                                                                             

                              


                                       
                                          

                                  




                         

                                
//! 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<usize> {
//! #         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<EventedStdin>,
//! # }
//! #
//! # 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<usize> {
//! #         self.input.read(buf)
//! #     }
//! # }
//! #
//! # impl tokio::io::AsyncRead for Stdin {
//! #     fn poll_read(
//! #         &mut self,
//! #         buf: &mut [u8],
//! #     ) -> std::result::Result<futures::Async<usize>, 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;