code cleanup
This commit is contained in:
@@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,4 +21,3 @@ pub enum DialogPurpose {
|
|||||||
// TODO in the future:
|
// TODO in the future:
|
||||||
// ConfirmQuit,
|
// ConfirmQuit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user