code cleanup

This commit is contained in:
filipriec
2025-05-31 23:02:09 +02:00
parent ea88c2686d
commit 6e2fc5349b
5 changed files with 316 additions and 214 deletions

View File

@@ -1,52 +1,50 @@
// src/modes/handlers/event.rs // 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::config::binds::config::Config;
use crate::ui::handlers::rat_state::UiStateHandler; use crate::config::binds::key_sequences::KeySequenceTracker;
use crate::ui::handlers::context::UiContext;
use crate::functions::common::buffer; use crate::functions::common::buffer;
use anyhow::Result; use crate::functions::modes::navigation::add_logic_nav;
use crate::tui::{ use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender;
terminal::core::TerminalCore, use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender;
functions::{ use crate::functions::modes::navigation::{add_table_nav, admin_nav};
common::{form::SaveOutcome, login, register}, use crate::modes::general::command_navigation::{
}, handle_command_navigation_event, NavigationState, TableDependencyGraph,
{intro, admin},
}; };
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::{ use crate::state::{
app::{ app::{
buffer::{AppView, BufferState},
highlight::HighlightState, highlight::HighlightState,
state::AppState, state::AppState,
buffer::{AppView, BufferState},
}, },
pages::{ pages::{
auth::{AuthState, LoginState, RegisterState},
admin::AdminState, admin::AdminState,
auth::{AuthState, LoginState, RegisterState},
canvas_state::CanvasState, canvas_state::CanvasState,
form::FormState, form::FormState,
intro::IntroState, 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::login::LoginResult;
use crate::tui::functions::common::register::RegisterResult; use crate::tui::functions::common::register::RegisterResult;
use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; use crate::tui::{
use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender; functions::common::{form::SaveOutcome, login, register},
use crate::functions::modes::navigation::add_logic_nav; 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::KeyCode;
use crossterm::event::{Event, KeyEvent};
use tokio::sync::mpsc;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventOutcome { pub enum EventOutcome {
@@ -139,12 +137,10 @@ impl EventHandler {
// Handle active command navigation first // Handle active command navigation first
if current_mode == AppMode::General && self.navigation_state.active { if current_mode == AppMode::General && self.navigation_state.active {
if let Event::Key(key_event) = event { if let Event::Key(key_event) = event {
let outcome = handle_command_navigation_event( let outcome =
&mut self.navigation_state, handle_command_navigation_event(&mut self.navigation_state, key_event, config)
key_event, .await?;
config,
).await?;
if !self.navigation_state.active { if !self.navigation_state.active {
self.command_message = outcome.get_message_if_ok(); self.command_message = outcome.get_message_if_ok();
current_mode = ModeManager::derive_mode(app_state, self, admin_state); current_mode = ModeManager::derive_mode(app_state, self, admin_state);
@@ -160,14 +156,23 @@ impl EventHandler {
let current_view = { let current_view = {
let ui = &app_state.ui; let ui = &app_state.ui;
if ui.show_intro { AppView::Intro } if ui.show_intro {
else if ui.show_login { AppView::Login } AppView::Intro
else if ui.show_register { AppView::Register } } else if ui.show_login {
else if ui.show_admin { AppView::Admin } AppView::Login
else if ui.show_add_logic { AppView::AddLogic } } else if ui.show_register {
else if ui.show_add_table { AppView::AddTable } AppView::Register
else if ui.show_form { AppView::Form } } else if ui.show_admin {
else { AppView::Scratch } 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); buffer_state.update_history(current_view);
@@ -175,11 +180,18 @@ impl EventHandler {
if let Event::Key(key_event) = event { if let Event::Key(key_event) = event {
if let Some(dialog_result) = dialog::handle_dialog_event( if let Some(dialog_result) = dialog::handle_dialog_event(
&Event::Key(key_event), &Event::Key(key_event),
config, app_state, login_state, register_state, buffer_state, admin_state, config,
).await { app_state,
login_state,
register_state,
buffer_state,
admin_state,
)
.await
{
return dialog_result; return dialog_result;
} }
} else if let Event::Resize(_,_) = event { } else if let Event::Resize(_, _) = event {
// Handle resize if needed // Handle resize if needed
} }
return Ok(EventOutcome::Ok(String::new())); return Ok(EventOutcome::Ok(String::new()));
@@ -190,17 +202,33 @@ impl EventHandler {
let modifiers = key_event.modifiers; let modifiers = key_event.modifiers;
if UiStateHandler::toggle_sidebar(&mut app_state.ui, config, key_code, 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)); return Ok(EventOutcome::Ok(message));
} }
if UiStateHandler::toggle_buffer_list(&mut app_state.ui, config, key_code, modifiers) { 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)); return Ok(EventOutcome::Ok(message));
} }
if !matches!(current_mode, AppMode::Edit | AppMode::Command) { if !matches!(current_mode, AppMode::Edit | AppMode::Command) {
if let Some(action) = config.get_action_for_key_in_mode( 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 { match action {
"next_buffer" => { "next_buffer" => {
@@ -210,12 +238,15 @@ impl EventHandler {
} }
"previous_buffer" => { "previous_buffer" => {
if buffer::switch_buffer(buffer_state, false) { 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" => { "close_buffer" => {
let current_table_name = Some("2025_customer"); 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)); return Ok(EventOutcome::Ok(message));
} }
_ => {} _ => {}
@@ -287,7 +318,8 @@ impl EventHandler {
&mut self.command_input, &mut self.command_input,
&mut self.command_message, &mut self.command_message,
&mut self.navigation_state, &mut self.navigation_state,
).await; )
.await;
match nav_outcome { match nav_outcome {
Ok(EventOutcome::ButtonSelected { context, index }) => { Ok(EventOutcome::ButtonSelected { context, index }) => {
@@ -301,24 +333,36 @@ impl EventHandler {
} }
format!("Intro Option {} selected", index) format!("Intro Option {} selected", index)
} }
UiContext::Login => { UiContext::Login => match index {
match index { 0 => login::initiate_login(
0 => { login_state,
login::initiate_login(login_state, app_state, self.auth_client.clone(), self.login_result_sender.clone()) app_state,
}, self.auth_client.clone(),
1 => login::back_to_main(login_state, app_state, buffer_state).await, self.login_result_sender.clone(),
_ => "Invalid Login Option".to_string(), ),
1 => {
login::back_to_main(login_state, app_state, buffer_state)
.await
} }
} _ => "Invalid Login Option".to_string(),
UiContext::Register => { },
match index { UiContext::Register => match index {
0 => { 0 => register::initiate_registration(
register::initiate_registration(register_state, app_state, self.auth_client.clone(), self.register_result_sender.clone()) register_state,
}, app_state,
1 => register::back_to_login(register_state, app_state, buffer_state).await, self.auth_client.clone(),
_ => "Invalid Login Option".to_string(), self.register_result_sender.clone(),
),
1 => {
register::back_to_login(
register_state,
app_state,
buffer_state,
)
.await
} }
} _ => "Invalid Login Option".to_string(),
},
UiContext::Admin => { UiContext::Admin => {
admin::handle_admin_selection(app_state, admin_state); admin::handle_admin_selection(app_state, admin_state);
format!("Admin Option {} selected", index) format!("Admin Option {} selected", index)
@@ -334,53 +378,76 @@ impl EventHandler {
} }
AppMode::ReadOnly => { 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) && ModeManager::can_enter_highlight_mode(current_mode)
{ {
let current_field_index = if app_state.ui.show_login { login_state.current_field() } let current_field_index = if app_state.ui.show_login {
else if app_state.ui.show_register { register_state.current_field() } login_state.current_field()
else { form_state.current_field() }; } else if app_state.ui.show_register {
self.highlight_state = HighlightState::Linewise { anchor_line: current_field_index }; 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(); self.command_message = "-- LINE HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} } else if config.get_read_only_action_for_key(key_code, modifiers)
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode") == Some("enter_highlight_mode")
&& ModeManager::can_enter_highlight_mode(current_mode) && ModeManager::can_enter_highlight_mode(current_mode)
{ {
let current_field_index = if app_state.ui.show_login { login_state.current_field() } let current_field_index = if app_state.ui.show_login {
else if app_state.ui.show_register { register_state.current_field() } login_state.current_field()
else { form_state.current_field() }; } else if app_state.ui.show_register {
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } register_state.current_field()
else if app_state.ui.show_register { register_state.current_cursor_pos() } } else {
else { form_state.current_cursor_pos() }; 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); let anchor = (current_field_index, current_cursor_pos);
self.highlight_state = HighlightState::Characterwise { anchor }; self.highlight_state = HighlightState::Characterwise { anchor };
self.command_message = "-- HIGHLIGHT --".to_string(); self.command_message = "-- HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} } else if config
else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_before") .get_read_only_action_for_key(key_code, modifiers)
&& ModeManager::can_enter_edit_mode(current_mode) { .as_deref()
== Some("enter_edit_mode_before")
&& ModeManager::can_enter_edit_mode(current_mode)
{
self.is_edit_mode = true; self.is_edit_mode = true;
self.edit_mode_cooldown = true; self.edit_mode_cooldown = true;
self.command_message = "Edit mode".to_string(); self.command_message = "Edit mode".to_string();
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} } else if config
else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_after") .get_read_only_action_for_key(key_code, modifiers)
&& ModeManager::can_enter_edit_mode(current_mode) { .as_deref()
let current_input = if app_state.ui.show_login || app_state.ui.show_register{ == 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() login_state.get_current_input()
} else { } else {
form_state.get_current_input() form_state.get_current_input()
}; };
let current_cursor_pos = if app_state.ui.show_login || app_state.ui.show_register{ let current_cursor_pos =
login_state.current_cursor_pos() if app_state.ui.show_login || app_state.ui.show_register {
} else { login_state.current_cursor_pos()
form_state.current_cursor_pos() } else {
}; form_state.current_cursor_pos()
};
if !current_input.is_empty() && current_cursor_pos < current_input.len() { 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); login_state.set_current_cursor_pos(current_cursor_pos + 1);
self.ideal_cursor_column = login_state.current_cursor_pos(); self.ideal_cursor_column = login_state.current_cursor_pos();
} else { } else {
@@ -394,13 +461,14 @@ impl EventHandler {
self.command_message = "Edit mode (after cursor)".to_string(); self.command_message = "Edit mode (after cursor)".to_string();
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?; terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
return Ok(EventOutcome::Ok(self.command_message.clone())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} } else if config.get_read_only_action_for_key(key_code, modifiers)
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode") == Some("enter_command_mode")
&& ModeManager::can_enter_command_mode(current_mode) { && ModeManager::can_enter_command_mode(current_mode)
self.command_mode = true; {
self.command_input.clear(); self.command_mode = true;
self.command_message.clear(); self.command_input.clear();
return Ok(EventOutcome::Ok(String::new())); self.command_message.clear();
return Ok(EventOutcome::Ok(String::new()));
} }
if let Some(action) = config.get_common_action(key_code, modifiers) { if let Some(action) = config.get_common_action(key_code, modifiers) {
@@ -418,8 +486,9 @@ impl EventHandler {
app_state, app_state,
current_position, current_position,
total_count, total_count,
).await; )
}, .await;
}
_ => {} _ => {}
} }
} }
@@ -440,28 +509,38 @@ impl EventHandler {
&mut self.command_message, &mut self.command_message,
&mut self.edit_mode_cooldown, &mut self.edit_mode_cooldown,
&mut self.ideal_cursor_column, &mut self.ideal_cursor_column,
).await?; )
.await?;
return Ok(EventOutcome::Ok(message)); return Ok(EventOutcome::Ok(message));
} }
AppMode::Highlight => { AppMode::Highlight => {
if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") { if config.get_highlight_action_for_key(key_code, modifiers)
self.highlight_state = HighlightState::Off; == Some("exit_highlight_mode")
self.command_message = "Exited highlight mode".to_string(); {
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; self.highlight_state = HighlightState::Off;
return Ok(EventOutcome::Ok(self.command_message.clone())); self.command_message = "Exited highlight mode".to_string();
} terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
else if config.get_highlight_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") { return Ok(EventOutcome::Ok(self.command_message.clone()));
if let HighlightState::Characterwise { anchor } = self.highlight_state { } else if config.get_highlight_action_for_key(key_code, modifiers)
self.highlight_state = HighlightState::Linewise { anchor_line: anchor.0 }; == Some("enter_highlight_mode_linewise")
self.command_message = "-- LINE HIGHLIGHT --".to_string(); {
return Ok(EventOutcome::Ok(self.command_message.clone())); 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())); return Ok(EventOutcome::Ok("".to_string()));
} }
let (_should_exit, message) = read_only::handle_read_only_event( 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, register_state,
&mut admin_state.add_table_state, &mut admin_state.add_table_state,
&mut admin_state.add_logic_state, &mut admin_state.add_logic_state,
@@ -493,8 +572,9 @@ impl EventHandler {
app_state, app_state,
current_position, current_position,
total_count, total_count,
).await; )
}, .await;
}
_ => {} _ => {}
} }
} }
@@ -511,30 +591,52 @@ impl EventHandler {
total_count, total_count,
grpc_client, grpc_client,
app_state, app_state,
).await; )
.await;
match edit_result { match edit_result {
Ok(edit::EditEventOutcome::ExitEditMode) => { Ok(edit::EditEventOutcome::ExitEditMode) => {
self.is_edit_mode = false; self.is_edit_mode = false;
self.edit_mode_cooldown = true; self.edit_mode_cooldown = true;
let has_changes = if app_state.ui.show_login { login_state.has_unsaved_changes() } let has_changes = if app_state.ui.show_login {
else if app_state.ui.show_register { register_state.has_unsaved_changes() } login_state.has_unsaved_changes()
else { form_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 { self.command_message = if has_changes {
"Exited edit mode (unsaved changes remain)".to_string() "Exited edit mode (unsaved changes remain)".to_string()
} else { } else {
"Read-only mode".to_string() "Read-only mode".to_string()
}; };
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
let current_input = if app_state.ui.show_login { login_state.get_current_input() } let current_input = if app_state.ui.show_login {
else if app_state.ui.show_register { register_state.get_current_input() } login_state.get_current_input()
else { form_state.get_current_input() }; } else if app_state.ui.show_register {
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } register_state.get_current_input()
else if app_state.ui.show_register { register_state.current_cursor_pos() } } else {
else { form_state.current_cursor_pos() }; form_state.get_current_input()
if !current_input.is_empty() && current_cursor_pos >= current_input.len() { };
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 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); target_state.set_current_cursor_pos(new_pos);
self.ideal_cursor_column = new_pos; self.ideal_cursor_column = new_pos;
} }
@@ -564,10 +666,21 @@ impl EventHandler {
if config.is_command_execute(key_code, modifiers) { if config.is_command_execute(key_code, modifiers) {
let outcome = command_mode::handle_command_event( let outcome = command_mode::handle_command_event(
key_event, config, app_state, login_state, register_state, form_state, key_event,
&mut self.command_input, &mut self.command_message, config,
grpc_client, command_handler, terminal, current_position, total_count, app_state,
).await?; 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.command_mode = false;
self.key_sequence_tracker.reset(); self.key_sequence_tracker.reset();
let new_mode = ModeManager::derive_mode(app_state, self, admin_state); 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 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); self.key_sequence_tracker.add_key(key_code);
let sequence = self.key_sequence_tracker.get_sequence(); 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 { if app_state.ui.show_form || app_state.ui.show_intro {
// Build table graph from profile data // 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 // Activate navigation with graph
self.navigation_state.activate_table_tree(graph); self.navigation_state.activate_table_tree(graph);
@@ -601,14 +719,17 @@ impl EventHandler {
self.key_sequence_tracker.reset(); self.key_sequence_tracker.reset();
// ModeManager will derive AppMode::General due to navigation_state.active // ModeManager will derive AppMode::General due to navigation_state.active
// app_state.update_mode(AppMode::General); // This will be handled by ModeManager // 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 { } else {
self.key_sequence_tracker.reset(); self.key_sequence_tracker.reset();
self.command_input.push('f'); self.command_input.push('f');
if sequence.len() > 1 && sequence[0] == KeyCode::Char('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())); return Ok(EventOutcome::Ok(self.command_message.clone()));
} }
} }
@@ -630,7 +751,7 @@ impl EventHandler {
return Ok(EventOutcome::Ok(String::new())); 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())); return Ok(EventOutcome::Ok("Resized".to_string()));
} }

View File

@@ -21,4 +21,3 @@ pub enum DialogPurpose {
// TODO in the future: // TODO in the future:
// ConfirmQuit, // ConfirmQuit,
} }

View File

@@ -1,4 +1,4 @@
// src/ui/handlers/rat_state.rs // client/src/ui/handlers/rat_state.rs
use crossterm::event::{KeyCode, KeyModifiers}; use crossterm::event::{KeyCode, KeyModifiers};
use crate::config::binds::config::Config; use crate::config::binds::config::Config;
use crate::state::app::state::UiState; use crate::state::app::state::UiState;

View File

@@ -1,9 +1,9 @@
// src/ui/handlers/render.rs // client/src/ui/handlers/render.rs
use crate::components::{ use crate::components::{
render_background, render_background,
render_buffer_list, render_buffer_list,
render_command_line, // For the normal command line render_command_line,
render_status_line, render_status_line,
intro::intro::render_intro, intro::intro::render_intro,
handlers::sidebar::{self, calculate_sidebar_layout}, handlers::sidebar::{self, calculate_sidebar_layout},
@@ -11,13 +11,11 @@ use crate::components::{
admin::render_add_table, admin::render_add_table,
admin::add_logic::render_add_logic, admin::add_logic::render_add_logic,
auth::{login::render_login, register::render_register}, 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 crate::config::colors::themes::Theme;
use ratatui::{ use ratatui::{
// layout::{Constraint, Direction, Layout, Rect}, // Rect might be unused if all areas are handled layout::{Constraint, Direction, Layout},
layout::{Constraint, Direction, Layout}, // Style might be unused if all styling is in components
// style::Style, // Style might be unused
Frame, Frame,
}; };
use crate::state::pages::canvas_state::CanvasState; use crate::state::pages::canvas_state::CanvasState;
@@ -48,7 +46,7 @@ pub fn render_ui(
event_handler_command_input: &str, event_handler_command_input: &str,
event_handler_command_mode_active: bool, event_handler_command_mode_active: bool,
event_handler_command_message: &str, event_handler_command_message: &str,
navigation_state: &NavigationState, // This is the correct reference navigation_state: &NavigationState,
total_count: u64, total_count: u64,
current_position: u64, current_position: u64,
current_dir: &str, current_dir: &str,
@@ -59,26 +57,24 @@ pub fn render_ui(
const PALETTE_OPTIONS_HEIGHT_FOR_LAYOUT: u16 = 15; const PALETTE_OPTIONS_HEIGHT_FOR_LAYOUT: u16 = 15;
let mut bottom_area_constraints: Vec<Constraint> = vec![Constraint::Length(1)]; // For status_line let mut bottom_area_constraints: Vec<Constraint> = vec![Constraint::Length(1)];
let command_palette_area_height = if navigation_state.active { 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 { } else if event_handler_command_mode_active {
1 // Normal command line 1
} else { } else {
0 // Neither is active 0 // Neither is active
}; };
if command_palette_area_height > 0 { 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)); 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 { 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); main_layout_constraints.extend(bottom_area_constraints);
@@ -103,12 +99,9 @@ pub fn render_ui(
chunk_idx += 1; chunk_idx += 1;
let command_render_area = if command_palette_area_height > 0 { 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 { if root_chunks.len() > chunk_idx {
Some(root_chunks[chunk_idx]) Some(root_chunks[chunk_idx])
} else { } 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 None
} }
} else { } else {
@@ -116,13 +109,12 @@ pub fn render_ui(
}; };
// --- Render main content views ---
if app_state.ui.show_intro { if app_state.ui.show_intro {
render_intro(f, intro_state, main_content_area, theme); render_intro(f, intro_state, main_content_area, theme);
} else if app_state.ui.show_register { } else if app_state.ui.show_register {
render_register( render_register(
f, main_content_area, theme, register_state, app_state, 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, highlight_state,
); );
} else if app_state.ui.show_add_table { } else if app_state.ui.show_add_table {
@@ -139,7 +131,7 @@ pub fn render_ui(
} else if app_state.ui.show_login { } else if app_state.ui.show_login {
render_login( render_login(
f, main_content_area, theme, login_state, app_state, 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, highlight_state,
); );
} else if app_state.ui.show_admin { } else if app_state.ui.show_admin {
@@ -157,15 +149,14 @@ pub fn render_ui(
); );
} }
let available_width = form_actual_area.width; 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 { let form_render_area = if available_width >= 80 {
Layout::default().direction(Direction::Horizontal) Layout::default().direction(Direction::Horizontal)
.constraints([Constraint::Min(0), Constraint::Length(80), Constraint::Min(0)]) .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 { } else {
Layout::default().direction(Direction::Horizontal) Layout::default().direction(Direction::Horizontal)
.constraints([Constraint::Min(0), Constraint::Length(available_width), Constraint::Min(0)]) .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 fields_vec: Vec<&str> = form_state.fields.iter().map(AsRef::as_ref).collect();
let values_vec: Vec<&String> = form_state.values.iter().collect(); let values_vec: Vec<&String> = form_state.values.iter().collect();
@@ -175,16 +166,13 @@ pub fn render_ui(
total_count, current_position, total_count, current_position,
); );
} }
// --- End main content views ---
if let Some(area) = buffer_list_area { 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_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_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 let Some(palette_or_command_area) = command_render_area { // Use the calculated area
if navigation_state.active { if navigation_state.active {
find_file_palette::render_find_file_palette( find_file_palette::render_find_file_palette(

View File

@@ -1,4 +1,4 @@
// src/ui/handlers/ui.rs // client/src/ui/handlers/ui.rs
use crate::config::binds::config::Config; use crate::config::binds::config::Config;
use crate::config::colors::themes::Theme; 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::ui::handlers::render::render_ui;
use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::login::LoginResult;
use crate::tui::functions::common::register::RegisterResult; use crate::tui::functions::common::register::RegisterResult;
// Removed: use crate::tui::functions::common::add_table::handle_save_table_action; use crate::ui::handlers::context::DialogPurpose;
// Removed: use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender;
use crate::ui::handlers::context::DialogPurpose; // UiContext removed if not used directly
use crate::tui::functions::common::login; use crate::tui::functions::common::login;
use crate::tui::functions::common::register; use crate::tui::functions::common::register;
use std::time::Instant; use std::time::Instant;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use crossterm::cursor::SetCursorStyle; use crossterm::cursor::SetCursorStyle;
use crossterm::event as crossterm_event; use crossterm::event as crossterm_event;
use tracing::{error, info, warn}; // Added warn use tracing::{error, info, warn};
use tokio::sync::mpsc; use tokio::sync::mpsc;
@@ -43,14 +41,14 @@ pub async fn run_ui() -> Result<()> {
let mut grpc_client = GrpcClient::new().await?; let mut grpc_client = GrpcClient::new().await?;
let mut command_handler = CommandHandler::new(); let mut command_handler = CommandHandler::new();
// --- Channel for Login Results ---
let (login_result_sender, mut login_result_receiver) = let (login_result_sender, mut login_result_receiver) =
mpsc::channel::<LoginResult>(1); mpsc::channel::<LoginResult>(1);
let (register_result_sender, mut register_result_receiver) = let (register_result_sender, mut register_result_receiver) =
mpsc::channel::<RegisterResult>(1); mpsc::channel::<RegisterResult>(1);
let (save_table_result_sender, mut save_table_result_receiver) = let (save_table_result_sender, mut save_table_result_receiver) =
mpsc::channel::<Result<String>>(1); mpsc::channel::<Result<String>>(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::<Result<String>>(1); mpsc::channel::<Result<String>>(1);
let mut event_handler = EventHandler::new( let mut event_handler = EventHandler::new(
@@ -69,7 +67,7 @@ pub async fn run_ui() -> Result<()> {
let mut buffer_state = BufferState::default(); let mut buffer_state = BufferState::default();
let mut app_state = AppState::new().context("Failed to create initial app state")?; 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; let mut auto_logged_in = false;
match load_auth_data() { match load_auth_data() {
Ok(Some(stored_data)) => { Ok(Some(stored_data)) => {
@@ -87,7 +85,7 @@ pub async fn run_ui() -> Result<()> {
error!("Failed to load auth data: {}", e); error!("Failed to load auth data: {}", e);
} }
} }
// --- END DATA ---
let column_names = let column_names =
UiService::initialize_app_state(&mut grpc_client, &mut app_state) 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; let mut needs_redraw = true;
loop { loop {
// --- Synchronize UI View from Active Buffer ---
if let Some(active_view) = buffer_state.get_active_view() { if let Some(active_view) = buffer_state.get_active_view() {
app_state.ui.show_intro = false; app_state.ui.show_intro = false;
app_state.ui.show_login = false; app_state.ui.show_login = false;
@@ -155,12 +153,12 @@ pub async fn run_ui() -> Result<()> {
AppView::Scratch => {} AppView::Scratch => {}
} }
} }
// --- End Synchronization ---
// --- Handle Pending Table Structure Fetches ---
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() { if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
if app_state.ui.show_add_logic { 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 && 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()) { 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( let fetch_message = UiService::initialize_add_logic_table_data(
&mut grpc_client, &mut grpc_client,
&mut admin_state.add_logic_state, &mut admin_state.add_logic_state,
&app_state.profile_tree, // Pass the profile tree &app_state.profile_tree,
).await.unwrap_or_else(|e| { ).await.unwrap_or_else(|e| {
error!("Error initializing add_logic_table_data: {}", e); error!("Error initializing add_logic_table_data: {}", e);
format!("Error fetching table structure: {}", e) format!("Error fetching table structure: {}", e)
@@ -196,7 +194,7 @@ pub async fn run_ui() -> Result<()> {
} }
} }
// --- 3. Draw UI ---
if needs_redraw { if needs_redraw {
terminal.draw(|f| { terminal.draw(|f| {
render_ui( render_ui(
@@ -215,7 +213,7 @@ pub async fn run_ui() -> Result<()> {
event_handler.command_mode, event_handler.command_mode,
&event_handler.command_message, &event_handler.command_message,
&event_handler.navigation_state, &event_handler.navigation_state,
// General app state
app_state.total_count, app_state.total_count,
app_state.current_position, app_state.current_position,
&app_state.current_dir, &app_state.current_dir,
@@ -226,7 +224,7 @@ pub async fn run_ui() -> Result<()> {
needs_redraw = false; 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 let Some(table_name) = admin_state.add_logic_state.script_editor_awaiting_column_autocomplete.clone() {
if app_state.ui.show_add_logic { if app_state.ui.show_add_logic {
let profile_name = admin_state.add_logic_state.profile_name.clone(); 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); let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &admin_state);
match current_mode { match current_mode {
AppMode::Edit => { terminal.show_cursor()?; } 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")?; } 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 total_count = app_state.total_count;
let mut current_position = app_state.current_position; let mut current_position = app_state.current_position;
@@ -274,7 +272,7 @@ pub async fn run_ui() -> Result<()> {
needs_redraw = true; needs_redraw = true;
} }
// --- 1. Handle Terminal Events ---
let mut event_outcome_result = Ok(EventOutcome::Ok(String::new())); let mut event_outcome_result = Ok(EventOutcome::Ok(String::new()));
let mut event_processed = false; let mut event_processed = false;
if crossterm_event::poll(std::time::Duration::from_millis(1))? { 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; app_state.current_position = current_position;
// --- Check for Login Results from Channel ---
match login_result_receiver.try_recv() { match login_result_receiver.try_recv() {
Ok(result) => { Ok(result) => {
if login::handle_login_result(result, &mut app_state, &mut auth_state, &mut login_state) { if login::handle_login_result(result, &mut app_state, &mut auth_state, &mut login_state) {
needs_redraw = true; needs_redraw = true;
} }
} }
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ } Err(mpsc::error::TryRecvError::Empty) => {}
Err(mpsc::error::TryRecvError::Disconnected) => { Err(mpsc::error::TryRecvError::Disconnected) => {
error!("Login result channel disconnected unexpectedly."); error!("Login result channel disconnected unexpectedly.");
} }
} }
// --- Check for Register Results from Channel ---
match register_result_receiver.try_recv() { match register_result_receiver.try_recv() {
Ok(result) => { Ok(result) => {
if register::handle_registration_result(result, &mut app_state, &mut register_state) { if register::handle_registration_result(result, &mut app_state, &mut register_state) {
needs_redraw = true; needs_redraw = true;
} }
} }
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ } Err(mpsc::error::TryRecvError::Empty) => {}
Err(mpsc::error::TryRecvError::Disconnected) => { Err(mpsc::error::TryRecvError::Disconnected) => {
error!("Register result channel disconnected unexpectedly."); error!("Register result channel disconnected unexpectedly.");
} }
} }
// --- Check for Save Table Results ---
match save_table_result_receiver.try_recv() { match save_table_result_receiver.try_recv() {
Ok(result) => { Ok(result) => {
app_state.hide_dialog(); app_state.hide_dialog();
@@ -355,13 +353,11 @@ pub async fn run_ui() -> Result<()> {
} }
} }
// --- Centralized Consequence Handling ---
let mut should_exit = false; let mut should_exit = false;
match event_outcome_result { match event_outcome_result {
Ok(outcome) => match outcome { Ok(outcome) => match outcome {
EventOutcome::Ok(_message) => { EventOutcome::Ok(_message) => {}
// Message is often set directly in event_handler.command_message
}
EventOutcome::Exit(message) => { EventOutcome::Exit(message) => {
event_handler.command_message = message; event_handler.command_message = message;
should_exit = true; should_exit = true;
@@ -380,19 +376,17 @@ pub async fn run_ui() -> Result<()> {
format!("Error handling save outcome: {}", e); format!("Error handling save outcome: {}", e);
} }
} }
EventOutcome::ButtonSelected { context: _, index: _ } => { EventOutcome::ButtonSelected { context: _, index: _ } => {}
// Handled within event_handler or specific navigation modules
}
}, },
Err(e) => { Err(e) => {
event_handler.command_message = format!("Error: {}", 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 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; let mut position_logic_needs_redraw = false;
if app_state.ui.show_form { 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() { if !load_message.starts_with("Loaded entry") || event_handler.command_message.is_empty() {
event_handler.command_message = load_message; event_handler.command_message = load_message;
} }
} else { // current_position is 0 or invalid } else {
app_state.current_position = 1.min(current_total_count + 1); 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.reset_to_empty();
form_state.current_field = 0; 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 { } else if !position_changed && !event_handler.is_edit_mode {
let current_input = form_state.get_current_input(); let current_input = form_state.get_current_input();
@@ -460,18 +454,18 @@ pub async fn run_ui() -> Result<()> {
if position_logic_needs_redraw { if position_logic_needs_redraw {
needs_redraw = true; needs_redraw = true;
} }
// --- End Position Change Handling ---
if should_exit { if should_exit {
return Ok(()); return Ok(());
} }
// --- FPS Calculation ---
let now = Instant::now(); let now = Instant::now();
let frame_duration = now.duration_since(last_frame_time); let frame_duration = now.duration_since(last_frame_time);
last_frame_time = now; 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(); current_fps = 1.0 / frame_duration.as_secs_f64();
} }
} // End main loop }
} }