aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-10-27 13:32:58 -0400
committerJesse Luehrs <doy@tozt.net>2019-10-27 13:32:58 -0400
commit7c3436ea96d3e897b184f8b57fc554950885459c (patch)
treef004529e28ea1831cced4bc18887b06ad63f06cd
parent12f5e2aefb7dd6ebf3aaf7e19f32a00d187f1bfe (diff)
downloadtokio-terminal-resize-7c3436ea96d3e897b184f8b57fc554950885459c.tar.gz
tokio-terminal-resize-7c3436ea96d3e897b184f8b57fc554950885459c.zip
copy implementation over from teleterm
-rw-r--r--Cargo.toml7
-rw-r--r--src/lib.rs75
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 <doy@tozt.net>"]
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<T> = std::result::Result<T, Error>;
+
+pub struct Resizer {
+ winches:
+ Box<dyn futures::stream::Stream<Item = (), Error = Error> + 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<Option<Self::Item>, 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)
}
}