parsql_cli/ui/
mod.rs

1//! Interactive TUI module for parsql CLI
2
3mod app;
4mod command_input;
5mod components;
6mod event;
7mod keys;
8mod migration_list;
9mod migration_detail;
10mod help;
11mod theme;
12mod output_stream;
13mod database;
14mod migration_creator;
15mod migration_loader;
16mod migration_executor;
17mod migration_viewer;
18mod migration_content_view;
19
20use anyhow::Result;
21use crossterm::{
22    event::{DisableMouseCapture, EnableMouseCapture},
23    execute,
24    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
25};
26use ratatui::{
27    backend::CrosstermBackend,
28    Terminal,
29};
30use std::io;
31
32pub use app::App;
33use event::{Event, EventHandler};
34
35/// Run the interactive TUI
36pub fn run_tui(
37    database_url: Option<String>,
38    config: crate::config::Config,
39    verbose: bool,
40) -> Result<()> {
41    // Setup terminal
42    enable_raw_mode()?;
43    let mut stdout = io::stdout();
44    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
45    let backend = CrosstermBackend::new(stdout);
46    let mut terminal = Terminal::new(backend)?;
47
48    // Create app state
49    let mut app = App::new(database_url, config, verbose);
50    
51    // Create event handler
52    let event_handler = EventHandler::new(250);
53
54    // Run the app
55    let res = run_app(&mut terminal, &mut app, event_handler);
56
57    // Restore terminal
58    disable_raw_mode()?;
59    execute!(
60        terminal.backend_mut(),
61        LeaveAlternateScreen,
62        DisableMouseCapture
63    )?;
64    terminal.show_cursor()?;
65
66    if let Err(err) = res {
67        println!("Error: {:?}", err);
68    }
69
70    Ok(())
71}
72
73fn run_app<B: ratatui::backend::Backend>(
74    terminal: &mut Terminal<B>,
75    app: &mut App,
76    mut event_handler: EventHandler,
77) -> Result<()> {
78    loop {
79        // Draw UI
80        terminal.draw(|f| app.draw(f))?;
81
82        // Handle events
83        match event_handler.next()? {
84            Event::Tick => app.tick(),
85            Event::Key(key_event) => {
86                if app.handle_key_event(key_event)? {
87                    return Ok(());
88                }
89                // Check if app should quit
90                if app.should_quit {
91                    return Ok(());
92                }
93            }
94            Event::Mouse(_) => {}
95            Event::Resize(_, _) => {}
96        }
97    }
98}