253 lines
14 KiB
Rust
253 lines
14 KiB
Rust
// src/modes/canvas/edit.rs
|
|
use crate::config::binds::config::Config;
|
|
use crate::services::grpc_client::GrpcClient;
|
|
use crate::state::pages::{
|
|
auth::{LoginState, RegisterState},
|
|
canvas_state::CanvasState,
|
|
};
|
|
use crate::state::pages::form::FormState; // <<< ADD THIS LINE
|
|
// AddLogicState is already imported
|
|
// AddTableState is already imported
|
|
use crate::state::pages::admin::AdminState;
|
|
use crate::modes::handlers::event::EventOutcome;
|
|
use crate::functions::modes::edit::{add_logic_e, auth_e, form_e, add_table_e};
|
|
use crate::state::app::state::AppState;
|
|
use anyhow::Result;
|
|
use crossterm::event::KeyEvent; // Removed KeyCode, KeyModifiers as they were unused
|
|
use tracing::debug;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum EditEventOutcome {
|
|
Message(String),
|
|
ExitEditMode,
|
|
}
|
|
|
|
pub async fn handle_edit_event(
|
|
key: KeyEvent,
|
|
config: &Config,
|
|
form_state: &mut FormState, // Now FormState is in scope
|
|
login_state: &mut LoginState,
|
|
register_state: &mut RegisterState,
|
|
admin_state: &mut AdminState,
|
|
ideal_cursor_column: &mut usize,
|
|
current_position: &mut u64,
|
|
total_count: u64,
|
|
grpc_client: &mut GrpcClient,
|
|
app_state: &AppState,
|
|
) -> Result<EditEventOutcome> {
|
|
// --- Global command mode check ---
|
|
if let Some("enter_command_mode") = config.get_action_for_key_in_mode(
|
|
&config.keybindings.global, // Assuming command mode can be entered globally
|
|
key.code,
|
|
key.modifiers,
|
|
) {
|
|
// This check might be redundant if EventHandler already prevents entering Edit mode
|
|
// when command_mode is true. However, it's a safeguard.
|
|
return Ok(EditEventOutcome::Message(
|
|
"Cannot enter command mode from edit mode here.".to_string(),
|
|
));
|
|
}
|
|
|
|
// --- Common actions (save, revert) ---
|
|
if let Some(action) = config.get_action_for_key_in_mode(
|
|
&config.keybindings.common,
|
|
key.code,
|
|
key.modifiers,
|
|
).as_deref() {
|
|
if matches!(action, "save" | "revert") {
|
|
let message_string: String = if app_state.ui.show_login {
|
|
auth_e::execute_common_action(action, login_state, grpc_client, current_position, total_count).await?
|
|
} else if app_state.ui.show_register {
|
|
auth_e::execute_common_action(action, register_state, grpc_client, current_position, total_count).await?
|
|
} else if app_state.ui.show_add_table {
|
|
// TODO: Implement common actions for AddTable if needed
|
|
format!("Action '{}' not implemented for Add Table in edit mode.", action)
|
|
} else if app_state.ui.show_add_logic {
|
|
// TODO: Implement common actions for AddLogic if needed
|
|
format!("Action '{}' not implemented for Add Logic in edit mode.", action)
|
|
} else { // Assuming Form view
|
|
let outcome = form_e::execute_common_action(action, form_state, grpc_client, current_position, total_count).await?;
|
|
match outcome {
|
|
EventOutcome::Ok(msg) | EventOutcome::DataSaved(_, msg) => msg,
|
|
_ => format!("Unexpected outcome from common action: {:?}", outcome),
|
|
}
|
|
};
|
|
return Ok(EditEventOutcome::Message(message_string));
|
|
}
|
|
}
|
|
|
|
// --- Edit-specific actions ---
|
|
if let Some(action_str) = config.get_edit_action_for_key(key.code, key.modifiers).as_deref() {
|
|
// --- Handle "enter_decider" (Enter key) ---
|
|
if action_str == "enter_decider" {
|
|
let effective_action = if app_state.ui.show_register
|
|
&& register_state.in_suggestion_mode
|
|
&& register_state.current_field() == 4 { // Role field
|
|
"select_suggestion"
|
|
} else if app_state.ui.show_add_logic
|
|
&& admin_state.add_logic_state.in_target_column_suggestion_mode
|
|
&& admin_state.add_logic_state.current_field() == 1 { // Target Column field
|
|
"select_suggestion"
|
|
} else {
|
|
"next_field" // Default action for Enter
|
|
};
|
|
|
|
let msg = if app_state.ui.show_login {
|
|
auth_e::execute_edit_action(effective_action, key, login_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_table {
|
|
add_table_e::execute_edit_action(effective_action, key, &mut admin_state.add_table_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_logic {
|
|
add_logic_e::execute_edit_action(effective_action, key, &mut admin_state.add_logic_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_register {
|
|
auth_e::execute_edit_action(effective_action, key, register_state, ideal_cursor_column).await?
|
|
} else { // Form view
|
|
form_e::execute_edit_action(effective_action, key, form_state, ideal_cursor_column).await?
|
|
};
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
}
|
|
|
|
// --- Handle "exit" (Escape key) ---
|
|
if action_str == "exit" {
|
|
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
|
let msg = auth_e::execute_edit_action("exit_suggestion_mode", key, register_state, ideal_cursor_column).await?;
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
} else if app_state.ui.show_add_logic && admin_state.add_logic_state.in_target_column_suggestion_mode {
|
|
admin_state.add_logic_state.in_target_column_suggestion_mode = false;
|
|
admin_state.add_logic_state.show_target_column_suggestions = false;
|
|
admin_state.add_logic_state.selected_target_column_suggestion_index = None;
|
|
return Ok(EditEventOutcome::Message("Exited column suggestions".to_string()));
|
|
} else {
|
|
return Ok(EditEventOutcome::ExitEditMode);
|
|
}
|
|
}
|
|
|
|
// --- Autocomplete for AddLogicState Target Column ---
|
|
if app_state.ui.show_add_logic && admin_state.add_logic_state.current_field() == 1 { // Target Column field
|
|
if action_str == "suggestion_down" { // "Tab" is mapped to suggestion_down
|
|
if !admin_state.add_logic_state.in_target_column_suggestion_mode {
|
|
// Attempt to open suggestions
|
|
if let Some(profile_name) = admin_state.add_logic_state.profile_name.clone().into() {
|
|
if let Some(table_name) = admin_state.add_logic_state.selected_table_name.clone() {
|
|
debug!("Fetching table structure for autocomplete: Profile='{}', Table='{}'", profile_name, table_name);
|
|
match grpc_client.get_table_structure(profile_name, table_name).await {
|
|
Ok(ts_response) => {
|
|
admin_state.add_logic_state.table_columns_for_suggestions =
|
|
ts_response.columns.into_iter().map(|c| c.name).collect();
|
|
admin_state.add_logic_state.update_target_column_suggestions();
|
|
if !admin_state.add_logic_state.target_column_suggestions.is_empty() {
|
|
admin_state.add_logic_state.in_target_column_suggestion_mode = true;
|
|
// update_target_column_suggestions handles initial selection
|
|
return Ok(EditEventOutcome::Message("Column suggestions shown".to_string()));
|
|
} else {
|
|
return Ok(EditEventOutcome::Message("No column suggestions for current input".to_string()));
|
|
}
|
|
}
|
|
Err(e) => {
|
|
debug!("Error fetching table structure: {}", e);
|
|
admin_state.add_logic_state.table_columns_for_suggestions.clear(); // Clear old data on error
|
|
admin_state.add_logic_state.update_target_column_suggestions();
|
|
return Ok(EditEventOutcome::Message(format!("Error fetching columns: {}", e)));
|
|
}
|
|
}
|
|
} else {
|
|
return Ok(EditEventOutcome::Message("No table selected for column suggestions".to_string()));
|
|
}
|
|
} else { // Should not happen if AddLogic is properly initialized
|
|
return Ok(EditEventOutcome::Message("Profile name missing for column suggestions".to_string()));
|
|
}
|
|
} else { // Already in suggestion mode, navigate down
|
|
let msg = add_logic_e::execute_edit_action(action_str, key, &mut admin_state.add_logic_state, ideal_cursor_column).await?;
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
}
|
|
} else if admin_state.add_logic_state.in_target_column_suggestion_mode && action_str == "suggestion_up" {
|
|
let msg = add_logic_e::execute_edit_action(action_str, key, &mut admin_state.add_logic_state, ideal_cursor_column).await?;
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
}
|
|
}
|
|
|
|
// --- Autocomplete for RegisterState Role Field ---
|
|
if app_state.ui.show_register && register_state.current_field() == 4 { // Role field
|
|
if !register_state.in_suggestion_mode && action_str == "suggestion_down" { // Tab
|
|
register_state.update_role_suggestions();
|
|
if !register_state.role_suggestions.is_empty() {
|
|
register_state.in_suggestion_mode = true;
|
|
// update_role_suggestions should handle initial selection
|
|
return Ok(EditEventOutcome::Message("Role suggestions shown".to_string()));
|
|
} else {
|
|
// If Tab doesn't open suggestions, it might fall through to "next_field"
|
|
// or you might want specific behavior. For now, let it fall through.
|
|
}
|
|
}
|
|
if register_state.in_suggestion_mode && matches!(action_str, "suggestion_down" | "suggestion_up") {
|
|
let msg = auth_e::execute_edit_action(action_str, key, register_state, ideal_cursor_column).await?;
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
}
|
|
}
|
|
|
|
// --- Dispatch other edit actions ---
|
|
let msg = if app_state.ui.show_login {
|
|
auth_e::execute_edit_action(action_str, key, login_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_table {
|
|
add_table_e::execute_edit_action(action_str, key, &mut admin_state.add_table_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_logic {
|
|
// If not a suggestion action handled above for AddLogic
|
|
if !(admin_state.add_logic_state.in_target_column_suggestion_mode && matches!(action_str, "suggestion_down" | "suggestion_up")) {
|
|
add_logic_e::execute_edit_action(action_str, key, &mut admin_state.add_logic_state, ideal_cursor_column).await?
|
|
} else { String::new() /* Already handled */ }
|
|
} else if app_state.ui.show_register {
|
|
if !(register_state.in_suggestion_mode && matches!(action_str, "suggestion_down" | "suggestion_up")) {
|
|
auth_e::execute_edit_action(action_str, key, register_state, ideal_cursor_column).await?
|
|
} else { String::new() /* Already handled */ }
|
|
} else { // Form view
|
|
form_e::execute_edit_action(action_str, key, form_state, ideal_cursor_column).await?
|
|
};
|
|
return Ok(EditEventOutcome::Message(msg));
|
|
}
|
|
|
|
// --- Character insertion ---
|
|
// If character insertion happens while in suggestion mode, exit suggestion mode first.
|
|
let mut exited_suggestion_mode_for_typing = false;
|
|
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
|
register_state.in_suggestion_mode = false;
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
exited_suggestion_mode_for_typing = true;
|
|
}
|
|
if app_state.ui.show_add_logic && admin_state.add_logic_state.in_target_column_suggestion_mode {
|
|
admin_state.add_logic_state.in_target_column_suggestion_mode = false;
|
|
admin_state.add_logic_state.show_target_column_suggestions = false;
|
|
admin_state.add_logic_state.selected_target_column_suggestion_index = None;
|
|
exited_suggestion_mode_for_typing = true;
|
|
}
|
|
|
|
let mut char_insert_msg = if app_state.ui.show_login {
|
|
auth_e::execute_edit_action("insert_char", key, login_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_table {
|
|
add_table_e::execute_edit_action("insert_char", key, &mut admin_state.add_table_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_add_logic {
|
|
add_logic_e::execute_edit_action("insert_char", key, &mut admin_state.add_logic_state, ideal_cursor_column).await?
|
|
} else if app_state.ui.show_register {
|
|
auth_e::execute_edit_action("insert_char", key, register_state, ideal_cursor_column).await?
|
|
} else { // Form view
|
|
form_e::execute_edit_action("insert_char", key, form_state, ideal_cursor_column).await?
|
|
};
|
|
|
|
// After character insertion, update suggestions if applicable
|
|
if app_state.ui.show_register && register_state.current_field() == 4 {
|
|
register_state.update_role_suggestions();
|
|
// If we just exited suggestion mode by typing, don't immediately show them again unless Tab is pressed.
|
|
// However, update_role_suggestions will set show_role_suggestions if matches are found.
|
|
// This is fine, as the render logic checks in_suggestion_mode.
|
|
}
|
|
if app_state.ui.show_add_logic && admin_state.add_logic_state.current_field() == 1 {
|
|
admin_state.add_logic_state.update_target_column_suggestions();
|
|
}
|
|
|
|
if exited_suggestion_mode_for_typing && char_insert_msg.is_empty() {
|
|
char_insert_msg = "Suggestions hidden".to_string();
|
|
}
|
|
|
|
|
|
Ok(EditEventOutcome::Message(char_insert_msg))
|
|
}
|