fixed working canvas in client, need more fixes now
This commit is contained in:
@@ -31,12 +31,9 @@ pub async fn execute_canvas_action_with_autocomplete<S: CanvasState + Autocomple
|
|||||||
|
|
||||||
// 3. AUTO-TRIGGER LOGIC: Check if we should activate/deactivate autocomplete
|
// 3. AUTO-TRIGGER LOGIC: Check if we should activate/deactivate autocomplete
|
||||||
if let Some(cfg) = config {
|
if let Some(cfg) = config {
|
||||||
println!("{:?}, {}", action, cfg.should_auto_trigger_autocomplete());
|
|
||||||
if cfg.should_auto_trigger_autocomplete() {
|
if cfg.should_auto_trigger_autocomplete() {
|
||||||
println!("AUTO-TRIGGER");
|
|
||||||
match action {
|
match action {
|
||||||
CanvasAction::InsertChar(_) => {
|
CanvasAction::InsertChar(_) => {
|
||||||
println!("AUTO-T on Ins");
|
|
||||||
let current_field = state.current_field();
|
let current_field = state.current_field();
|
||||||
let current_input = state.get_current_input();
|
let current_input = state.get_current_input();
|
||||||
|
|
||||||
@@ -44,13 +41,11 @@ pub async fn execute_canvas_action_with_autocomplete<S: CanvasState + Autocomple
|
|||||||
&& !state.is_autocomplete_active()
|
&& !state.is_autocomplete_active()
|
||||||
&& current_input.len() >= 1
|
&& current_input.len() >= 1
|
||||||
{
|
{
|
||||||
println!("ACT AUTOC");
|
|
||||||
state.activate_autocomplete();
|
state.activate_autocomplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasAction::NextField | CanvasAction::PrevField => {
|
CanvasAction::NextField | CanvasAction::PrevField => {
|
||||||
println!("AUTO-T on nav");
|
|
||||||
let current_field = state.current_field();
|
let current_field = state.current_field();
|
||||||
|
|
||||||
if state.supports_autocomplete(current_field) && !state.is_autocomplete_active() {
|
if state.supports_autocomplete(current_field) && !state.is_autocomplete_active() {
|
||||||
|
|||||||
@@ -108,8 +108,6 @@ impl CanvasConfig {
|
|||||||
match Self::load_and_validate() {
|
match Self::load_and_validate() {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("⚠️ Failed to load canvas config: {}", e);
|
|
||||||
eprintln!(" Using default configuration");
|
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,9 +128,7 @@ impl CanvasConfig {
|
|||||||
|
|
||||||
// Validate the handlers match their claimed capabilities
|
// Validate the handlers match their claimed capabilities
|
||||||
if let Err(handler_errors) = registry.validate_against_implementation() {
|
if let Err(handler_errors) = registry.validate_against_implementation() {
|
||||||
eprintln!("⚠️ Handler validation failed:");
|
|
||||||
for error in handler_errors {
|
for error in handler_errors {
|
||||||
eprintln!(" - {}", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,15 +137,8 @@ impl CanvasConfig {
|
|||||||
let validation_result = validator.validate_keybindings(&config.keybindings);
|
let validation_result = validator.validate_keybindings(&config.keybindings);
|
||||||
|
|
||||||
if !validation_result.is_valid {
|
if !validation_result.is_valid {
|
||||||
eprintln!("❌ Canvas configuration validation failed:");
|
|
||||||
validator.print_validation_result(&validation_result);
|
validator.print_validation_result(&validation_result);
|
||||||
eprintln!();
|
|
||||||
eprintln!("🔧 To generate a working config template:");
|
|
||||||
eprintln!(" CanvasConfig::generate_template()");
|
|
||||||
eprintln!();
|
|
||||||
eprintln!("📁 Expected config file location: canvas_config.toml");
|
|
||||||
} else if !validation_result.warnings.is_empty() {
|
} else if !validation_result.warnings.is_empty() {
|
||||||
eprintln!("⚠️ Canvas configuration has warnings:");
|
|
||||||
validator.print_validation_result(&validation_result);
|
validator.print_validation_result(&validation_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,9 +151,7 @@ impl CanvasConfig {
|
|||||||
|
|
||||||
// Validate handlers first
|
// Validate handlers first
|
||||||
if let Err(errors) = registry.validate_against_implementation() {
|
if let Err(errors) = registry.validate_against_implementation() {
|
||||||
eprintln!("⚠️ Warning: Handler validation failed while generating template:");
|
|
||||||
for error in errors {
|
for error in errors {
|
||||||
eprintln!(" - {}", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +164,6 @@ impl CanvasConfig {
|
|||||||
|
|
||||||
// Validate handlers first
|
// Validate handlers first
|
||||||
if let Err(errors) = registry.validate_against_implementation() {
|
if let Err(errors) = registry.validate_against_implementation() {
|
||||||
eprintln!("⚠️ Warning: Handler validation failed while generating template:");
|
|
||||||
for error in errors {
|
for error in errors {
|
||||||
eprintln!(" - {}", error);
|
eprintln!(" - {}", error);
|
||||||
}
|
}
|
||||||
@@ -263,26 +249,225 @@ impl CanvasConfig {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_keybinding(&self, _binding: &str, _key: KeyCode, _modifiers: KeyModifiers) -> bool {
|
fn matches_keybinding(&self, binding: &str, key: KeyCode, modifiers: KeyModifiers) -> bool {
|
||||||
// Keep your existing implementation - this is just a placeholder
|
// Special handling for shift+character combinations
|
||||||
true
|
if binding.to_lowercase().starts_with("shift+") {
|
||||||
}
|
let parts: Vec<&str> = binding.split('+').collect();
|
||||||
|
if parts.len() == 2 && parts[1].len() == 1 {
|
||||||
/// Debug method to print loaded keybindings with validation
|
let expected_lowercase = parts[1].chars().next().unwrap().to_lowercase().next().unwrap();
|
||||||
pub fn debug_keybindings(&self) {
|
let expected_uppercase = expected_lowercase.to_uppercase().next().unwrap();
|
||||||
println!("📋 Canvas keybindings loaded:");
|
if let KeyCode::Char(actual_char) = key {
|
||||||
println!(" Read-only: {} actions", self.keybindings.read_only.len());
|
if actual_char == expected_uppercase && modifiers.contains(KeyModifiers::SHIFT) {
|
||||||
println!(" Edit: {} actions", self.keybindings.edit.len());
|
return true;
|
||||||
|
}
|
||||||
// NEW: Show validation status against actual implementation
|
}
|
||||||
let validation = self.validate();
|
}
|
||||||
if validation.is_valid {
|
|
||||||
println!(" ✅ Configuration matches actual implementation");
|
|
||||||
} else {
|
|
||||||
println!(" ❌ Configuration has {} errors vs implementation", validation.errors.len());
|
|
||||||
}
|
}
|
||||||
if !validation.warnings.is_empty() {
|
|
||||||
println!(" ⚠️ Configuration has {} warnings", validation.warnings.len());
|
// Handle Shift+Tab -> BackTab
|
||||||
|
if binding.to_lowercase() == "shift+tab" && key == KeyCode::BackTab && modifiers.is_empty() {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle multi-character bindings (all standard keys without modifiers)
|
||||||
|
if binding.len() > 1 && !binding.contains('+') {
|
||||||
|
return match binding.to_lowercase().as_str() {
|
||||||
|
// Navigation keys
|
||||||
|
"left" => key == KeyCode::Left,
|
||||||
|
"right" => key == KeyCode::Right,
|
||||||
|
"up" => key == KeyCode::Up,
|
||||||
|
"down" => key == KeyCode::Down,
|
||||||
|
"home" => key == KeyCode::Home,
|
||||||
|
"end" => key == KeyCode::End,
|
||||||
|
"pageup" | "pgup" => key == KeyCode::PageUp,
|
||||||
|
"pagedown" | "pgdn" => key == KeyCode::PageDown,
|
||||||
|
|
||||||
|
// Editing keys
|
||||||
|
"insert" | "ins" => key == KeyCode::Insert,
|
||||||
|
"delete" | "del" => key == KeyCode::Delete,
|
||||||
|
"backspace" => key == KeyCode::Backspace,
|
||||||
|
|
||||||
|
// Tab keys
|
||||||
|
"tab" => key == KeyCode::Tab,
|
||||||
|
"backtab" => key == KeyCode::BackTab,
|
||||||
|
|
||||||
|
// Special keys
|
||||||
|
"enter" | "return" => key == KeyCode::Enter,
|
||||||
|
"escape" | "esc" => key == KeyCode::Esc,
|
||||||
|
"space" => key == KeyCode::Char(' '),
|
||||||
|
|
||||||
|
// Function keys F1-F24
|
||||||
|
"f1" => key == KeyCode::F(1),
|
||||||
|
"f2" => key == KeyCode::F(2),
|
||||||
|
"f3" => key == KeyCode::F(3),
|
||||||
|
"f4" => key == KeyCode::F(4),
|
||||||
|
"f5" => key == KeyCode::F(5),
|
||||||
|
"f6" => key == KeyCode::F(6),
|
||||||
|
"f7" => key == KeyCode::F(7),
|
||||||
|
"f8" => key == KeyCode::F(8),
|
||||||
|
"f9" => key == KeyCode::F(9),
|
||||||
|
"f10" => key == KeyCode::F(10),
|
||||||
|
"f11" => key == KeyCode::F(11),
|
||||||
|
"f12" => key == KeyCode::F(12),
|
||||||
|
"f13" => key == KeyCode::F(13),
|
||||||
|
"f14" => key == KeyCode::F(14),
|
||||||
|
"f15" => key == KeyCode::F(15),
|
||||||
|
"f16" => key == KeyCode::F(16),
|
||||||
|
"f17" => key == KeyCode::F(17),
|
||||||
|
"f18" => key == KeyCode::F(18),
|
||||||
|
"f19" => key == KeyCode::F(19),
|
||||||
|
"f20" => key == KeyCode::F(20),
|
||||||
|
"f21" => key == KeyCode::F(21),
|
||||||
|
"f22" => key == KeyCode::F(22),
|
||||||
|
"f23" => key == KeyCode::F(23),
|
||||||
|
"f24" => key == KeyCode::F(24),
|
||||||
|
|
||||||
|
// Lock keys (may not work reliably in all terminals)
|
||||||
|
"capslock" => key == KeyCode::CapsLock,
|
||||||
|
"scrolllock" => key == KeyCode::ScrollLock,
|
||||||
|
"numlock" => key == KeyCode::NumLock,
|
||||||
|
|
||||||
|
// System keys
|
||||||
|
"printscreen" => key == KeyCode::PrintScreen,
|
||||||
|
"pause" => key == KeyCode::Pause,
|
||||||
|
"menu" => key == KeyCode::Menu,
|
||||||
|
"keypadbegin" => key == KeyCode::KeypadBegin,
|
||||||
|
|
||||||
|
// Media keys (rarely supported but included for completeness)
|
||||||
|
"mediaplay" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Play),
|
||||||
|
"mediapause" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Pause),
|
||||||
|
"mediaplaypause" => key == KeyCode::Media(crossterm::event::MediaKeyCode::PlayPause),
|
||||||
|
"mediareverse" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Reverse),
|
||||||
|
"mediastop" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Stop),
|
||||||
|
"mediafastforward" => key == KeyCode::Media(crossterm::event::MediaKeyCode::FastForward),
|
||||||
|
"mediarewind" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Rewind),
|
||||||
|
"mediatracknext" => key == KeyCode::Media(crossterm::event::MediaKeyCode::TrackNext),
|
||||||
|
"mediatrackprevious" => key == KeyCode::Media(crossterm::event::MediaKeyCode::TrackPrevious),
|
||||||
|
"mediarecord" => key == KeyCode::Media(crossterm::event::MediaKeyCode::Record),
|
||||||
|
"medialowervolume" => key == KeyCode::Media(crossterm::event::MediaKeyCode::LowerVolume),
|
||||||
|
"mediaraisevolume" => key == KeyCode::Media(crossterm::event::MediaKeyCode::RaiseVolume),
|
||||||
|
"mediamutevolume" => key == KeyCode::Media(crossterm::event::MediaKeyCode::MuteVolume),
|
||||||
|
|
||||||
|
// Modifier keys (these work better as part of combinations)
|
||||||
|
"leftshift" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftShift),
|
||||||
|
"leftcontrol" | "leftctrl" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftControl),
|
||||||
|
"leftalt" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftAlt),
|
||||||
|
"leftsuper" | "leftwindows" | "leftcmd" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftSuper),
|
||||||
|
"lefthyper" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftHyper),
|
||||||
|
"leftmeta" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::LeftMeta),
|
||||||
|
"rightshift" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightShift),
|
||||||
|
"rightcontrol" | "rightctrl" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightControl),
|
||||||
|
"rightalt" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightAlt),
|
||||||
|
"rightsuper" | "rightwindows" | "rightcmd" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightSuper),
|
||||||
|
"righthyper" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightHyper),
|
||||||
|
"rightmeta" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::RightMeta),
|
||||||
|
"isolevel3shift" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::IsoLevel3Shift),
|
||||||
|
"isolevel5shift" => key == KeyCode::Modifier(crossterm::event::ModifierKeyCode::IsoLevel5Shift),
|
||||||
|
|
||||||
|
// Multi-key sequences need special handling
|
||||||
|
"gg" => false, // This needs sequence handling
|
||||||
|
_ => {
|
||||||
|
// Handle single characters and punctuation
|
||||||
|
if binding.len() == 1 {
|
||||||
|
if let Some(c) = binding.chars().next() {
|
||||||
|
key == KeyCode::Char(c)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle modifier combinations (like "Ctrl+F5", "Alt+Shift+A")
|
||||||
|
let parts: Vec<&str> = binding.split('+').collect();
|
||||||
|
let mut expected_modifiers = KeyModifiers::empty();
|
||||||
|
let mut expected_key = None;
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
match part.to_lowercase().as_str() {
|
||||||
|
// Modifiers
|
||||||
|
"ctrl" | "control" => expected_modifiers |= KeyModifiers::CONTROL,
|
||||||
|
"shift" => expected_modifiers |= KeyModifiers::SHIFT,
|
||||||
|
"alt" => expected_modifiers |= KeyModifiers::ALT,
|
||||||
|
"super" | "windows" | "cmd" => expected_modifiers |= KeyModifiers::SUPER,
|
||||||
|
"hyper" => expected_modifiers |= KeyModifiers::HYPER,
|
||||||
|
"meta" => expected_modifiers |= KeyModifiers::META,
|
||||||
|
|
||||||
|
// Navigation keys
|
||||||
|
"left" => expected_key = Some(KeyCode::Left),
|
||||||
|
"right" => expected_key = Some(KeyCode::Right),
|
||||||
|
"up" => expected_key = Some(KeyCode::Up),
|
||||||
|
"down" => expected_key = Some(KeyCode::Down),
|
||||||
|
"home" => expected_key = Some(KeyCode::Home),
|
||||||
|
"end" => expected_key = Some(KeyCode::End),
|
||||||
|
"pageup" | "pgup" => expected_key = Some(KeyCode::PageUp),
|
||||||
|
"pagedown" | "pgdn" => expected_key = Some(KeyCode::PageDown),
|
||||||
|
|
||||||
|
// Editing keys
|
||||||
|
"insert" | "ins" => expected_key = Some(KeyCode::Insert),
|
||||||
|
"delete" | "del" => expected_key = Some(KeyCode::Delete),
|
||||||
|
"backspace" => expected_key = Some(KeyCode::Backspace),
|
||||||
|
|
||||||
|
// Tab keys
|
||||||
|
"tab" => expected_key = Some(KeyCode::Tab),
|
||||||
|
"backtab" => expected_key = Some(KeyCode::BackTab),
|
||||||
|
|
||||||
|
// Special keys
|
||||||
|
"enter" | "return" => expected_key = Some(KeyCode::Enter),
|
||||||
|
"escape" | "esc" => expected_key = Some(KeyCode::Esc),
|
||||||
|
"space" => expected_key = Some(KeyCode::Char(' ')),
|
||||||
|
|
||||||
|
// Function keys
|
||||||
|
"f1" => expected_key = Some(KeyCode::F(1)),
|
||||||
|
"f2" => expected_key = Some(KeyCode::F(2)),
|
||||||
|
"f3" => expected_key = Some(KeyCode::F(3)),
|
||||||
|
"f4" => expected_key = Some(KeyCode::F(4)),
|
||||||
|
"f5" => expected_key = Some(KeyCode::F(5)),
|
||||||
|
"f6" => expected_key = Some(KeyCode::F(6)),
|
||||||
|
"f7" => expected_key = Some(KeyCode::F(7)),
|
||||||
|
"f8" => expected_key = Some(KeyCode::F(8)),
|
||||||
|
"f9" => expected_key = Some(KeyCode::F(9)),
|
||||||
|
"f10" => expected_key = Some(KeyCode::F(10)),
|
||||||
|
"f11" => expected_key = Some(KeyCode::F(11)),
|
||||||
|
"f12" => expected_key = Some(KeyCode::F(12)),
|
||||||
|
"f13" => expected_key = Some(KeyCode::F(13)),
|
||||||
|
"f14" => expected_key = Some(KeyCode::F(14)),
|
||||||
|
"f15" => expected_key = Some(KeyCode::F(15)),
|
||||||
|
"f16" => expected_key = Some(KeyCode::F(16)),
|
||||||
|
"f17" => expected_key = Some(KeyCode::F(17)),
|
||||||
|
"f18" => expected_key = Some(KeyCode::F(18)),
|
||||||
|
"f19" => expected_key = Some(KeyCode::F(19)),
|
||||||
|
"f20" => expected_key = Some(KeyCode::F(20)),
|
||||||
|
"f21" => expected_key = Some(KeyCode::F(21)),
|
||||||
|
"f22" => expected_key = Some(KeyCode::F(22)),
|
||||||
|
"f23" => expected_key = Some(KeyCode::F(23)),
|
||||||
|
"f24" => expected_key = Some(KeyCode::F(24)),
|
||||||
|
|
||||||
|
// Lock keys
|
||||||
|
"capslock" => expected_key = Some(KeyCode::CapsLock),
|
||||||
|
"scrolllock" => expected_key = Some(KeyCode::ScrollLock),
|
||||||
|
"numlock" => expected_key = Some(KeyCode::NumLock),
|
||||||
|
|
||||||
|
// System keys
|
||||||
|
"printscreen" => expected_key = Some(KeyCode::PrintScreen),
|
||||||
|
"pause" => expected_key = Some(KeyCode::Pause),
|
||||||
|
"menu" => expected_key = Some(KeyCode::Menu),
|
||||||
|
"keypadbegin" => expected_key = Some(KeyCode::KeypadBegin),
|
||||||
|
|
||||||
|
// Single character (letters, numbers, punctuation)
|
||||||
|
part => {
|
||||||
|
if part.len() == 1 {
|
||||||
|
if let Some(c) = part.chars().next() {
|
||||||
|
expected_key = Some(KeyCode::Char(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers == expected_modifiers && Some(key) == expected_key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ move_word_next = ["w"]
|
|||||||
next_field = ["Tab"]
|
next_field = ["Tab"]
|
||||||
move_word_prev = ["b"]
|
move_word_prev = ["b"]
|
||||||
move_word_end = ["e"]
|
move_word_end = ["e"]
|
||||||
move_last_line = ["G"]
|
move_last_line = ["shift+g"]
|
||||||
move_word_end_prev = ["ge"]
|
move_word_end_prev = ["ge"]
|
||||||
move_line_start = ["0"]
|
move_line_start = ["0"]
|
||||||
move_first_line = ["gg"]
|
move_first_line = ["g+g"]
|
||||||
prev_field = ["Shift+Tab"]
|
prev_field = ["Shift+Tab"]
|
||||||
|
|
||||||
[keybindings.highlight]
|
[keybindings.highlight]
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use canvas::canvas::CanvasState;
|
|||||||
use canvas::{canvas::CanvasAction, dispatcher::ActionDispatcher, canvas::ActionResult};
|
use canvas::{canvas::CanvasAction, dispatcher::ActionDispatcher, canvas::ActionResult};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::proto::komp_ac::search::search_response::Hit;
|
use common::proto::komp_ac::search::search_response::Hit;
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
@@ -143,23 +143,46 @@ async fn execute_canvas_action(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NEW: Unified canvas action handler for any CanvasState (LoginState, RegisterState, etc.)
|
/// FIXED: Unified canvas action handler with proper priority order for edit mode
|
||||||
/// This replaces the old auth_e::execute_edit_action calls with the new canvas library
|
|
||||||
/// NEW: Unified canvas action handler for any CanvasState with character fallback
|
|
||||||
/// Complete canvas action handler with fallbacks for common keys
|
|
||||||
/// Debug version to see what's happening
|
|
||||||
async fn handle_canvas_state_edit<S: CanvasState>(
|
async fn handle_canvas_state_edit<S: CanvasState>(
|
||||||
key: KeyEvent,
|
key: KeyEvent,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
ideal_cursor_column: &mut usize,
|
ideal_cursor_column: &mut usize,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
println!("DEBUG: Key pressed: {:?}", key); // DEBUG
|
// println!("DEBUG: Key pressed: {:?}", key); // DEBUG
|
||||||
|
|
||||||
// Try direct key mapping first (same pattern as FormState)
|
// PRIORITY 1: Character insertion in edit mode comes FIRST
|
||||||
|
if let KeyCode::Char(c) = key.code {
|
||||||
|
// Only insert if no modifiers or just shift (for uppercase)
|
||||||
|
if key.modifiers.is_empty() || key.modifiers == KeyModifiers::SHIFT {
|
||||||
|
// println!("DEBUG: Using character insertion priority for: {}", c); // DEBUG
|
||||||
|
let canvas_action = CanvasAction::InsertChar(c);
|
||||||
|
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
||||||
|
Ok(ActionResult::Success(msg)) => {
|
||||||
|
return Ok(msg.unwrap_or_default());
|
||||||
|
}
|
||||||
|
Ok(ActionResult::HandledByFeature(msg)) => {
|
||||||
|
return Ok(msg);
|
||||||
|
}
|
||||||
|
Ok(ActionResult::Error(msg)) => {
|
||||||
|
return Ok(format!("Error: {}", msg));
|
||||||
|
}
|
||||||
|
Ok(ActionResult::RequiresContext(msg)) => {
|
||||||
|
return Ok(format!("Context needed: {}", msg));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// println!("DEBUG: Character insertion failed: {:?}, trying config", e);
|
||||||
|
// Fall through to try config mappings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIORITY 2: Check canvas config for special keys/combinations
|
||||||
let canvas_config = canvas::config::CanvasConfig::load();
|
let canvas_config = canvas::config::CanvasConfig::load();
|
||||||
if let Some(action_name) = canvas_config.get_edit_action(key.code, key.modifiers) {
|
if let Some(action_name) = canvas_config.get_edit_action(key.code, key.modifiers) {
|
||||||
println!("DEBUG: Canvas config mapped to: {}", action_name); // DEBUG
|
// println!("DEBUG: Canvas config mapped to: {}", action_name); // DEBUG
|
||||||
let canvas_action = CanvasAction::from_string(action_name);
|
let canvas_action = CanvasAction::from_string(action_name);
|
||||||
|
|
||||||
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
||||||
@@ -176,62 +199,43 @@ async fn handle_canvas_state_edit<S: CanvasState>(
|
|||||||
return Ok(format!("Context needed: {}", msg));
|
return Ok(format!("Context needed: {}", msg));
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("DEBUG: Canvas action failed, trying client config"); // DEBUG
|
// println!("DEBUG: Canvas action failed, trying client config"); // DEBUG
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("DEBUG: No canvas config mapping found"); // DEBUG
|
// println!("DEBUG: No canvas config mapping found"); // DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try config-mapped action (same pattern as FormState)
|
// PRIORITY 3: Check client config ONLY for non-character keys or modified keys
|
||||||
if let Some(action_str) = config.get_edit_action_for_key(key.code, key.modifiers) {
|
if !matches!(key.code, KeyCode::Char(_)) || !key.modifiers.is_empty() {
|
||||||
println!("DEBUG: Client config mapped to: {}", action_str); // DEBUG
|
if let Some(action_str) = config.get_edit_action_for_key(key.code, key.modifiers) {
|
||||||
let canvas_action = CanvasAction::from_string(&action_str);
|
// println!("DEBUG: Client config mapped to: {} (for non-char key)", action_str); // DEBUG
|
||||||
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
let canvas_action = CanvasAction::from_string(&action_str);
|
||||||
Ok(ActionResult::Success(msg)) => {
|
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
||||||
return Ok(msg.unwrap_or_default());
|
Ok(ActionResult::Success(msg)) => {
|
||||||
}
|
return Ok(msg.unwrap_or_default());
|
||||||
Ok(ActionResult::HandledByFeature(msg)) => {
|
}
|
||||||
return Ok(msg);
|
Ok(ActionResult::HandledByFeature(msg)) => {
|
||||||
}
|
return Ok(msg);
|
||||||
Ok(ActionResult::Error(msg)) => {
|
}
|
||||||
return Ok(format!("Error: {}", msg));
|
Ok(ActionResult::Error(msg)) => {
|
||||||
}
|
return Ok(format!("Error: {}", msg));
|
||||||
Ok(ActionResult::RequiresContext(msg)) => {
|
}
|
||||||
return Ok(format!("Context needed: {}", msg));
|
Ok(ActionResult::RequiresContext(msg)) => {
|
||||||
}
|
return Ok(format!("Context needed: {}", msg));
|
||||||
Err(e) => {
|
}
|
||||||
return Ok(format!("Action failed: {}", e));
|
Err(e) => {
|
||||||
|
return Ok(format!("Action failed: {}", e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// println!("DEBUG: No client config mapping found for non-char key"); // DEBUG
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("DEBUG: No client config mapping found"); // DEBUG
|
// println!("DEBUG: Skipping client config for character key in edit mode"); // DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
// Character insertion fallback
|
// println!("DEBUG: No action taken for key: {:?}", key); // DEBUG
|
||||||
if let KeyCode::Char(c) = key.code {
|
|
||||||
println!("DEBUG: Using character fallback for: {}", c); // DEBUG
|
|
||||||
let canvas_action = CanvasAction::InsertChar(c);
|
|
||||||
match ActionDispatcher::dispatch(canvas_action, state, ideal_cursor_column).await {
|
|
||||||
Ok(ActionResult::Success(msg)) => {
|
|
||||||
return Ok(msg.unwrap_or_default());
|
|
||||||
}
|
|
||||||
Ok(ActionResult::HandledByFeature(msg)) => {
|
|
||||||
return Ok(msg);
|
|
||||||
}
|
|
||||||
Ok(ActionResult::Error(msg)) => {
|
|
||||||
return Ok(format!("Error: {}", msg));
|
|
||||||
}
|
|
||||||
Ok(ActionResult::RequiresContext(msg)) => {
|
|
||||||
return Ok(format!("Context needed: {}", msg));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
return Ok(format!("Character insertion failed: {}", e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("DEBUG: No action taken for key: {:?}", key); // DEBUG
|
|
||||||
Ok(String::new())
|
Ok(String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user