1pub mod app;
6pub mod backend;
7pub mod event;
8pub mod handler;
9pub mod screens;
10pub mod ui;
11pub mod widgets;
12
13use crate::config::{Config, WorkspaceManager};
14use crate::errors::Result;
15use app::App;
16use crossterm::{
17 execute,
18 terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
19};
20use ratatui::backend::CrosstermBackend;
21use ratatui::Terminal;
22use std::io;
23use std::time::Duration;
24
25pub async fn run_tui(config: Config, config_was_created: bool) -> Result<()> {
27 enable_raw_mode()?;
29 let mut stdout = io::stdout();
30 if let Err(e) = execute!(stdout, EnterAlternateScreen) {
31 let _ = disable_raw_mode();
32 return Err(e.into());
33 }
34 let backend = CrosstermBackend::new(stdout);
35 let mut terminal = match Terminal::new(backend) {
36 Ok(terminal) => terminal,
37 Err(e) => {
38 let _ = disable_raw_mode();
39 let mut stdout = io::stdout();
40 let _ = execute!(stdout, LeaveAlternateScreen);
41 return Err(e.into());
42 }
43 };
44
45 let result = async {
46 let workspaces = WorkspaceManager::list()?;
48
49 let mut app = App::new(config, workspaces, config_was_created);
51
52 let tick_rate = Duration::from_millis(100);
54 let (mut rx, backend_tx) = event::spawn_event_loop(tick_rate);
55
56 run_app(&mut terminal, &mut app, &mut rx, &backend_tx).await
58 }
59 .await;
60
61 let _ = disable_raw_mode();
63 let _ = execute!(terminal.backend_mut(), LeaveAlternateScreen);
64 let _ = terminal.show_cursor();
65
66 result
67}
68
69async fn run_app(
70 terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
71 app: &mut App,
72 rx: &mut tokio::sync::mpsc::UnboundedReceiver<event::AppEvent>,
73 backend_tx: &tokio::sync::mpsc::UnboundedSender<event::AppEvent>,
74) -> Result<()> {
75 loop {
76 terminal.draw(|frame| ui::render(app, frame))?;
77
78 match rx.recv().await {
79 Some(event) => handler::handle_event(app, event, backend_tx).await,
80 None => break,
81 }
82
83 if app.should_quit {
84 break;
85 }
86 }
87 Ok(())
88}