use std::io::stdout;
use std::time::Duration;
use anyhow::{Context, Result};
use crossterm::event::{self, Event, KeyEventKind};
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};
use crossterm::{ExecutableCommand, execute};
use escriba_runtime::EditorState;
use madori::AppEvent;
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use crate::keys::crossterm_key_event;
use crate::render::draw_frame;
pub fn run(mut state: EditorState) -> Result<()> {
let mut out = stdout();
out.execute(EnterAlternateScreen)
.context("claiming alt screen")?;
enable_raw_mode().context("enabling raw mode")?;
let result = inner_loop(&mut state);
let _ = disable_raw_mode();
let _ = execute!(out, LeaveAlternateScreen);
result
}
fn inner_loop(state: &mut EditorState) -> Result<()> {
let mut terminal =
Terminal::new(CrosstermBackend::new(stdout())).context("opening ratatui terminal")?;
let size = terminal.size()?;
crate::render::sync_viewport(state, size.width, size.height);
terminal.draw(|f| draw_frame(f, state))?;
loop {
if state.quit_requested {
return Ok(());
}
state.deliver();
if event::poll(Duration::from_millis(200))? {
match event::read()? {
Event::Key(ke) if ke.kind == KeyEventKind::Press => {
state.tick(&AppEvent::Key(crossterm_key_event(&ke)));
}
Event::Resize(w, h) => {
crate::render::sync_viewport(state, w, h);
}
Event::FocusGained | Event::FocusLost | Event::Mouse(_) | Event::Paste(_) => {
}
_ => {}
}
}
let size = terminal.size()?;
crate::render::sync_viewport(state, size.width, size.height);
terminal.draw(|f| draw_frame(f, state))?;
}
}