diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index e232ab5..53e0771 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -1,52 +1,50 @@ // src/modes/handlers/event.rs -use crossterm::event::{Event, KeyEvent}; -use crossterm::cursor::SetCursorStyle; -use crate::services::grpc_client::GrpcClient; -use crate::services::auth::AuthClient; use crate::config::binds::config::Config; -use crate::ui::handlers::rat_state::UiStateHandler; -use crate::ui::handlers::context::UiContext; +use crate::config::binds::key_sequences::KeySequenceTracker; use crate::functions::common::buffer; -use anyhow::Result; -use crate::tui::{ - terminal::core::TerminalCore, - functions::{ - common::{form::SaveOutcome, login, register}, - }, - {intro, admin}, +use crate::functions::modes::navigation::add_logic_nav; +use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender; +use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; +use crate::functions::modes::navigation::{add_table_nav, admin_nav}; +use crate::modes::general::command_navigation::{ + handle_command_navigation_event, NavigationState, TableDependencyGraph, }; +use crate::modes::{ + canvas::{common_mode, edit, read_only}, + common::{command_mode, commands::CommandHandler}, + general::{dialog, navigation}, + handlers::mode_manager::{AppMode, ModeManager}, +}; +use crate::services::auth::AuthClient; +use crate::services::grpc_client::GrpcClient; use crate::state::{ app::{ + buffer::{AppView, BufferState}, highlight::HighlightState, state::AppState, - buffer::{AppView, BufferState}, }, pages::{ - auth::{AuthState, LoginState, RegisterState}, admin::AdminState, + auth::{AuthState, LoginState, RegisterState}, canvas_state::CanvasState, form::FormState, intro::IntroState, }, }; -use crate::modes::{ - common::{command_mode, commands::CommandHandler}, - handlers::mode_manager::{ModeManager, AppMode}, - canvas::{edit, read_only, common_mode}, - general::{navigation, dialog}, -}; -use crate::modes::general::command_navigation::{ - handle_command_navigation_event, NavigationState, TableDependencyGraph, -}; -use crate::functions::modes::navigation::{admin_nav, add_table_nav}; -use crate::config::binds::key_sequences::KeySequenceTracker; -use tokio::sync::mpsc; use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::register::RegisterResult; -use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; -use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender; -use crate::functions::modes::navigation::add_logic_nav; +use crate::tui::{ + functions::common::{form::SaveOutcome, login, register}, + terminal::core::TerminalCore, + {admin, intro}, +}; +use crate::ui::handlers::context::UiContext; +use crate::ui::handlers::rat_state::UiStateHandler; +use anyhow::Result; +use crossterm::cursor::SetCursorStyle; use crossterm::event::KeyCode; +use crossterm::event::{Event, KeyEvent}; +use tokio::sync::mpsc; #[derive(Debug, Clone, PartialEq, Eq)] pub enum EventOutcome { @@ -139,12 +137,10 @@ impl EventHandler { // Handle active command navigation first if current_mode == AppMode::General && self.navigation_state.active { if let Event::Key(key_event) = event { - let outcome = handle_command_navigation_event( - &mut self.navigation_state, - key_event, - config, - ).await?; - + let outcome = + handle_command_navigation_event(&mut self.navigation_state, key_event, config) + .await?; + if !self.navigation_state.active { self.command_message = outcome.get_message_if_ok(); current_mode = ModeManager::derive_mode(app_state, self, admin_state); @@ -160,14 +156,23 @@ impl EventHandler { let current_view = { let ui = &app_state.ui; - if ui.show_intro { AppView::Intro } - else if ui.show_login { AppView::Login } - else if ui.show_register { AppView::Register } - else if ui.show_admin { AppView::Admin } - else if ui.show_add_logic { AppView::AddLogic } - else if ui.show_add_table { AppView::AddTable } - else if ui.show_form { AppView::Form } - else { AppView::Scratch } + if ui.show_intro { + AppView::Intro + } else if ui.show_login { + AppView::Login + } else if ui.show_register { + AppView::Register + } else if ui.show_admin { + AppView::Admin + } else if ui.show_add_logic { + AppView::AddLogic + } else if ui.show_add_table { + AppView::AddTable + } else if ui.show_form { + AppView::Form + } else { + AppView::Scratch + } }; buffer_state.update_history(current_view); @@ -175,11 +180,18 @@ impl EventHandler { if let Event::Key(key_event) = event { if let Some(dialog_result) = dialog::handle_dialog_event( &Event::Key(key_event), - config, app_state, login_state, register_state, buffer_state, admin_state, - ).await { + config, + app_state, + login_state, + register_state, + buffer_state, + admin_state, + ) + .await + { return dialog_result; } - } else if let Event::Resize(_,_) = event { + } else if let Event::Resize(_, _) = event { // Handle resize if needed } return Ok(EventOutcome::Ok(String::new())); @@ -190,17 +202,33 @@ impl EventHandler { let modifiers = key_event.modifiers; if UiStateHandler::toggle_sidebar(&mut app_state.ui, config, key_code, modifiers) { - let message = format!("Sidebar {}", if app_state.ui.show_sidebar { "shown" } else { "hidden" }); + let message = format!( + "Sidebar {}", + if app_state.ui.show_sidebar { + "shown" + } else { + "hidden" + } + ); return Ok(EventOutcome::Ok(message)); } if UiStateHandler::toggle_buffer_list(&mut app_state.ui, config, key_code, modifiers) { - let message = format!("Buffer {}", if app_state.ui.show_buffer_list { "shown" } else { "hidden" }); + let message = format!( + "Buffer {}", + if app_state.ui.show_buffer_list { + "shown" + } else { + "hidden" + } + ); return Ok(EventOutcome::Ok(message)); } if !matches!(current_mode, AppMode::Edit | AppMode::Command) { if let Some(action) = config.get_action_for_key_in_mode( - &config.keybindings.global, key_code, modifiers + &config.keybindings.global, + key_code, + modifiers, ) { match action { "next_buffer" => { @@ -210,12 +238,15 @@ impl EventHandler { } "previous_buffer" => { if buffer::switch_buffer(buffer_state, false) { - return Ok(EventOutcome::Ok("Switched to previous buffer".to_string())); + return Ok(EventOutcome::Ok( + "Switched to previous buffer".to_string(), + )); } } "close_buffer" => { let current_table_name = Some("2025_customer"); - let message = buffer_state.close_buffer_with_intro_fallback(current_table_name); + let message = + buffer_state.close_buffer_with_intro_fallback(current_table_name); return Ok(EventOutcome::Ok(message)); } _ => {} @@ -287,7 +318,8 @@ impl EventHandler { &mut self.command_input, &mut self.command_message, &mut self.navigation_state, - ).await; + ) + .await; match nav_outcome { Ok(EventOutcome::ButtonSelected { context, index }) => { @@ -301,24 +333,36 @@ impl EventHandler { } format!("Intro Option {} selected", index) } - UiContext::Login => { - match index { - 0 => { - login::initiate_login(login_state, app_state, self.auth_client.clone(), self.login_result_sender.clone()) - }, - 1 => login::back_to_main(login_state, app_state, buffer_state).await, - _ => "Invalid Login Option".to_string(), + UiContext::Login => match index { + 0 => login::initiate_login( + login_state, + app_state, + self.auth_client.clone(), + self.login_result_sender.clone(), + ), + 1 => { + login::back_to_main(login_state, app_state, buffer_state) + .await } - } - UiContext::Register => { - match index { - 0 => { - register::initiate_registration(register_state, app_state, self.auth_client.clone(), self.register_result_sender.clone()) - }, - 1 => register::back_to_login(register_state, app_state, buffer_state).await, - _ => "Invalid Login Option".to_string(), + _ => "Invalid Login Option".to_string(), + }, + UiContext::Register => match index { + 0 => register::initiate_registration( + register_state, + app_state, + self.auth_client.clone(), + self.register_result_sender.clone(), + ), + 1 => { + register::back_to_login( + register_state, + app_state, + buffer_state, + ) + .await } - } + _ => "Invalid Login Option".to_string(), + }, UiContext::Admin => { admin::handle_admin_selection(app_state, admin_state); format!("Admin Option {} selected", index) @@ -334,53 +378,76 @@ impl EventHandler { } AppMode::ReadOnly => { - if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") + if config.get_read_only_action_for_key(key_code, modifiers) + == Some("enter_highlight_mode_linewise") && ModeManager::can_enter_highlight_mode(current_mode) { - let current_field_index = if app_state.ui.show_login { login_state.current_field() } - else if app_state.ui.show_register { register_state.current_field() } - else { form_state.current_field() }; - self.highlight_state = HighlightState::Linewise { anchor_line: current_field_index }; + let current_field_index = if app_state.ui.show_login { + login_state.current_field() + } else if app_state.ui.show_register { + register_state.current_field() + } else { + form_state.current_field() + }; + self.highlight_state = HighlightState::Linewise { + anchor_line: current_field_index, + }; self.command_message = "-- LINE HIGHLIGHT --".to_string(); return Ok(EventOutcome::Ok(self.command_message.clone())); - } - else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode") + } else if config.get_read_only_action_for_key(key_code, modifiers) + == Some("enter_highlight_mode") && ModeManager::can_enter_highlight_mode(current_mode) { - let current_field_index = if app_state.ui.show_login { login_state.current_field() } - else if app_state.ui.show_register { register_state.current_field() } - else { form_state.current_field() }; - let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } - else if app_state.ui.show_register { register_state.current_cursor_pos() } - else { form_state.current_cursor_pos() }; + let current_field_index = if app_state.ui.show_login { + login_state.current_field() + } else if app_state.ui.show_register { + register_state.current_field() + } else { + form_state.current_field() + }; + let current_cursor_pos = if app_state.ui.show_login { + login_state.current_cursor_pos() + } else if app_state.ui.show_register { + register_state.current_cursor_pos() + } else { + form_state.current_cursor_pos() + }; let anchor = (current_field_index, current_cursor_pos); self.highlight_state = HighlightState::Characterwise { anchor }; self.command_message = "-- HIGHLIGHT --".to_string(); return Ok(EventOutcome::Ok(self.command_message.clone())); - } - else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_before") - && ModeManager::can_enter_edit_mode(current_mode) { + } else if config + .get_read_only_action_for_key(key_code, modifiers) + .as_deref() + == Some("enter_edit_mode_before") + && ModeManager::can_enter_edit_mode(current_mode) + { self.is_edit_mode = true; self.edit_mode_cooldown = true; self.command_message = "Edit mode".to_string(); terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; return Ok(EventOutcome::Ok(self.command_message.clone())); - } - else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_after") - && ModeManager::can_enter_edit_mode(current_mode) { - let current_input = if app_state.ui.show_login || app_state.ui.show_register{ + } else if config + .get_read_only_action_for_key(key_code, modifiers) + .as_deref() + == Some("enter_edit_mode_after") + && ModeManager::can_enter_edit_mode(current_mode) + { + let current_input = if app_state.ui.show_login || app_state.ui.show_register + { login_state.get_current_input() } else { form_state.get_current_input() }; - let current_cursor_pos = if app_state.ui.show_login || app_state.ui.show_register{ - login_state.current_cursor_pos() - } else { - form_state.current_cursor_pos() - }; + let current_cursor_pos = + if app_state.ui.show_login || app_state.ui.show_register { + login_state.current_cursor_pos() + } else { + form_state.current_cursor_pos() + }; if !current_input.is_empty() && current_cursor_pos < current_input.len() { - if app_state.ui.show_login || app_state.ui.show_register{ + if app_state.ui.show_login || app_state.ui.show_register { login_state.set_current_cursor_pos(current_cursor_pos + 1); self.ideal_cursor_column = login_state.current_cursor_pos(); } else { @@ -394,13 +461,14 @@ impl EventHandler { self.command_message = "Edit mode (after cursor)".to_string(); terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; return Ok(EventOutcome::Ok(self.command_message.clone())); - } - else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode") - && ModeManager::can_enter_command_mode(current_mode) { - self.command_mode = true; - self.command_input.clear(); - self.command_message.clear(); - return Ok(EventOutcome::Ok(String::new())); + } else if config.get_read_only_action_for_key(key_code, modifiers) + == Some("enter_command_mode") + && ModeManager::can_enter_command_mode(current_mode) + { + self.command_mode = true; + self.command_input.clear(); + self.command_message.clear(); + return Ok(EventOutcome::Ok(String::new())); } if let Some(action) = config.get_common_action(key_code, modifiers) { @@ -418,8 +486,9 @@ impl EventHandler { app_state, current_position, total_count, - ).await; - }, + ) + .await; + } _ => {} } } @@ -440,28 +509,38 @@ impl EventHandler { &mut self.command_message, &mut self.edit_mode_cooldown, &mut self.ideal_cursor_column, - ).await?; + ) + .await?; return Ok(EventOutcome::Ok(message)); } AppMode::Highlight => { - if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") { - self.highlight_state = HighlightState::Off; - self.command_message = "Exited highlight mode".to_string(); - terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; - return Ok(EventOutcome::Ok(self.command_message.clone())); - } - else if config.get_highlight_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") { - if let HighlightState::Characterwise { anchor } = self.highlight_state { - self.highlight_state = HighlightState::Linewise { anchor_line: anchor.0 }; - self.command_message = "-- LINE HIGHLIGHT --".to_string(); - return Ok(EventOutcome::Ok(self.command_message.clone())); - } + if config.get_highlight_action_for_key(key_code, modifiers) + == Some("exit_highlight_mode") + { + self.highlight_state = HighlightState::Off; + self.command_message = "Exited highlight mode".to_string(); + terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; + return Ok(EventOutcome::Ok(self.command_message.clone())); + } else if config.get_highlight_action_for_key(key_code, modifiers) + == Some("enter_highlight_mode_linewise") + { + if let HighlightState::Characterwise { anchor } = self.highlight_state { + self.highlight_state = HighlightState::Linewise { + anchor_line: anchor.0, + }; + self.command_message = "-- LINE HIGHLIGHT --".to_string(); + return Ok(EventOutcome::Ok(self.command_message.clone())); + } return Ok(EventOutcome::Ok("".to_string())); - } + } let (_should_exit, message) = read_only::handle_read_only_event( - app_state, key_event, config, form_state, login_state, + app_state, + key_event, + config, + form_state, + login_state, register_state, &mut admin_state.add_table_state, &mut admin_state.add_logic_state, @@ -493,8 +572,9 @@ impl EventHandler { app_state, current_position, total_count, - ).await; - }, + ) + .await; + } _ => {} } } @@ -511,30 +591,52 @@ impl EventHandler { total_count, grpc_client, app_state, - ).await; + ) + .await; match edit_result { Ok(edit::EditEventOutcome::ExitEditMode) => { self.is_edit_mode = false; self.edit_mode_cooldown = true; - let has_changes = if app_state.ui.show_login { login_state.has_unsaved_changes() } - else if app_state.ui.show_register { register_state.has_unsaved_changes() } - else { form_state.has_unsaved_changes() }; + let has_changes = if app_state.ui.show_login { + login_state.has_unsaved_changes() + } else if app_state.ui.show_register { + register_state.has_unsaved_changes() + } else { + form_state.has_unsaved_changes() + }; self.command_message = if has_changes { "Exited edit mode (unsaved changes remain)".to_string() } else { "Read-only mode".to_string() }; terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; - let current_input = if app_state.ui.show_login { login_state.get_current_input() } - else if app_state.ui.show_register { register_state.get_current_input() } - else { form_state.get_current_input() }; - let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } - else if app_state.ui.show_register { register_state.current_cursor_pos() } - else { form_state.current_cursor_pos() }; - if !current_input.is_empty() && current_cursor_pos >= current_input.len() { + let current_input = if app_state.ui.show_login { + login_state.get_current_input() + } else if app_state.ui.show_register { + register_state.get_current_input() + } else { + form_state.get_current_input() + }; + let current_cursor_pos = if app_state.ui.show_login { + login_state.current_cursor_pos() + } else if app_state.ui.show_register { + register_state.current_cursor_pos() + } else { + form_state.current_cursor_pos() + }; + if !current_input.is_empty() + && current_cursor_pos >= current_input.len() + { let new_pos = current_input.len() - 1; - let target_state: &mut dyn CanvasState = if app_state.ui.show_login { login_state } else if app_state.ui.show_register { register_state } else { form_state }; + let target_state: &mut dyn CanvasState = if app_state.ui.show_login + { + login_state + } else if app_state.ui.show_register { + register_state + } else { + form_state + }; target_state.set_current_cursor_pos(new_pos); self.ideal_cursor_column = new_pos; } @@ -564,10 +666,21 @@ impl EventHandler { if config.is_command_execute(key_code, modifiers) { let outcome = command_mode::handle_command_event( - key_event, config, app_state, login_state, register_state, form_state, - &mut self.command_input, &mut self.command_message, - grpc_client, command_handler, terminal, current_position, total_count, - ).await?; + key_event, + config, + app_state, + login_state, + register_state, + form_state, + &mut self.command_input, + &mut self.command_message, + grpc_client, + command_handler, + terminal, + current_position, + total_count, + ) + .await?; self.command_mode = false; self.key_sequence_tracker.reset(); let new_mode = ModeManager::derive_mode(app_state, self, admin_state); @@ -582,14 +695,19 @@ impl EventHandler { } if let KeyCode::Char(c) = key_code { - if c == 'f' { // Assuming 'f' is part of the sequence, e.g. ":f" or " f" + if c == 'f' { + // Assuming 'f' is part of the sequence, e.g. ":f" or " f" self.key_sequence_tracker.add_key(key_code); let sequence = self.key_sequence_tracker.get_sequence(); - if config.matches_key_sequence_generalized(&sequence) == Some("find_file_palette_toggle") { + if config.matches_key_sequence_generalized(&sequence) + == Some("find_file_palette_toggle") + { if app_state.ui.show_form || app_state.ui.show_intro { // Build table graph from profile data - let graph = TableDependencyGraph::from_profile_tree(&app_state.profile_tree); + let graph = TableDependencyGraph::from_profile_tree( + &app_state.profile_tree, + ); // Activate navigation with graph self.navigation_state.activate_table_tree(graph); @@ -601,14 +719,17 @@ impl EventHandler { self.key_sequence_tracker.reset(); // ModeManager will derive AppMode::General due to navigation_state.active // app_state.update_mode(AppMode::General); // This will be handled by ModeManager - return Ok(EventOutcome::Ok("Table tree palette activated".to_string())); + return Ok(EventOutcome::Ok( + "Table tree palette activated".to_string(), + )); } else { self.key_sequence_tracker.reset(); self.command_input.push('f'); if sequence.len() > 1 && sequence[0] == KeyCode::Char('f') { - self.command_input.push('f'); + self.command_input.push('f'); } - self.command_message = "Find File not available in this view.".to_string(); + self.command_message = + "Find File not available in this view.".to_string(); return Ok(EventOutcome::Ok(self.command_message.clone())); } } @@ -630,7 +751,7 @@ impl EventHandler { return Ok(EventOutcome::Ok(String::new())); } } - } else if let Event::Resize(_,_) = event { + } else if let Event::Resize(_, _) = event { return Ok(EventOutcome::Ok("Resized".to_string())); } diff --git a/client/src/ui/handlers/context.rs b/client/src/ui/handlers/context.rs index 8a755b1..2ad95da 100644 --- a/client/src/ui/handlers/context.rs +++ b/client/src/ui/handlers/context.rs @@ -21,4 +21,3 @@ pub enum DialogPurpose { // TODO in the future: // ConfirmQuit, } - diff --git a/client/src/ui/handlers/rat_state.rs b/client/src/ui/handlers/rat_state.rs index 4b35408..935ab20 100644 --- a/client/src/ui/handlers/rat_state.rs +++ b/client/src/ui/handlers/rat_state.rs @@ -1,4 +1,4 @@ -// src/ui/handlers/rat_state.rs +// client/src/ui/handlers/rat_state.rs use crossterm::event::{KeyCode, KeyModifiers}; use crate::config::binds::config::Config; use crate::state::app::state::UiState; diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index c03e332..34d5b1a 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -1,9 +1,9 @@ -// src/ui/handlers/render.rs +// client/src/ui/handlers/render.rs use crate::components::{ render_background, render_buffer_list, - render_command_line, // For the normal command line + render_command_line, render_status_line, intro::intro::render_intro, handlers::sidebar::{self, calculate_sidebar_layout}, @@ -11,13 +11,11 @@ use crate::components::{ admin::render_add_table, admin::add_logic::render_add_logic, auth::{login::render_login, register::render_register}, - common::find_file_palette, // Add this import + common::find_file_palette, }; use crate::config::colors::themes::Theme; use ratatui::{ - // layout::{Constraint, Direction, Layout, Rect}, // Rect might be unused if all areas are handled - layout::{Constraint, Direction, Layout}, // Style might be unused if all styling is in components - // style::Style, // Style might be unused + layout::{Constraint, Direction, Layout}, Frame, }; use crate::state::pages::canvas_state::CanvasState; @@ -48,7 +46,7 @@ pub fn render_ui( event_handler_command_input: &str, event_handler_command_mode_active: bool, event_handler_command_message: &str, - navigation_state: &NavigationState, // This is the correct reference + navigation_state: &NavigationState, total_count: u64, current_position: u64, current_dir: &str, @@ -59,26 +57,24 @@ pub fn render_ui( const PALETTE_OPTIONS_HEIGHT_FOR_LAYOUT: u16 = 15; - let mut bottom_area_constraints: Vec = vec![Constraint::Length(1)]; // For status_line + let mut bottom_area_constraints: Vec = vec![Constraint::Length(1)]; let command_palette_area_height = if navigation_state.active { - 1 + PALETTE_OPTIONS_HEIGHT_FOR_LAYOUT // Input line + fixed height for options + 1 + PALETTE_OPTIONS_HEIGHT_FOR_LAYOUT } else if event_handler_command_mode_active { - 1 // Normal command line + 1 } else { 0 // Neither is active }; if command_palette_area_height > 0 { - // This constraint is for the command_render_area (palette or command line) bottom_area_constraints.push(Constraint::Length(command_palette_area_height)); } - let mut main_layout_constraints = vec![Constraint::Min(1)]; // Main content area + let mut main_layout_constraints = vec![Constraint::Min(1)]; if app_state.ui.show_buffer_list { - main_layout_constraints.insert(0, Constraint::Length(1)); // Buffer list at the top + main_layout_constraints.insert(0, Constraint::Length(1)); } - // bottom_area_constraints already contains status_line and potentially command_palette_area main_layout_constraints.extend(bottom_area_constraints); @@ -103,12 +99,9 @@ pub fn render_ui( chunk_idx += 1; let command_render_area = if command_palette_area_height > 0 { - // Check if there's a chunk available for command_render_area if root_chunks.len() > chunk_idx { Some(root_chunks[chunk_idx]) } else { - // This case should ideally not happen if constraints are set up correctly - // but as a fallback, don't try to render if no area. None } } else { @@ -116,13 +109,12 @@ pub fn render_ui( }; - // --- Render main content views --- if app_state.ui.show_intro { render_intro(f, intro_state, main_content_area, theme); } else if app_state.ui.show_register { render_register( f, main_content_area, theme, register_state, app_state, - register_state.current_field() < 4, // Assuming 4 fields before buttons + register_state.current_field() < 4, highlight_state, ); } else if app_state.ui.show_add_table { @@ -139,7 +131,7 @@ pub fn render_ui( } else if app_state.ui.show_login { render_login( f, main_content_area, theme, login_state, app_state, - login_state.current_field() < 2, // Assuming 2 fields before buttons + login_state.current_field() < 2, highlight_state, ); } else if app_state.ui.show_admin { @@ -157,15 +149,14 @@ pub fn render_ui( ); } let available_width = form_actual_area.width; - // Center the form if space allows, otherwise use available width let form_render_area = if available_width >= 80 { Layout::default().direction(Direction::Horizontal) .constraints([Constraint::Min(0), Constraint::Length(80), Constraint::Min(0)]) - .split(form_actual_area)[1] // Use form_actual_area here + .split(form_actual_area)[1] } else { Layout::default().direction(Direction::Horizontal) .constraints([Constraint::Min(0), Constraint::Length(available_width), Constraint::Min(0)]) - .split(form_actual_area)[1] // Use form_actual_area here + .split(form_actual_area)[1] }; let fields_vec: Vec<&str> = form_state.fields.iter().map(AsRef::as_ref).collect(); let values_vec: Vec<&String> = form_state.values.iter().collect(); @@ -175,16 +166,13 @@ pub fn render_ui( total_count, current_position, ); } - // --- End main content views --- if let Some(area) = buffer_list_area { - // No need to check app_state.ui.show_buffer_list again, area is Some only if true render_buffer_list(f, area, theme, buffer_state, app_state); } render_status_line(f, status_line_area, current_dir, theme, is_event_handler_edit_mode, current_fps); - // Render command line or find_file_palette if let Some(palette_or_command_area) = command_render_area { // Use the calculated area if navigation_state.active { find_file_palette::render_find_file_palette( diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index e20cc61..f0e7298 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -1,4 +1,4 @@ -// src/ui/handlers/ui.rs +// client/src/ui/handlers/ui.rs use crate::config::binds::config::Config; use crate::config::colors::themes::Theme; @@ -23,16 +23,14 @@ use crate::tui::terminal::{EventReader, TerminalCore}; use crate::ui::handlers::render::render_ui; use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::register::RegisterResult; -// Removed: use crate::tui::functions::common::add_table::handle_save_table_action; -// Removed: use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; -use crate::ui::handlers::context::DialogPurpose; // UiContext removed if not used directly +use crate::ui::handlers::context::DialogPurpose; use crate::tui::functions::common::login; use crate::tui::functions::common::register; use std::time::Instant; use anyhow::{Context, Result}; use crossterm::cursor::SetCursorStyle; use crossterm::event as crossterm_event; -use tracing::{error, info, warn}; // Added warn +use tracing::{error, info, warn}; use tokio::sync::mpsc; @@ -43,14 +41,14 @@ pub async fn run_ui() -> Result<()> { let mut grpc_client = GrpcClient::new().await?; let mut command_handler = CommandHandler::new(); - // --- Channel for Login Results --- + let (login_result_sender, mut login_result_receiver) = mpsc::channel::(1); let (register_result_sender, mut register_result_receiver) = mpsc::channel::(1); let (save_table_result_sender, mut save_table_result_receiver) = mpsc::channel::>(1); - let (save_logic_result_sender, _save_logic_result_receiver) = // Prefixed and removed mut + let (save_logic_result_sender, _save_logic_result_receiver) = mpsc::channel::>(1); let mut event_handler = EventHandler::new( @@ -69,7 +67,7 @@ pub async fn run_ui() -> Result<()> { let mut buffer_state = BufferState::default(); let mut app_state = AppState::new().context("Failed to create initial app state")?; - // --- DATA: Load auth data from file at startup --- + let mut auto_logged_in = false; match load_auth_data() { Ok(Some(stored_data)) => { @@ -87,7 +85,7 @@ pub async fn run_ui() -> Result<()> { error!("Failed to load auth data: {}", e); } } - // --- END DATA --- + let column_names = UiService::initialize_app_state(&mut grpc_client, &mut app_state) @@ -108,7 +106,7 @@ pub async fn run_ui() -> Result<()> { let mut needs_redraw = true; loop { - // --- Synchronize UI View from Active Buffer --- + if let Some(active_view) = buffer_state.get_active_view() { app_state.ui.show_intro = false; app_state.ui.show_login = false; @@ -155,12 +153,12 @@ pub async fn run_ui() -> Result<()> { AppView::Scratch => {} } } - // --- End Synchronization --- - // --- Handle Pending Table Structure Fetches --- + + if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() { if app_state.ui.show_add_logic { - // Ensure admin_state.add_logic_state matches the pending fetch + if admin_state.add_logic_state.profile_name == profile_name && admin_state.add_logic_state.selected_table_name.as_deref() == Some(table_name.as_str()) { @@ -168,7 +166,7 @@ pub async fn run_ui() -> Result<()> { let fetch_message = UiService::initialize_add_logic_table_data( &mut grpc_client, &mut admin_state.add_logic_state, - &app_state.profile_tree, // Pass the profile tree + &app_state.profile_tree, ).await.unwrap_or_else(|e| { error!("Error initializing add_logic_table_data: {}", e); format!("Error fetching table structure: {}", e) @@ -196,7 +194,7 @@ pub async fn run_ui() -> Result<()> { } } - // --- 3. Draw UI --- + if needs_redraw { terminal.draw(|f| { render_ui( @@ -215,7 +213,7 @@ pub async fn run_ui() -> Result<()> { event_handler.command_mode, &event_handler.command_message, &event_handler.navigation_state, - // General app state + app_state.total_count, app_state.current_position, &app_state.current_dir, @@ -226,7 +224,7 @@ pub async fn run_ui() -> Result<()> { needs_redraw = false; } - // --- Handle Pending Column Autocomplete for Table Selection --- + if let Some(table_name) = admin_state.add_logic_state.script_editor_awaiting_column_autocomplete.clone() { if app_state.ui.show_add_logic { let profile_name = admin_state.add_logic_state.profile_name.clone(); @@ -249,7 +247,7 @@ pub async fn run_ui() -> Result<()> { } } - // --- Cursor Visibility Logic --- + let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &admin_state); match current_mode { AppMode::Edit => { terminal.show_cursor()?; } @@ -265,7 +263,7 @@ pub async fn run_ui() -> Result<()> { } AppMode::Command => { terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?; terminal.show_cursor().context("Failed to show cursor in Command mode")?; } } - // --- End Cursor Visibility Logic --- + let total_count = app_state.total_count; let mut current_position = app_state.current_position; @@ -274,7 +272,7 @@ pub async fn run_ui() -> Result<()> { needs_redraw = true; } - // --- 1. Handle Terminal Events --- + let mut event_outcome_result = Ok(EventOutcome::Ok(String::new())); let mut event_processed = false; if crossterm_event::poll(std::time::Duration::from_millis(1))? { @@ -304,32 +302,32 @@ pub async fn run_ui() -> Result<()> { } app_state.current_position = current_position; - // --- Check for Login Results from Channel --- + match login_result_receiver.try_recv() { Ok(result) => { if login::handle_login_result(result, &mut app_state, &mut auth_state, &mut login_state) { needs_redraw = true; } } - Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ } + Err(mpsc::error::TryRecvError::Empty) => {} Err(mpsc::error::TryRecvError::Disconnected) => { error!("Login result channel disconnected unexpectedly."); } } - // --- Check for Register Results from Channel --- + match register_result_receiver.try_recv() { Ok(result) => { if register::handle_registration_result(result, &mut app_state, &mut register_state) { needs_redraw = true; } } - Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ } + Err(mpsc::error::TryRecvError::Empty) => {} Err(mpsc::error::TryRecvError::Disconnected) => { error!("Register result channel disconnected unexpectedly."); } } - // --- Check for Save Table Results --- + match save_table_result_receiver.try_recv() { Ok(result) => { app_state.hide_dialog(); @@ -355,13 +353,11 @@ pub async fn run_ui() -> Result<()> { } } - // --- Centralized Consequence Handling --- + let mut should_exit = false; match event_outcome_result { Ok(outcome) => match outcome { - EventOutcome::Ok(_message) => { - // Message is often set directly in event_handler.command_message - } + EventOutcome::Ok(_message) => {} EventOutcome::Exit(message) => { event_handler.command_message = message; should_exit = true; @@ -380,19 +376,17 @@ pub async fn run_ui() -> Result<()> { format!("Error handling save outcome: {}", e); } } - EventOutcome::ButtonSelected { context: _, index: _ } => { - // Handled within event_handler or specific navigation modules - } + EventOutcome::ButtonSelected { context: _, index: _ } => {} }, Err(e) => { event_handler.command_message = format!("Error: {}", e); } } - // --- End Consequence Handling --- - // --- Position Change Handling --- + + let position_changed = app_state.current_position != position_before_event; - let current_total_count = app_state.total_count; // Use current total_count + let current_total_count = app_state.total_count; let mut position_logic_needs_redraw = false; if app_state.ui.show_form { @@ -430,13 +424,13 @@ pub async fn run_ui() -> Result<()> { if !load_message.starts_with("Loaded entry") || event_handler.command_message.is_empty() { event_handler.command_message = load_message; } - } else { // current_position is 0 or invalid + } else { app_state.current_position = 1.min(current_total_count + 1); - if app_state.current_position > current_total_count { // Handles empty db case + if app_state.current_position > current_total_count { form_state.reset_to_empty(); form_state.current_field = 0; } - // If db is not empty, this will trigger load in next iteration if position changed to 1 + } } else if !position_changed && !event_handler.is_edit_mode { let current_input = form_state.get_current_input(); @@ -460,18 +454,18 @@ pub async fn run_ui() -> Result<()> { if position_logic_needs_redraw { needs_redraw = true; } - // --- End Position Change Handling --- + if should_exit { return Ok(()); } - // --- FPS Calculation --- + let now = Instant::now(); let frame_duration = now.duration_since(last_frame_time); last_frame_time = now; - if frame_duration.as_secs_f64() > 1e-6 { // Avoid division by zero + if frame_duration.as_secs_f64() > 1e-6 { current_fps = 1.0 / frame_duration.as_secs_f64(); } - } // End main loop + } }