aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
blob: 9a19ed872b28c8df9760633e1c78b89e70f7bf69 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! 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;