1pub mod app;
2pub mod components;
3pub mod event_explorer;
4pub mod events;
5pub mod ui;
6
7use crossterm::{
8 execute,
9 terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
10};
11use ratatui::{backend::CrosstermBackend, Terminal};
12use std::io;
13use tokio::sync::mpsc;
14use tracing::debug;
15
16use app::TuiApp;
17use events::{handle_input, InputEvent};
18use theater_server::ManagementResponse;
19use ui::render_ui;
20
21pub async fn run_tui(
22 actor_id: String,
23 manifest_path: String,
24 mut response_rx: mpsc::UnboundedReceiver<ManagementResponse>,
25) -> Result<(), Box<dyn std::error::Error>> {
26 debug!("Starting TUI for actor: {}", actor_id);
27
28 enable_raw_mode()?;
30 let mut stdout = io::stdout();
31 execute!(stdout, EnterAlternateScreen)?;
32 let backend = CrosstermBackend::new(stdout);
33 let mut terminal = Terminal::new(backend)?;
34
35 let mut app = TuiApp::new(actor_id, manifest_path);
37
38 let result = run_tui_loop(&mut terminal, &mut app, &mut response_rx).await;
40
41 disable_raw_mode()?;
43 execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
44 terminal.show_cursor()?;
45
46 result
47}
48
49async fn run_tui_loop(
50 terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
51 app: &mut TuiApp,
52 response_rx: &mut mpsc::UnboundedReceiver<ManagementResponse>,
53) -> Result<(), Box<dyn std::error::Error>> {
54 loop {
55 terminal.draw(|f| render_ui(f, app))?;
57
58 match handle_input(app)? {
60 InputEvent::Quit => {
61 app.quit();
62 break;
63 }
64 InputEvent::TogglePause => {
65 app.toggle_pause();
66 debug!("Toggled pause state: paused={}", app.paused);
67 }
68 InputEvent::ToggleAutoScroll => {
69 app.toggle_auto_scroll();
70 debug!("Toggled auto-scroll: enabled={}", app.auto_scroll);
71 }
72 InputEvent::ClearEvents => {
73 app.reset_events();
74 debug!("Cleared event history");
75 }
76 InputEvent::None => {}
77 }
78
79 while let Ok(response) = response_rx.try_recv() {
81 debug!("TUI received management response: {:?}", response);
82 app.handle_management_response(response);
83 }
84
85 if app.should_quit {
87 debug!("TUI quitting");
88 break;
89 }
90
91 tokio::time::sleep(tokio::time::Duration::from_millis(16)).await; }
94
95 Ok(())
96}