mod impls; mod retval; mod utils; mod windows; use anyhow::Result as AResult; use backtrace::Backtrace; use crossterm::event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}; use crossterm::execute; use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; use once_cell::sync::Lazy; use retval::{RetVal, ReturnValue}; use std::panic::set_hook; use std::process::exit; use std::{ io::{stdout, Stdout}, thread, time::Duration, }; use tui::{backend::CrosstermBackend, Terminal}; use utils::Channel; use windows::{MainWnd, SharedWnd, WindowsHandler, WndId}; pub type Backend = CrosstermBackend; pub type Frame<'f> = tui::Frame<'f, Backend>; const EVENT_GEN_PERIOD: Duration = Duration::from_millis(120); static GENERAL_EVENT_CHANNEL: Lazy> = Lazy::new(|| Channel::new()); enum GEvent { CreateWnd(SharedWnd), CloseWnd { wid: WndId, force: bool }, Key(KeyCode), Tick, } fn get_terminal() -> AResult> { let backend = CrosstermBackend::new(stdout()); Ok(Terminal::new(backend)?) } pub async fn init_tui() -> AResult<()> { //TODO: fix this set_hook(Box::new(|p| { teardown().unwrap(); get_terminal().unwrap().show_cursor().unwrap(); eprintln!("{}\n{:?}", p, Backtrace::new()); exit(254); })); if let Err(e) = init().await { teardown()?; return Err(e); } Ok(()) } async fn init() -> AResult<()> { enable_raw_mode()?; execute!(stdout(), EnterAlternateScreen, EnableMouseCapture)?; WindowsHandler::lock().await.push_new::().await; thread::spawn(move || loop { if event::poll(EVENT_GEN_PERIOD).unwrap() { match event::read().unwrap() { Event::Key(key) => GENERAL_EVENT_CHANNEL.send(GEvent::Key(key.code)), _ => (), } } else { GENERAL_EVENT_CHANNEL.send(GEvent::Tick) } }); WindowsHandler::lock().await.clear()?; loop { match GENERAL_EVENT_CHANNEL.recv() { GEvent::Tick => { let mut wh = WindowsHandler::lock().await; wh.update().await?; wh.draw().await?; } GEvent::CloseWnd { wid, force } => { let mut wh = WindowsHandler::lock().await; wh.close(wid, force).await; } GEvent::Key(key) => { WindowsHandler::lock().await.send_handle_kbd(key); } GEvent::CreateWnd(wnd) => { WindowsHandler::lock().await.push_dyn(wnd).await; } } } } fn teardown() -> AResult<()> { disable_raw_mode()?; execute!(stdout(), LeaveAlternateScreen, DisableMouseCapture)?; Ok(()) }