use std::io::Write;
#[cfg(unix)]
use nix::sys::termios::{self, SetArg, Termios};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, BorrowedFd};
pub struct TerminalGuard {
#[cfg(unix)]
saved_attrs: Option<Termios>,
}
impl Default for TerminalGuard {
fn default() -> Self {
Self::new()
}
}
impl TerminalGuard {
pub fn new() -> Self {
#[cfg(unix)]
{
let saved_attrs = save_terminal_attrs();
TerminalGuard { saved_attrs }
}
#[cfg(not(unix))]
{
TerminalGuard
}
}
pub fn restore_now(&mut self) {
#[cfg(unix)]
{
if let Some(ref attrs) = self.saved_attrs {
restore_terminal_attrs(attrs);
self.saved_attrs = None;
}
}
restore_cursor_visibility();
}
}
impl Drop for TerminalGuard {
fn drop(&mut self) {
self.restore_now();
}
}
#[cfg(unix)]
fn save_terminal_attrs() -> Option<Termios> {
let stdin = std::io::stdin();
let fd = stdin.as_raw_fd();
unsafe {
let borrowed_fd = BorrowedFd::borrow_raw(fd);
termios::tcgetattr(borrowed_fd).ok()
}
}
#[cfg(unix)]
fn restore_terminal_attrs(attrs: &Termios) {
let stdin = std::io::stdin();
let fd = stdin.as_raw_fd();
unsafe {
let borrowed_fd = BorrowedFd::borrow_raw(fd);
let _ = termios::tcsetattr(borrowed_fd, SetArg::TCSANOW, attrs);
}
}
fn restore_cursor_visibility() {
let _ = std::io::stdout().write_all(b"\x1b[?25h");
let _ = std::io::stdout().flush();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_terminal_guard_creation() {
let _guard = TerminalGuard::new();
}
#[test]
fn test_terminal_guard_drop() {
{
let _guard = TerminalGuard::new();
} }
#[test]
fn test_cursor_visibility_no_panic() {
restore_cursor_visibility();
}
}