compiled still not working
This commit is contained in:
@@ -8,7 +8,7 @@ license.workspace = true
|
||||
anyhow = { workspace = true }
|
||||
async-trait = "0.1.88"
|
||||
common = { path = "../common" }
|
||||
canvas = { path = "../canvas", features = ["gui", "suggestions", "cursor-style"] }
|
||||
canvas = { path = "../canvas", features = ["gui", "suggestions", "cursor-style", "keymap"] }
|
||||
|
||||
ratatui = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use canvas::CanvasKeyMap;
|
||||
|
||||
// NEW: Editor Keybinding Mode Enum
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@@ -760,4 +761,43 @@ impl Config {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Unified action resolver for app-level actions
|
||||
pub fn get_app_action(
|
||||
&self,
|
||||
key_code: crossterm::event::KeyCode,
|
||||
modifiers: crossterm::event::KeyModifiers,
|
||||
) -> Option<&str> {
|
||||
// First check common actions
|
||||
if let Some(action) = self.get_common_action(key_code, modifiers) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
// Then check read-only mode actions
|
||||
if let Some(action) = self.get_read_only_action_for_key(key_code, modifiers) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
// Then check highlight mode actions
|
||||
if let Some(action) = self.get_highlight_action_for_key(key_code, modifiers) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
// Then check edit mode actions
|
||||
if let Some(action) = self.get_edit_action_for_key(key_code, modifiers) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn build_canvas_keymap(&self) -> CanvasKeyMap {
|
||||
CanvasKeyMap::from_mode_maps(
|
||||
&self.keybindings.read_only,
|
||||
&self.keybindings.edit,
|
||||
&self.keybindings.highlight,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ use crate::tui::{
|
||||
};
|
||||
use crate::ui::handlers::context::UiContext;
|
||||
use crate::ui::handlers::rat_state::UiStateHandler;
|
||||
use canvas::KeyEventOutcome;
|
||||
use anyhow::Result;
|
||||
use common::proto::komp_ac::search::search_response::Hit;
|
||||
use crossterm::event::KeyModifiers;
|
||||
@@ -650,80 +651,29 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
AppMode::ReadOnly => {
|
||||
// Handle highlight mode transitions (delegated to FormEditor)
|
||||
if config.get_read_only_action_for_key(key_code, modifiers)
|
||||
== Some("enter_highlight_mode_linewise")
|
||||
&& ModeManager::can_enter_highlight_mode(current_mode)
|
||||
{
|
||||
// First let the canvas editor try to handle the key
|
||||
if app_state.ui.show_form {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.enter_highlight_line_mode();
|
||||
match editor.handle_key_event(key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
return Ok(EventOutcome::Ok(msg));
|
||||
}
|
||||
KeyEventOutcome::Consumed(None) => {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::Pending => {
|
||||
// Waiting for multi-key sequence (e.g. after pressing 'g')
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::NotMatched => {
|
||||
// Fall through to client-level actions
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.enter_highlight_mode();
|
||||
}
|
||||
self.command_message = "-- HIGHLIGHT --".to_string();
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.enter_edit_mode();
|
||||
}
|
||||
self.is_edit_mode = true;
|
||||
self.edit_mode_cooldown = true;
|
||||
self.command_message = "Edit mode".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_after")
|
||||
&& ModeManager::can_enter_edit_mode(current_mode)
|
||||
{
|
||||
let current_input = Self::get_current_input_for_state(
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
form_state,
|
||||
);
|
||||
let current_cursor_pos =
|
||||
Self::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() {
|
||||
let new_cursor_pos = current_cursor_pos + 1;
|
||||
Self::set_current_cursor_pos_for_state(
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
form_state,
|
||||
new_cursor_pos,
|
||||
);
|
||||
self.ideal_cursor_column = Self::get_current_cursor_pos_for_state(
|
||||
app_state,
|
||||
login_state,
|
||||
register_state,
|
||||
form_state,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.enter_edit_mode();
|
||||
}
|
||||
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();
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
} else if config.get_read_only_action_for_key(key_code, modifiers)
|
||||
== Some("enter_command_mode")
|
||||
// Entering command mode is still a client-level action
|
||||
if config.get_app_action(key_code, modifiers) == Some("enter_command_mode")
|
||||
&& ModeManager::can_enter_command_mode(current_mode)
|
||||
{
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
@@ -736,7 +686,7 @@ impl EventHandler {
|
||||
}
|
||||
|
||||
// Handle common actions (save, quit, etc.)
|
||||
if let Some(action) = config.get_common_action(key_code, modifiers) {
|
||||
if let Some(action) = config.get_app_action(key_code, modifiers) {
|
||||
match action {
|
||||
"save" | "force_quit" | "save_and_quit" | "revert" => {
|
||||
return self
|
||||
@@ -755,37 +705,27 @@ impl EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Try canvas action for form first
|
||||
if app_state.ui.show_form {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
if let Ok(Some(canvas_message)) =
|
||||
self.handle_form_canvas_action(key_event, editor, config, false).await
|
||||
{
|
||||
return Ok(EventOutcome::Ok(canvas_message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
}
|
||||
|
||||
AppMode::Highlight => {
|
||||
if config.get_highlight_action_for_key(key_code, modifiers)
|
||||
== Some("exit_highlight_mode")
|
||||
{
|
||||
if app_state.ui.show_form {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.exit_highlight_mode();
|
||||
match editor.handle_key_event(key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
return Ok(EventOutcome::Ok(msg));
|
||||
}
|
||||
KeyEventOutcome::Consumed(None) => {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::Pending => {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::NotMatched => {
|
||||
// Fall through to client-level actions
|
||||
}
|
||||
}
|
||||
}
|
||||
self.command_message = "Exited highlight mode".to_string();
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
} else if config.get_highlight_action_for_key(key_code, modifiers)
|
||||
== Some("enter_highlight_mode_linewise")
|
||||
{
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
editor.enter_highlight_line_mode();
|
||||
}
|
||||
self.command_message = "-- LINE HIGHLIGHT --".to_string();
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
}
|
||||
|
||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||
@@ -793,7 +733,7 @@ impl EventHandler {
|
||||
|
||||
AppMode::Edit => {
|
||||
// Handle common actions (save, quit, etc.)
|
||||
if let Some(action) = config.get_common_action(key_code, modifiers) {
|
||||
if let Some(action) = config.get_app_action(key_code, modifiers) {
|
||||
match action {
|
||||
"save" | "force_quit" | "save_and_quit" | "revert" => {
|
||||
return self
|
||||
@@ -812,19 +752,24 @@ impl EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Try canvas action for form first
|
||||
// Let the canvas editor handle edit-mode keys
|
||||
if app_state.ui.show_form {
|
||||
if let Some(editor) = &mut app_state.form_editor {
|
||||
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
|
||||
key_event,
|
||||
editor,
|
||||
config,
|
||||
true,
|
||||
).await {
|
||||
if !canvas_message.is_empty() {
|
||||
self.command_message = canvas_message.clone();
|
||||
match editor.handle_key_event(key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
self.command_message = msg.clone();
|
||||
return Ok(EventOutcome::Ok(msg));
|
||||
}
|
||||
KeyEventOutcome::Consumed(None) => {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::Pending => {
|
||||
// Rare in edit mode, but allow multi-key sequences if defined
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
KeyEventOutcome::NotMatched => {
|
||||
// Fall through to client-level actions
|
||||
}
|
||||
return Ok(EventOutcome::Ok(canvas_message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -973,66 +918,6 @@ impl EventHandler {
|
||||
matches!(command, "w" | "q" | "q!" | "wq" | "r")
|
||||
}
|
||||
|
||||
async fn handle_form_canvas_action(
|
||||
&mut self,
|
||||
key_event: KeyEvent,
|
||||
editor: &mut FormEditor<FormState>,
|
||||
config: &Config,
|
||||
is_edit_mode: bool,
|
||||
) -> Result<Option<String>> {
|
||||
use crossterm::event::KeyCode;
|
||||
|
||||
if is_edit_mode {
|
||||
if let KeyCode::Char(c) = key_event.code {
|
||||
if key_event.modifiers.is_empty() || key_event.modifiers == KeyModifiers::SHIFT {
|
||||
editor.insert_char(c)?;
|
||||
return Ok(Some(format!("Inserted '{}'", c)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use your config to resolve actions
|
||||
if let Some(action) = config.get_edit_action_for_key(key_event.code, key_event.modifiers) {
|
||||
match action {
|
||||
"delete_char_backward" => { editor.delete_backward()?; return Ok(Some("Deleted backward".to_string())); }
|
||||
"delete_char_forward" => { editor.delete_forward()?; return Ok(Some("Deleted forward".to_string())); }
|
||||
"move_left" => { editor.move_left()?; return Ok(Some("Moved left".to_string())); }
|
||||
"move_right" => { editor.move_right()?; return Ok(Some("Moved right".to_string())); }
|
||||
"move_up" => { editor.move_up()?; return Ok(Some("Moved up".to_string())); }
|
||||
"move_down" => { editor.move_down()?; return Ok(Some("Moved down".to_string())); }
|
||||
|
||||
"move_line_start" => { editor.move_line_start(); return Ok(Some("Line start".to_string())); }
|
||||
"move_line_end" => { editor.move_line_end(); return Ok(Some("Line end".to_string())); }
|
||||
"move_word_next" => { editor.move_word_next(); return Ok(Some("Next word".to_string())); }
|
||||
"move_word_prev" => { editor.move_word_prev(); return Ok(Some("Prev word".to_string())); }
|
||||
"move_word_end" => { editor.move_word_end(); return Ok(Some("Word end".to_string())); }
|
||||
"move_word_end_prev" => { editor.move_word_end_prev(); return Ok(Some("Prev word end".to_string())); }
|
||||
|
||||
"next_field" => { editor.next_field()?; return Ok(Some("Next field".to_string())); }
|
||||
"prev_field" => { editor.prev_field()?; return Ok(Some("Prev field".to_string())); }
|
||||
"open_suggestions" => {
|
||||
let field_index = editor.current_field();
|
||||
editor.open_suggestions(field_index);
|
||||
return Ok(Some("Opened suggestions".to_string()));
|
||||
}
|
||||
"apply_suggestion" | "enter_decider" => {
|
||||
if let Some(s) = editor.apply_suggestion() {
|
||||
return Ok(Some(format!("Applied suggestion: {}", s)));
|
||||
} else {
|
||||
return Ok(Some("No suggestion applied".to_string()));
|
||||
}
|
||||
}
|
||||
"exit" | "exit_edit_mode" => {
|
||||
editor.exit_edit_mode()?;
|
||||
return Ok(Some("Exited edit mode".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn handle_core_action(
|
||||
&mut self,
|
||||
action: &str,
|
||||
|
||||
Reference in New Issue
Block a user