use bmux_tui::crossterm::read_event;
use bmux_tui::event::Event;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use tokio::sync::mpsc;
use crate::tui_host_types::TuiError;
pub struct TuiInput {
receiver: mpsc::UnboundedReceiver<Result<Option<Event>, std::io::Error>>,
shutdown: Arc<AtomicBool>,
thread: Option<JoinHandle<()>>,
}
impl TuiInput {
#[must_use]
pub fn start() -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
let shutdown = Arc::new(AtomicBool::new(false));
let thread_shutdown = Arc::clone(&shutdown);
let thread = std::thread::spawn(move || {
while !thread_shutdown.load(Ordering::Relaxed) {
match read_event() {
Ok(event) => {
if sender.send(Ok(event)).is_err() {
break;
}
}
Err(error) => {
let _ = sender.send(Err(error));
break;
}
}
}
});
Self {
receiver,
shutdown,
thread: Some(thread),
}
}
pub async fn recv(&mut self) -> Result<Option<Event>, TuiError> {
match self.receiver.recv().await {
Some(Ok(event)) => Ok(event),
Some(Err(error)) => Err(error.into()),
None => Err(std::io::Error::other("terminal event stream closed").into()),
}
}
pub fn request_shutdown(&self) {
self.shutdown.store(true, Ordering::Relaxed);
}
}
impl Drop for TuiInput {
fn drop(&mut self) {
self.request_shutdown();
let _detached = self.thread.take();
}
}