280 lines
12 KiB
Rust
280 lines
12 KiB
Rust
// src/modes/canvas/edit.rs
|
|
|
|
use crate::config::binds::config::Config;
|
|
use crate::services::grpc_client::GrpcClient;
|
|
use crate::state::pages::{auth::{AuthState, RegisterState}};
|
|
use crate::state::canvas_state::CanvasState;
|
|
use crate::state::pages::form::FormState;
|
|
use crate::functions::modes::edit::{auth_e, form_e};
|
|
use crate::modes::handlers::event::EventOutcome;
|
|
use crate::state::state::AppState;
|
|
use crossterm::event::{KeyCode, KeyEvent};
|
|
|
|
pub async fn handle_edit_event(
|
|
key: KeyEvent,
|
|
config: &Config,
|
|
form_state: &mut FormState,
|
|
auth_state: &mut AuthState,
|
|
register_state: &mut RegisterState,
|
|
ideal_cursor_column: &mut usize,
|
|
command_message: &mut String,
|
|
current_position: &mut u64,
|
|
total_count: u64,
|
|
grpc_client: &mut GrpcClient,
|
|
app_state: &AppState,
|
|
) -> Result<String, Box<dyn std::error::Error>> {
|
|
|
|
// Global command mode check
|
|
if let Some("enter_command_mode") = config.get_action_for_key_in_mode(
|
|
&config.keybindings.global,
|
|
key.code,
|
|
key.modifiers
|
|
) {
|
|
*command_message = "Switching to Command Mode...".to_string();
|
|
return Ok(command_message.clone());
|
|
}
|
|
|
|
// Common actions (save/revert)
|
|
if let Some(action) = config.get_action_for_key_in_mode(
|
|
&config.keybindings.common,
|
|
key.code,
|
|
key.modifiers
|
|
) {
|
|
if matches!(action, "save" | "revert") {
|
|
let message = if app_state.ui.show_login {
|
|
auth_e::execute_common_action(
|
|
action,
|
|
auth_state, // Concrete AuthState
|
|
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 {
|
|
form_e::execute_common_action(
|
|
action,
|
|
form_state, // Concrete FormState
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
.map(|outcome| match outcome {
|
|
EventOutcome::Ok(msg) => msg,
|
|
EventOutcome::Exit(msg) => format!("Exit requested: {}", msg),
|
|
EventOutcome::DataSaved(save_outcome, msg) => format!("Data saved ({:?}): {}", save_outcome, msg),
|
|
EventOutcome::ButtonSelected { context, index } => {
|
|
"Unexpected action in edit mode".to_string()
|
|
}
|
|
})
|
|
}?;
|
|
return Ok(message);
|
|
}
|
|
}
|
|
|
|
// Edit-specific actions
|
|
if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) {
|
|
// --- Autocomplete Dropdown Interaction Handling (PRIORITY) ---
|
|
if app_state.ui.show_register && register_state.current_field() == 4 && register_state.show_role_suggestions {
|
|
match action {
|
|
"suggestion_down" => {
|
|
let max_index = register_state.role_suggestions.len().saturating_sub(1);
|
|
let current_index = register_state.selected_suggestion_index.unwrap_or(0);
|
|
register_state.selected_suggestion_index = Some(if current_index >= max_index { 0 } else { current_index + 1 });
|
|
return Ok("Suggestion changed".to_string());
|
|
}
|
|
"suggestion_up" => {
|
|
let max_index = register_state.role_suggestions.len().saturating_sub(1);
|
|
let current_index = register_state.selected_suggestion_index.unwrap_or(0);
|
|
register_state.selected_suggestion_index = Some(if current_index == 0 { max_index } else { current_index.saturating_sub(1) });
|
|
return Ok("Suggestion changed".to_string());
|
|
}
|
|
"select_suggestion" => {
|
|
if let Some(selected_index) = register_state.selected_suggestion_index {
|
|
if let Some(selected_role) = register_state.role_suggestions.get(selected_index) {
|
|
register_state.role = selected_role.clone();
|
|
// Hide dropdown after selection
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
register_state.role_suggestions.clear();
|
|
// Move cursor to end of selected role
|
|
let new_cursor_pos = register_state.role.len();
|
|
register_state.set_current_cursor_pos(new_cursor_pos);
|
|
*ideal_cursor_column = new_cursor_pos;
|
|
return Ok(format!("Selected role: {}", register_state.role));
|
|
}
|
|
}
|
|
return Ok("No suggestion selected".to_string());
|
|
}
|
|
"hide_suggestions" => {
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
return Ok("Suggestions hidden".to_string());
|
|
}
|
|
// Allow field navigation to hide suggestions
|
|
"next_field" | "prev_field" => {
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
// Fall through to execute the navigation action below
|
|
}
|
|
_ => {} // Other edit actions might be ignored while dropdown is active
|
|
}
|
|
}
|
|
// --- End Autocomplete Interaction Handling ---
|
|
|
|
|
|
// --- Autocomplete Handling for Role Field ---
|
|
if app_state.ui.show_register && register_state.current_field() == 4 {
|
|
match action {
|
|
"suggestion_down" if register_state.show_role_suggestions => {
|
|
let max_index = register_state.role_suggestions.len() - 1;
|
|
let current_index = register_state.selected_suggestion_index.unwrap_or(0);
|
|
register_state.selected_suggestion_index = Some(if current_index >= max_index { 0 } else { current_index + 1 });
|
|
return Ok("Suggestion changed".to_string());
|
|
}
|
|
"suggestion_up" if register_state.show_role_suggestions => {
|
|
let max_index = register_state.role_suggestions.len() - 1;
|
|
let current_index = register_state.selected_suggestion_index.unwrap_or(0);
|
|
register_state.selected_suggestion_index = Some(if current_index == 0 { max_index } else { current_index - 1 });
|
|
return Ok("Suggestion changed".to_string());
|
|
}
|
|
"select_suggestion" if register_state.show_role_suggestions => {
|
|
if let Some(selected_index) = register_state.selected_suggestion_index {
|
|
if let Some(selected_role) = register_state.role_suggestions.get(selected_index) {
|
|
register_state.role = selected_role.clone();
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
register_state.role_suggestions.clear();
|
|
// Optionally move to next field or exit edit mode here
|
|
return Ok(format!("Selected role: {}", register_state.role));
|
|
}
|
|
}
|
|
return Ok("No suggestion selected".to_string());
|
|
}
|
|
"hide_suggestions" => {
|
|
register_state.show_role_suggestions = false;
|
|
register_state.selected_suggestion_index = None;
|
|
return Ok("Suggestions hidden".to_string());
|
|
}
|
|
// Let other edit actions (like move_*) fall through for the role field if desired
|
|
// Or explicitly handle them here if they should behave differently
|
|
_ => {}
|
|
}
|
|
}
|
|
// --- End Autocomplete Handling ---
|
|
|
|
return if app_state.ui.show_login {
|
|
auth_e::execute_edit_action(
|
|
action,
|
|
key,
|
|
auth_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
} else if app_state.ui.show_register {
|
|
auth_e::execute_edit_action(
|
|
action,
|
|
key,
|
|
register_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
} else {
|
|
form_e::execute_edit_action(
|
|
action,
|
|
key,
|
|
form_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
};
|
|
}
|
|
|
|
// Character insertion
|
|
if let KeyCode::Char(_) = key.code {
|
|
// --- Autocomplete Trigger on Char Insert ---
|
|
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
|
|
let result = // Store result before potential update
|
|
// --- End Autocomplete Trigger ---
|
|
|
|
return if app_state.ui.show_login {
|
|
auth_e::execute_edit_action(
|
|
"insert_char",
|
|
key,
|
|
auth_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
} else if app_state.ui.show_register {
|
|
auth_e::execute_edit_action(
|
|
"insert_char",
|
|
key,
|
|
register_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
} else {
|
|
form_e::execute_edit_action(
|
|
"insert_char",
|
|
key,
|
|
form_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
};
|
|
|
|
// After character insertion/deletion, update suggestions if it was the role field
|
|
if is_role_field {
|
|
register_state.update_role_suggestions();
|
|
}
|
|
return result; // Return the result from execute_edit_action
|
|
}
|
|
|
|
// Handle Backspace/Delete for Autocomplete Trigger
|
|
if matches!(key.code, KeyCode::Backspace | KeyCode::Delete) {
|
|
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
|
|
let action_str = if key.code == KeyCode::Backspace { "backspace" } else { "delete_char" };
|
|
|
|
// Execute the action first
|
|
let result = if app_state.ui.show_register {
|
|
auth_e::execute_edit_action(
|
|
action_str,
|
|
key,
|
|
register_state,
|
|
ideal_cursor_column,
|
|
grpc_client,
|
|
current_position,
|
|
total_count
|
|
).await
|
|
} else {
|
|
// Handle for login/form if needed, assuming auth_e covers RegisterState
|
|
Ok("Action not applicable here".to_string()) // Placeholder
|
|
}?;
|
|
|
|
if is_role_field {
|
|
register_state.update_role_suggestions();
|
|
}
|
|
return Ok(result);
|
|
}
|
|
|
|
Ok(command_message.clone())
|
|
}
|