mod exit;
mod terminal;
pub use exit::{request_exit, reset_exit, should_exit};
pub use terminal::{ManagedTerminal, restore_terminal, setup_terminal};
use anyhow::Result;
use crossterm::event::{self, Event};
use reratui_core::Element;
use reratui_hooks::frame::FrameContext;
use reratui_hooks::hook_context::HookContext;
use std::{
rc::Rc,
time::{Duration, Instant},
};
pub async fn render<F>(initializer: F) -> Result<()>
where
F: Fn() -> Element + 'static,
{
reratui_panic::setup_panic_handler();
let mut terminal = setup_terminal()?;
let hook_context = Rc::new(HookContext::new());
reratui_hooks::hook_context::set_hook_context(hook_context.clone());
let element = initializer();
let mut frame_count: u64 = 0;
let mut last_frame_time = Instant::now();
let mut running = true;
while running {
let current_time = Instant::now();
let delta = current_time.duration_since(last_frame_time);
last_frame_time = current_time;
hook_context.reset_hook_index();
if event::poll(Duration::from_millis(16))? {
if let Ok(event) = event::read() {
let processed = if let Event::Key(key_event) = &event {
reratui_hooks::event::global_events::process_global_event(key_event)
} else {
false
};
if !processed {
reratui_hooks::event::set_current_event(Some(std::sync::Arc::new(event)));
if should_exit() {
running = false;
}
}
}
} else {
reratui_hooks::event::set_current_event(None);
}
if should_exit() {
running = false;
}
terminal.draw(|frame| {
let frame_ctx = unsafe { FrameContext::new(frame, frame_count, delta, current_time) };
let _frame_context = reratui_hooks::context::use_context_provider(|| frame_ctx);
let area = frame.area();
element.render(area, frame.buffer_mut());
})?;
reratui_core::component::cleanup_unmounted();
frame_count += 1;
tokio::time::sleep(Duration::from_millis(16)).await;
}
reratui_hooks::event::set_current_event(None);
reratui_hooks::hook_context::clear_hook_context();
restore_terminal()?;
Ok(())
}