Skip to main content

ghostscope_ui/components/
app.rs

1mod actions;
2mod event_loop;
3mod logging;
4mod render;
5mod runtime_status;
6
7use crate::events::EventRegistry;
8use crate::model::ui_state::LayoutMode;
9use crate::model::AppState;
10use anyhow::Result;
11use crossterm::{
12    event::EnableBracketedPaste,
13    execute,
14    terminal::{enable_raw_mode, EnterAlternateScreen},
15};
16use ratatui::{backend::CrosstermBackend, Terminal};
17use std::io;
18
19/// Modern TUI application using TEA architecture
20pub struct App {
21    terminal: Terminal<CrosstermBackend<io::Stdout>>,
22    state: AppState,
23    should_quit: bool,
24}
25
26impl App {
27    /// Create a new application instance
28    pub async fn new(event_registry: EventRegistry, layout_mode: LayoutMode) -> Result<Self> {
29        // Setup terminal
30        enable_raw_mode()?;
31        let mut stdout = io::stdout();
32        execute!(stdout, EnterAlternateScreen)?;
33        // Enable bracketed paste to detect paste events (does not affect mouse selection copy)
34        execute!(stdout, EnableBracketedPaste)?;
35        // Mouse capture disabled to allow standard copy/paste functionality
36        let backend = CrosstermBackend::new(stdout);
37        let terminal = Terminal::new(backend)?;
38
39        let mut state = AppState::new(event_registry, layout_mode);
40
41        // Request initial source code on startup if source panel is enabled
42        if state.ui.config.show_source_panel {
43            if let Err(e) = state
44                .event_registry
45                .command_sender
46                .send(crate::events::RuntimeCommand::RequestSourceCode)
47            {
48                tracing::warn!("Failed to send initial source code request: {}", e);
49            } else {
50                // Move to connecting state since we've sent the request
51                state.set_loading_state(
52                    crate::components::loading::LoadingState::ConnectingToRuntime,
53                );
54            }
55        }
56
57        Ok(Self {
58            terminal,
59            state,
60            should_quit: false,
61        })
62    }
63
64    /// Create a new application instance with full UI configuration
65    pub async fn new_with_config(
66        event_registry: EventRegistry,
67        ui_config: crate::model::ui_state::UiConfig,
68    ) -> Result<Self> {
69        // Setup terminal
70        enable_raw_mode()?;
71        let mut stdout = io::stdout();
72        execute!(stdout, EnterAlternateScreen)?;
73        // Enable bracketed paste to detect paste events (does not affect mouse selection copy)
74        execute!(stdout, EnableBracketedPaste)?;
75        // Mouse capture disabled to allow standard copy/paste functionality
76        let backend = CrosstermBackend::new(stdout);
77        let terminal = Terminal::new(backend)?;
78
79        let mut state = AppState::new_with_config(event_registry, ui_config);
80
81        // Request initial source code on startup if source panel is enabled
82        if state.ui.config.show_source_panel {
83            if let Err(e) = state
84                .event_registry
85                .command_sender
86                .send(crate::events::RuntimeCommand::RequestSourceCode)
87            {
88                tracing::warn!("Failed to send initial source code request: {}", e);
89            } else {
90                // Move to connecting state since we've sent the request
91                state.set_loading_state(
92                    crate::components::loading::LoadingState::ConnectingToRuntime,
93                );
94            }
95        }
96
97        Ok(Self {
98            terminal,
99            state,
100            should_quit: false,
101        })
102    }
103}