From 7c3436ea96d3e897b184f8b57fc554950885459c Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 27 Oct 2019 13:32:58 -0400 Subject: copy implementation over from teleterm --- Cargo.toml | 7 ++++-- src/lib.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9f5eb1c..a1d2b8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" authors = ["Jesse Luehrs "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +futures = "0.1.29" +snafu = { version = "0.5", features = ["futures-01"] } +term_size = "0.3" +tokio = "0.1.22" +tokio-signal = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 31e1bb2..218010e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,72 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); +use futures::future::Future as _; +use futures::stream::Stream as _; +use snafu::futures01::StreamExt as _; +use snafu::ResultExt as _; +use std::convert::TryInto as _; + +#[derive(Debug, snafu::Snafu)] +pub enum Error { + #[snafu(display("failed to get terminal size"))] + GetTerminalSize, + + #[snafu(display("invalid terminal size found: {}", source))] + InvalidTerminalSize { source: std::num::TryFromIntError }, + + #[snafu(display("SIGWINCH handler failed: {}", source))] + SigWinchHandler { source: std::io::Error }, +} + +pub type Result = std::result::Result; + +pub struct Resizer { + winches: + Box + Send>, + sent_initial_size: bool, +} + +impl Resizer { + pub fn new() -> Self { + Self::default() + } +} + +impl Default for Resizer { + fn default() -> Self { + let winches = tokio_signal::unix::Signal::new( + tokio_signal::unix::libc::SIGWINCH, + ) + .flatten_stream() + .map(|_| ()) + .context(SigWinchHandler); + Self { + winches: Box::new(winches), + sent_initial_size: false, + } + } +} + +#[must_use = "streams do nothing unless polled"] +impl futures::stream::Stream for Resizer { + type Item = (u16, u16); + type Error = Error; + + fn poll(&mut self) -> futures::Poll, Self::Error> { + if !self.sent_initial_size { + self.sent_initial_size = true; + return Ok(futures::Async::Ready(Some(term_size()?))); + } + let _ = futures::try_ready!(self.winches.poll()); + Ok(futures::Async::Ready(Some(term_size()?))) + } +} + +fn term_size() -> Result<(u16, u16)> { + if let Some((cols, rows)) = term_size::dimensions() { + Ok(( + rows.try_into().context(InvalidTerminalSize)?, + cols.try_into().context(InvalidTerminalSize)?, + )) + } else { + Err(Error::GetTerminalSize) } } -- cgit v1.2.3-54-g00ecf