From 898ca615b5d573120a62cc01b2fb43f1d707f69f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 9 Mar 2021 03:19:05 -0500 Subject: make raw_guard also async i think tcsetattr etc can actually block in some cases --- examples/tmux.rs | 2 +- src/blocking/input.rs | 51 ++++++++++++++++++++++++++++++++++++++++-- src/input.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 4 +--- src/raw_guard.rs | 49 ---------------------------------------- 5 files changed, 111 insertions(+), 57 deletions(-) delete mode 100644 src/raw_guard.rs diff --git a/examples/tmux.rs b/examples/tmux.rs index d5969e3..877285b 100644 --- a/examples/tmux.rs +++ b/examples/tmux.rs @@ -303,7 +303,7 @@ struct Tmux { impl Tmux { async fn new() -> Self { - let (input, _raw) = textmode::Input::new().unwrap(); + let (input, _raw) = textmode::Input::new().await.unwrap(); let (tm, _screen) = textmode::Output::new().await.unwrap(); let state = State::new(); Self { diff --git a/src/blocking/input.rs b/src/blocking/input.rs index 6b466a2..bdc916b 100644 --- a/src/blocking/input.rs +++ b/src/blocking/input.rs @@ -1,6 +1,53 @@ use crate::error::*; use std::io::Read as _; +use std::os::unix::io::AsRawFd as _; + +pub struct RawGuard { + termios: nix::sys::termios::Termios, + cleaned_up: bool, +} + +impl RawGuard { + #[allow(clippy::new_without_default)] + pub fn new() -> Result { + let stdin = std::io::stdin().as_raw_fd(); + let termios = + nix::sys::termios::tcgetattr(stdin).map_err(Error::SetRaw)?; + let mut termios_raw = termios.clone(); + nix::sys::termios::cfmakeraw(&mut termios_raw); + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &termios_raw, + ) + .map_err(Error::SetRaw)?; + Ok(Self { + termios, + cleaned_up: false, + }) + } + + pub fn cleanup(&mut self) -> Result<()> { + if self.cleaned_up { + return Ok(()); + } + self.cleaned_up = true; + let stdin = std::io::stdin().as_raw_fd(); + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &self.termios, + ) + .map_err(Error::UnsetRaw) + } +} + +impl Drop for RawGuard { + fn drop(&mut self) { + let _ = self.cleanup(); + } +} pub struct Input { buf: Vec, @@ -15,8 +62,8 @@ pub struct Input { #[allow(clippy::new_without_default)] impl Input { - pub fn new() -> Result<(Self, crate::RawGuard)> { - Ok((Self::new_without_raw(), crate::RawGuard::new()?)) + pub fn new() -> Result<(Self, RawGuard)> { + Ok((Self::new_without_raw(), RawGuard::new()?)) } pub fn new_without_raw() -> Self { diff --git a/src/input.rs b/src/input.rs index ee5d28f..159e61d 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,6 +1,64 @@ use crate::error::*; use futures_lite::io::AsyncReadExt as _; +use std::os::unix::io::AsRawFd as _; + +pub struct RawGuard { + termios: nix::sys::termios::Termios, + cleaned_up: bool, +} + +impl RawGuard { + #[allow(clippy::new_without_default)] + pub async fn new() -> Result { + let stdin = std::io::stdin().as_raw_fd(); + let termios = blocking::unblock(move || { + nix::sys::termios::tcgetattr(stdin).map_err(Error::SetRaw) + }) + .await?; + let mut termios_raw = termios.clone(); + nix::sys::termios::cfmakeraw(&mut termios_raw); + blocking::unblock(move || { + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &termios_raw, + ) + .map_err(Error::SetRaw) + }) + .await?; + Ok(Self { + termios, + cleaned_up: false, + }) + } + + pub async fn cleanup(&mut self) -> Result<()> { + if self.cleaned_up { + return Ok(()); + } + self.cleaned_up = true; + let stdin = std::io::stdin().as_raw_fd(); + let termios = self.termios.clone(); + blocking::unblock(move || { + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &termios, + ) + .map_err(Error::UnsetRaw) + }) + .await + } +} + +impl Drop for RawGuard { + fn drop(&mut self) { + futures_lite::future::block_on(async { + let _ = self.cleanup().await; + }); + } +} pub struct Input { buf: Vec, @@ -15,8 +73,8 @@ pub struct Input { #[allow(clippy::new_without_default)] impl Input { - pub fn new() -> Result<(Self, crate::RawGuard)> { - Ok((Self::new_without_raw(), crate::RawGuard::new()?)) + pub async fn new() -> Result<(Self, RawGuard)> { + Ok((Self::new_without_raw(), RawGuard::new().await?)) } pub fn new_without_raw() -> Self { diff --git a/src/lib.rs b/src/lib.rs index 90f092a..e4abf7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,6 @@ mod error; pub use error::{Error, Result}; mod key; pub use key::Key; -mod raw_guard; -pub use raw_guard::RawGuard; #[cfg(feature = "async")] mod output; @@ -17,7 +15,7 @@ pub use output::{Output, ScreenGuard}; #[cfg(feature = "async")] mod input; #[cfg(feature = "async")] -pub use input::Input; +pub use input::{Input, RawGuard}; const INIT: &[u8] = b"\x1b7\x1b[?47h\x1b[2J\x1b[H\x1b[?25h"; const DEINIT: &[u8] = b"\x1b[?47l\x1b8\x1b[?25h"; diff --git a/src/raw_guard.rs b/src/raw_guard.rs deleted file mode 100644 index 3835181..0000000 --- a/src/raw_guard.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::error::*; - -use std::os::unix::io::AsRawFd as _; - -pub struct RawGuard { - termios: nix::sys::termios::Termios, - cleaned_up: bool, -} - -impl RawGuard { - #[allow(clippy::new_without_default)] - pub fn new() -> Result { - let stdin = std::io::stdin().as_raw_fd(); - let termios = - nix::sys::termios::tcgetattr(stdin).map_err(Error::SetRaw)?; - let mut termios_raw = termios.clone(); - nix::sys::termios::cfmakeraw(&mut termios_raw); - nix::sys::termios::tcsetattr( - stdin, - nix::sys::termios::SetArg::TCSANOW, - &termios_raw, - ) - .map_err(Error::SetRaw)?; - Ok(Self { - termios, - cleaned_up: false, - }) - } - - pub fn cleanup(&mut self) -> Result<()> { - if self.cleaned_up { - return Ok(()); - } - self.cleaned_up = true; - let stdin = std::io::stdin().as_raw_fd(); - nix::sys::termios::tcsetattr( - stdin, - nix::sys::termios::SetArg::TCSANOW, - &self.termios, - ) - .map_err(Error::UnsetRaw) - } -} - -impl Drop for RawGuard { - fn drop(&mut self) { - let _ = self.cleanup(); - } -} -- cgit v1.2.3-54-g00ecf