canvas library usage instead of internal canvas on the form, others are still using canvas from state. Needed debugging because its not working yet

This commit is contained in:
Priec
2025-07-29 15:20:00 +02:00
parent f24156775a
commit db938a2c8d
12 changed files with 677 additions and 107 deletions

View File

@@ -15,8 +15,12 @@ use crate::modes::{
general::{dialog, navigation},
handlers::mode_manager::{AppMode, ModeManager},
};
use crate::state::pages::canvas_state::CanvasState as LegacyCanvasState;
use crate::services::auth::AuthClient;
use crate::services::grpc_client::GrpcClient;
use canvas::{CanvasAction, ActionDispatcher, ActionResult};
use canvas::CanvasState as LibraryCanvasState;
use super::event_helper::*;
use crate::state::{
app::{
buffer::{AppView, BufferState},
@@ -573,55 +577,106 @@ impl EventHandler {
}
AppMode::ReadOnly => {
if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") && ModeManager::can_enter_highlight_mode(current_mode) {
let current_field_index = if app_state.ui.show_login { login_state.current_field() } else if app_state.ui.show_register { register_state.current_field() } else { form_state.current_field() };
self.highlight_state = HighlightState::Linewise { anchor_line: current_field_index };
// Handle highlight mode transitions
if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise")
&& ModeManager::can_enter_highlight_mode(current_mode)
{
let current_field_index = get_current_field_for_state(
app_state,
login_state,
register_state,
form_state
);
self.highlight_state = HighlightState::Linewise {
anchor_line: current_field_index
};
self.command_message = "-- LINE HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone()));
} else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode") && ModeManager::can_enter_highlight_mode(current_mode) {
let current_field_index = if app_state.ui.show_login { login_state.current_field() } else if app_state.ui.show_register { register_state.current_field() } else { form_state.current_field() };
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } else if app_state.ui.show_register { register_state.current_cursor_pos() } else { form_state.current_cursor_pos() };
}
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode")
&& ModeManager::can_enter_highlight_mode(current_mode)
{
let current_field_index = get_current_field_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
form_state
);
let anchor = (current_field_index, current_cursor_pos);
self.highlight_state = HighlightState::Characterwise { anchor };
self.command_message = "-- HIGHLIGHT --".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone()));
} else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_before") && ModeManager::can_enter_edit_mode(current_mode) {
}
// Handle edit mode transitions
else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_before")
&& ModeManager::can_enter_edit_mode(current_mode)
{
self.is_edit_mode = true;
self.edit_mode_cooldown = true;
self.command_message = "Edit mode".to_string();
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
return Ok(EventOutcome::Ok(self.command_message.clone()));
} else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_after") && ModeManager::can_enter_edit_mode(current_mode) {
let current_input = if app_state.ui.show_login || app_state.ui.show_register { login_state.get_current_input() } else { form_state.get_current_input() };
let current_cursor_pos = if app_state.ui.show_login || app_state.ui.show_register { login_state.current_cursor_pos() } else { form_state.current_cursor_pos() };
}
else if config.get_read_only_action_for_key(key_code, modifiers).as_deref() == Some("enter_edit_mode_after")
&& ModeManager::can_enter_edit_mode(current_mode)
{
let current_input = get_current_input_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_cursor_pos_for_mixed_state(
app_state,
login_state,
form_state
);
// Move cursor forward if possible
if !current_input.is_empty() && current_cursor_pos < current_input.len() {
if app_state.ui.show_login || app_state.ui.show_register {
login_state.set_current_cursor_pos(current_cursor_pos + 1);
self.ideal_cursor_column = login_state.current_cursor_pos();
} else {
form_state.set_current_cursor_pos(current_cursor_pos + 1);
self.ideal_cursor_column = form_state.current_cursor_pos();
}
let new_cursor_pos = current_cursor_pos + 1;
set_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
form_state,
new_cursor_pos
);
self.ideal_cursor_column = get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
form_state
);
}
self.is_edit_mode = true;
self.edit_mode_cooldown = true;
app_state.ui.focus_outside_canvas = false;
self.command_message = "Edit mode (after cursor)".to_string();
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
return Ok(EventOutcome::Ok(self.command_message.clone()));
} else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode") && ModeManager::can_enter_command_mode(current_mode) {
}
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode")
&& ModeManager::can_enter_command_mode(current_mode)
{
self.command_mode = true;
self.command_input.clear();
self.command_message.clear();
return Ok(EventOutcome::Ok(String::new()));
}
if let Some(action) =
config.get_common_action(key_code, modifiers)
{
// Handle common actions (save, quit, etc.)
if let Some(action) = config.get_common_action(key_code, modifiers) {
match action {
"save" | "force_quit" | "save_and_quit"
| "revert" => {
"save" | "force_quit" | "save_and_quit" | "revert" => {
return common_mode::handle_core_action(
action,
form_state,
@@ -639,23 +694,36 @@ impl EventHandler {
}
}
let (_should_exit, message) =
read_only::handle_read_only_event(
app_state,
// Try canvas action for form first (NEW: Canvas library integration)
if app_state.ui.show_form {
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
key_event,
config,
form_state,
login_state,
register_state,
&mut admin_state.add_table_state,
&mut admin_state.add_logic_state,
&mut self.key_sequence_tracker,
&mut self.grpc_client, // <-- FIX 1
&mut self.command_message,
&mut self.edit_mode_cooldown,
&mut self.ideal_cursor_column,
)
.await?;
false, // not edit mode
).await {
return Ok(EventOutcome::Ok(canvas_message));
}
}
// Fallback to legacy read-only event handling
let (_should_exit, message) = read_only::handle_read_only_event(
app_state,
key_event,
config,
form_state,
login_state,
register_state,
&mut admin_state.add_table_state,
&mut admin_state.add_logic_state,
&mut self.key_sequence_tracker,
&mut self.grpc_client,
&mut self.command_message,
&mut self.edit_mode_cooldown,
&mut self.ideal_cursor_column,
)
.await?;
return Ok(EventOutcome::Ok(message));
}
@@ -695,12 +763,10 @@ impl EventHandler {
}
AppMode::Edit => {
if let Some(action) =
config.get_common_action(key_code, modifiers)
{
// Handle common actions (save, quit, etc.)
if let Some(action) = config.get_common_action(key_code, modifiers) {
match action {
"save" | "force_quit" | "save_and_quit"
| "revert" => {
"save" | "force_quit" | "save_and_quit" | "revert" => {
return common_mode::handle_core_action(
action,
form_state,
@@ -718,9 +784,25 @@ impl EventHandler {
}
}
// Try canvas action for form first (NEW: Canvas library integration)
if app_state.ui.show_form {
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
key_event,
config,
form_state,
true, // edit mode
).await {
if !canvas_message.is_empty() {
self.command_message = canvas_message.clone();
}
return Ok(EventOutcome::Ok(canvas_message));
}
}
// Handle legacy edit events
let mut current_position = form_state.current_position;
let total_count = form_state.total_count;
// --- MODIFIED: Pass `self` instead of `grpc_client` ---
let edit_result = edit::handle_edit_event(
key_event,
config,
@@ -739,30 +821,62 @@ impl EventHandler {
Ok(edit::EditEventOutcome::ExitEditMode) => {
self.is_edit_mode = false;
self.edit_mode_cooldown = true;
let has_changes = if app_state.ui.show_login { login_state.has_unsaved_changes() } else if app_state.ui.show_register { register_state.has_unsaved_changes() } else { form_state.has_unsaved_changes() };
self.command_message = if has_changes { "Exited edit mode (unsaved changes remain)".to_string() } else { "Read-only mode".to_string() };
// Check for unsaved changes across all states
let has_changes = get_has_unsaved_changes_for_state(
app_state,
login_state,
register_state,
form_state
);
// Set appropriate message based on changes
self.command_message = if has_changes {
"Exited edit mode (unsaved changes remain)".to_string()
} else {
"Read-only mode".to_string()
};
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
let current_input = if app_state.ui.show_login { login_state.get_current_input() } else if app_state.ui.show_register { register_state.get_current_input() } else { form_state.get_current_input() };
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() } else if app_state.ui.show_register { register_state.current_cursor_pos() } else { form_state.current_cursor_pos() };
// Get current input and cursor position
let current_input = get_current_input_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
form_state
);
// Adjust cursor if it's beyond the input length
if !current_input.is_empty() && current_cursor_pos >= current_input.len() {
let new_pos = current_input.len() - 1;
let target_state: &mut dyn CanvasState = if app_state.ui.show_login { login_state } else if app_state.ui.show_register { register_state } else { form_state };
target_state.set_current_cursor_pos(new_pos);
set_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
form_state,
new_pos
);
self.ideal_cursor_column = new_pos;
}
return Ok(EventOutcome::Ok(
self.command_message.clone(),
));
return Ok(EventOutcome::Ok(self.command_message.clone()));
}
Ok(edit::EditEventOutcome::Message(msg)) => {
if !msg.is_empty() {
self.command_message = msg;
}
self.key_sequence_tracker.reset();
return Ok(EventOutcome::Ok(
self.command_message.clone(),
));
return Ok(EventOutcome::Ok(self.command_message.clone()));
}
Err(e) => {
return Err(e.into());
}
@@ -906,4 +1020,96 @@ impl EventHandler {
fn is_processed_command(&self, command: &str) -> bool {
matches!(command, "w" | "q" | "q!" | "wq" | "r")
}
async fn handle_form_canvas_action(
&mut self,
key_event: KeyEvent,
config: &Config,
form_state: &mut FormState,
is_edit_mode: bool,
) -> Result<Option<String>> {
// Handle suggestion actions first if suggestions are active
if form_state.autocomplete_active {
match key_event.code {
KeyCode::Up => {
if let Ok(result) = ActionDispatcher::dispatch(
CanvasAction::SuggestionUp,
form_state,
&mut self.ideal_cursor_column,
).await {
return Ok(result.message().map(|s| s.to_string()));
}
}
KeyCode::Down => {
if let Ok(result) = ActionDispatcher::dispatch(
CanvasAction::SuggestionDown,
form_state,
&mut self.ideal_cursor_column,
).await {
return Ok(result.message().map(|s| s.to_string()));
}
}
KeyCode::Enter => {
if let Ok(result) = ActionDispatcher::dispatch(
CanvasAction::SelectSuggestion,
form_state,
&mut self.ideal_cursor_column,
).await {
return Ok(result.message().map(|s| s.to_string()));
}
}
KeyCode::Esc => {
if let Ok(result) = ActionDispatcher::dispatch(
CanvasAction::ExitSuggestions,
form_state,
&mut self.ideal_cursor_column,
).await {
return Ok(result.message().map(|s| s.to_string()));
}
}
_ => {}
}
}
// Try to create canvas action from key
if let Some(canvas_action) = CanvasAction::from_key(key_event.code) {
match ActionDispatcher::dispatch(
canvas_action,
form_state,
&mut self.ideal_cursor_column,
).await {
Ok(result) => {
return Ok(result.message().map(|s| s.to_string()));
}
Err(_) => {
// Fall through to try config mapping
}
}
}
// Try mapped actions from config
let action_str = if is_edit_mode {
config.get_edit_action_for_key(key_event.code, key_event.modifiers)
} else {
config.get_read_only_action_for_key(key_event.code, key_event.modifiers)
};
if let Some(action_str) = action_str {
let canvas_action = CanvasAction::from_string(&action_str);
match ActionDispatcher::dispatch(
canvas_action,
form_state,
&mut self.ideal_cursor_column,
).await {
Ok(result) => {
return Ok(result.message().map(|s| s.to_string()));
}
Err(_) => {
// Ignore error, let existing code handle it
}
}
}
Ok(None)
}
}

View File

@@ -0,0 +1,105 @@
// src/modes/handlers/event_helper.rs
//! Helper functions to handle the differences between legacy and library CanvasState traits
use crate::state::app::state::AppState;
use crate::state::pages::{
form::FormState,
auth::{LoginState, RegisterState},
};
use crate::state::pages::canvas_state::CanvasState as LegacyCanvasState;
use canvas::CanvasState as LibraryCanvasState;
/// Get the current field index from the appropriate state based on which UI is active
pub fn get_current_field_for_state(
app_state: &AppState,
login_state: &LoginState,
register_state: &RegisterState,
form_state: &FormState,
) -> usize {
if app_state.ui.show_login {
login_state.current_field() // Uses LegacyCanvasState
} else if app_state.ui.show_register {
register_state.current_field() // Uses LegacyCanvasState
} else {
form_state.current_field() // Uses LibraryCanvasState
}
}
/// Get the current cursor position from the appropriate state based on which UI is active
pub fn get_current_cursor_pos_for_state(
app_state: &AppState,
login_state: &LoginState,
register_state: &RegisterState,
form_state: &FormState,
) -> usize {
if app_state.ui.show_login {
login_state.current_cursor_pos() // Uses LegacyCanvasState
} else if app_state.ui.show_register {
register_state.current_cursor_pos() // Uses LegacyCanvasState
} else {
form_state.current_cursor_pos() // Uses LibraryCanvasState
}
}
/// Check if the appropriate state has unsaved changes based on which UI is active
pub fn get_has_unsaved_changes_for_state(
app_state: &AppState,
login_state: &LoginState,
register_state: &RegisterState,
form_state: &FormState,
) -> bool {
if app_state.ui.show_login {
login_state.has_unsaved_changes() // Uses LegacyCanvasState
} else if app_state.ui.show_register {
register_state.has_unsaved_changes() // Uses LegacyCanvasState
} else {
form_state.has_unsaved_changes() // Uses LibraryCanvasState
}
}
/// Get the current input from the appropriate state based on which UI is active
pub fn get_current_input_for_state<'a>(
app_state: &AppState,
login_state: &'a LoginState,
register_state: &'a RegisterState,
form_state: &'a FormState,
) -> &'a str {
if app_state.ui.show_login {
login_state.get_current_input() // Uses LegacyCanvasState
} else if app_state.ui.show_register {
register_state.get_current_input() // Uses LegacyCanvasState
} else {
form_state.get_current_input() // Uses LibraryCanvasState
}
}
/// Set the cursor position for the appropriate state based on which UI is active
pub fn set_current_cursor_pos_for_state(
app_state: &AppState,
login_state: &mut LoginState,
register_state: &mut RegisterState,
form_state: &mut FormState,
pos: usize,
) {
if app_state.ui.show_login {
login_state.set_current_cursor_pos(pos); // Uses LegacyCanvasState
} else if app_state.ui.show_register {
register_state.set_current_cursor_pos(pos); // Uses LegacyCanvasState
} else {
form_state.set_current_cursor_pos(pos); // Uses LibraryCanvasState
}
}
/// Get cursor position for mixed login/register vs form logic
pub fn get_cursor_pos_for_mixed_state(
app_state: &AppState,
login_state: &LoginState,
form_state: &FormState,
) -> usize {
if app_state.ui.show_login || app_state.ui.show_register {
login_state.current_cursor_pos() // Uses LegacyCanvasState
} else {
form_state.current_cursor_pos() // Uses LibraryCanvasState
}
}