use std::io::{self, Read as _};
use crossterm::terminal::enable_raw_mode;
use tokio::signal::unix::{SignalKind, signal};
use tokio::sync::mpsc;
use super::{Size, Tty};
use crate::lookout::term;
const READ_BYTES: usize = 4096;
fn read_stdin() -> mpsc::Receiver<Vec<u8>> {
let (tx, rx) = mpsc::channel(64);
std::thread::spawn(move || {
let mut stdin = io::stdin().lock();
let mut buffer = [0_u8; READ_BYTES];
while let Ok(read) = stdin.read(&mut buffer) {
if read == 0 || tx.blocking_send(buffer[..read].to_vec()).is_err() {
break;
}
}
});
rx
}
fn window_size() -> io::Result<Size> {
let (cols, rows) = crossterm::terminal::size()?;
Ok(Size { rows, cols })
}
fn watch_resizes() -> io::Result<(mpsc::Receiver<Size>, tokio::task::JoinHandle<()>)> {
let mut winch = signal(SignalKind::window_change())?;
let (tx, rx) = mpsc::channel(8);
let task = tokio::spawn(async move {
while winch.recv().await.is_some() {
let Ok(size) = window_size() else { continue };
if tx.send(size).await.is_err() {
break;
}
}
});
Ok((rx, task))
}
pub(super) fn open() -> io::Result<Tty> {
let size = window_size()?;
let (resizes, watcher) = watch_resizes()?;
term::install_panic_hook();
let restore = term::RestoreGuard::with_action(move || {
watcher.abort();
let _ = super::reset_modes(&mut io::stdout());
term::restore();
});
enable_raw_mode()?;
Ok(Tty {
size,
keys: read_stdin(),
resizes,
restore,
})
}