tokio_pty_process_stream/
resize.rs

1use futures::future::Future as _;
2use futures::stream::Stream as _;
3use snafu::futures01::StreamExt as _;
4
5/// A wrapper around `Process` which listens for terminal resize signals and
6/// propagates the changes into the process running on the pty.
7///
8/// This is useful for running subprocesses in a pty that will ultimately be
9/// displayed in the user's terminal directly.
10pub struct ResizingProcess<R: tokio::io::AsyncRead + 'static> {
11    process: crate::process::Process<R>,
12    resizer: Box<
13        dyn futures::stream::Stream<
14                Item = (u16, u16),
15                Error = crate::error::Error,
16            > + Send,
17    >,
18}
19
20impl<R: tokio::io::AsyncRead + 'static> ResizingProcess<R> {
21    /// Creates a new `ResizingProcess` as a wrapper around the given
22    /// `Process` instance.
23    pub fn new(process: crate::process::Process<R>) -> Self {
24        Self {
25            process,
26            resizer: Box::new(
27                tokio_terminal_resize::resizes()
28                    .flatten_stream()
29                    .context(crate::error::Resize),
30            ),
31        }
32    }
33
34    /// Returns a mutable reference to the input object provided in the inner
35    /// `Process` instance's constructor.
36    pub fn input(&mut self) -> &mut R {
37        self.process.input()
38    }
39}
40
41impl<R: tokio::io::AsyncRead + 'static> ResizingProcess<R> {
42    const POLL_FNS:
43        &'static [&'static dyn for<'a> Fn(
44            &'a mut Self,
45        )
46            -> component_future::Poll<
47            Option<crate::process::Event>,
48            crate::error::Error,
49        >] = &[&Self::poll_resize, &Self::poll_process];
50
51    fn poll_resize(
52        &mut self,
53    ) -> component_future::Poll<
54        Option<crate::process::Event>,
55        crate::error::Error,
56    > {
57        let (rows, cols) =
58            component_future::try_ready!(self.resizer.poll()).unwrap();
59        self.process.resize(rows, cols);
60        Ok(component_future::Async::Ready(Some(
61            crate::process::Event::Resize { size: (rows, cols) },
62        )))
63    }
64
65    fn poll_process(
66        &mut self,
67    ) -> component_future::Poll<
68        Option<crate::process::Event>,
69        crate::error::Error,
70    > {
71        Ok(component_future::Async::Ready(
72            component_future::try_ready!(self.process.poll()),
73        ))
74    }
75}
76
77#[must_use = "streams do nothing unless polled"]
78impl<R: tokio::io::AsyncRead + 'static> futures::stream::Stream
79    for ResizingProcess<R>
80{
81    type Item = crate::process::Event;
82    type Error = crate::error::Error;
83
84    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
85        component_future::poll_stream(self, Self::POLL_FNS)
86    }
87}