mod agent;
mod app;
mod history;
mod ui;
use std::io;
use std::time::Duration;
use crossterm::event;
use ratatui::backend::CrosstermBackend;
use ratatui::{Terminal, TerminalOptions, Viewport};
use tuika::probe::RectProbe;
use tuika::{StyleSheet, TerminalSession, paint, translate_event};
use crate::app::{App, Flow};
pub const FRAME_MS: u64 = 60;
fn main() -> io::Result<()> {
let args: Vec<String> = std::env::args().skip(1).collect();
match args.first().map(String::as_str) {
Some("--help" | "-h") => {
println!("A replica of the Codex CLI's interface, built on tuika.");
println!("Not the Codex CLI; not affiliated with OpenAI. The agent is scripted:");
println!("no model, no network, no shell.");
println!();
println!("usage: cargo run --example codex [-- --dump [scene]]");
println!("scenes: welcome, turn, approval, slash, mention, status");
Ok(())
}
Some("--dump") => ui::dump(args.get(1).map(String::as_str)),
_ => run(),
}
}
fn run() -> io::Result<()> {
let mut app = App::new();
let theme = app::codex_theme();
let sheet = StyleSheet::from_theme(&theme);
let probe = RectProbe::new();
let _session = TerminalSession::enter()?;
let mut terminal = Terminal::with_options(
CrosstermBackend::new(io::stdout()),
TerminalOptions {
viewport: Viewport::Fullscreen,
},
)?;
loop {
terminal.draw(|f| {
let area = f.area();
let root = ui::build(&mut app, area, &theme, &sheet, &probe);
paint(f.buffer_mut(), area, &theme, root.as_ref(), &[]);
if let Some(pos) = app.cursor(probe.rect()) {
f.set_cursor_position(pos);
}
})?;
if event::poll(Duration::from_millis(FRAME_MS))?
&& let Some(ev) = translate_event(event::read()?)
&& app.handle(&ev) == Flow::Quit
{
break;
}
app.tick();
}
let _ = terminal.clear();
drop(terminal);
Ok(())
}