From 132088440902aaec69a6b014e7b50a960e2f9164 Mon Sep 17 00:00:00 2001 From: Priec Date: Wed, 20 Aug 2025 23:52:14 +0200 Subject: [PATCH] more improvements --- client/Cargo.toml | 2 +- client/src/components/form/form.rs | 44 +++++++++----------- client/src/modes/handlers/event.rs | 65 +++++++++++++++++++----------- client/src/state/app/state.rs | 5 +++ client/src/state/pages/form.rs | 9 ----- 5 files changed, 67 insertions(+), 58 deletions(-) diff --git a/client/Cargo.toml b/client/Cargo.toml index ea6d4ac..878786a 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true anyhow = { workspace = true } async-trait = "0.1.88" common = { path = "../common" } -canvas = { path = "../canvas", features = ["gui", "suggestions"] } +canvas = { path = "../canvas", features = ["gui", "suggestions", "cursor-style"] } ratatui = { workspace = true } crossterm = { workspace = true } diff --git a/client/src/components/form/form.rs b/client/src/components/form/form.rs index 8fdf03a..492d2ef 100644 --- a/client/src/components/form/form.rs +++ b/client/src/components/form/form.rs @@ -1,5 +1,6 @@ // src/components/form/form.rs use crate::config::colors::themes::Theme; +use crate::state::app::state::AppState; use crate::state::pages::form::FormState; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Margin, Rect}, @@ -8,19 +9,17 @@ use ratatui::{ Frame, }; use canvas::canvas::HighlightState; -use canvas::{FormEditor, render_canvas_default, render_canvas, render_suggestions_dropdown, DefaultCanvasTheme}; +use canvas::{ + render_canvas, render_suggestions_dropdown, DefaultCanvasTheme, FormEditor, +}; pub fn render_form( f: &mut Frame, area: Rect, - form_state: &FormState, - fields: &[&str], // no longer needed, FormEditor handles this - current_field_idx: &usize, // no longer needed - inputs: &[&String], // no longer needed + app_state: &AppState, + form_state: &FormState, // not needed directly anymore, editor holds it table_name: &str, theme: &Theme, - is_edit_mode: bool, // FormEditor tracks mode internally - highlight_state: &HighlightState, total_count: u64, current_position: u64, ) { @@ -62,24 +61,19 @@ pub fn render_form( .alignment(Alignment::Left); f.render_widget(count_para, main_layout[0]); - // --- FORM RENDERING (Using new canvas API) --- - let editor = FormEditor::new(form_state.clone()); + // --- FORM RENDERING (Using persistent FormEditor) --- + if let Some(editor) = &app_state.form_editor { + let active_field_rect = render_canvas(f, main_layout[1], editor, theme); - let active_field_rect = render_canvas( - f, - main_layout[1], - &editor, - theme, - ); - - // --- SUGGESTIONS DROPDOWN --- - if let Some(active_rect) = active_field_rect { - render_suggestions_dropdown( - f, - main_layout[1], - active_rect, - &DefaultCanvasTheme, - &editor, - ); + // --- SUGGESTIONS DROPDOWN --- + if let Some(active_rect) = active_field_rect { + render_suggestions_dropdown( + f, + main_layout[1], + active_rect, + &DefaultCanvasTheme, + editor, + ); + } } } diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 5e7d9b5..97ab8fa 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -16,7 +16,7 @@ use crate::modes::{ }; use crate::services::auth::AuthClient; use crate::services::grpc_client::GrpcClient; -use canvas::FormEditor; +use canvas::{FormEditor, AppMode as CanvasMode}; use crate::state::{ app::{ buffer::{AppView, BufferState}, @@ -42,7 +42,6 @@ use crate::ui::handlers::context::UiContext; use crate::ui::handlers::rat_state::UiStateHandler; use anyhow::Result; use common::proto::komp_ac::search::search_response::Hit; -use crossterm::cursor::SetCursorStyle; use crossterm::event::KeyModifiers; use crossterm::event::{Event, KeyCode, KeyEvent}; use tokio::sync::mpsc; @@ -695,10 +694,12 @@ impl EventHandler { 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(); - 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") @@ -734,16 +735,21 @@ impl EventHandler { ); } + 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(); - 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) { + if let Some(editor) = &mut app_state.form_editor { + editor.set_mode(CanvasMode::Command); + } self.command_mode = true; self.command_input.clear(); self.command_message.clear(); @@ -772,14 +778,15 @@ impl EventHandler { // Try canvas action for form first if app_state.ui.show_form { - let mut editor = FormEditor::new(form_state.clone()); - if let Ok(Some(canvas_message)) = self.handle_form_canvas_action( - key_event, - &mut editor, - config, - false, - ).await { - return Ok(EventOutcome::Ok(canvas_message)); + 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)); + } } } @@ -788,9 +795,11 @@ impl EventHandler { AppMode::Highlight => { if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") { + if let Some(editor) = &mut app_state.form_editor { + editor.exit_highlight_mode(); + } self.highlight_state = HighlightState::Off; self.command_message = "Exited highlight mode".to_string(); - terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?; 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 HighlightState::Characterwise { anchor } = self.highlight_state { @@ -827,17 +836,18 @@ impl EventHandler { // Try canvas action for form first if app_state.ui.show_form { - let mut editor = FormEditor::new(form_state.clone()); - if let Ok(Some(canvas_message)) = self.handle_form_canvas_action( - key_event, - &mut editor, - config, - true, - ).await { - if !canvas_message.is_empty() { - self.command_message = canvas_message.clone(); + 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(); + } + return Ok(EventOutcome::Ok(canvas_message)); } - return Ok(EventOutcome::Ok(canvas_message)); } } @@ -850,6 +860,9 @@ impl EventHandler { self.command_message.clear(); self.command_mode = false; self.key_sequence_tracker.reset(); + if let Some(editor) = &mut app_state.form_editor { + editor.set_mode(CanvasMode::ReadOnly); + } return Ok(EventOutcome::Ok( "Exited command mode".to_string(), )); @@ -1079,6 +1092,9 @@ impl EventHandler { } } "force_quit" => { + if let Some(editor) = &mut app_state.form_editor { + editor.cleanup_cursor()?; + } terminal.cleanup()?; Ok(EventOutcome::Exit( "Force exiting without saving.".to_string(), @@ -1106,6 +1122,9 @@ impl EventHandler { SaveOutcome::CreatedNew(_) => "New entry created.".to_string(), } }; + if let Some(editor) = &mut app_state.form_editor { + editor.cleanup_cursor()?; + } terminal.cleanup()?; Ok(EventOutcome::Exit(format!( "{}. Exiting application.", diff --git a/client/src/state/app/state.rs b/client/src/state/app/state.rs index cde8156..0df1a76 100644 --- a/client/src/state/app/state.rs +++ b/client/src/state/app/state.rs @@ -7,6 +7,8 @@ use common::proto::komp_ac::table_structure::TableStructureResponse; use crate::modes::handlers::mode_manager::AppMode; use crate::state::app::search::SearchState; use crate::ui::handlers::context::DialogPurpose; +use canvas::FormEditor; +use crate::state::pages::form::FormState; use std::collections::HashMap; use std::env; use std::sync::Arc; @@ -67,6 +69,8 @@ pub struct AppState { // UI preferences pub ui: UiState, + pub form_editor: Option>, + #[cfg(feature = "ui-debug")] pub debug_state: Option, } @@ -86,6 +90,7 @@ impl AppState { pending_table_structure_fetch: None, search_state: None, ui: UiState::default(), + form_editor: None, #[cfg(feature = "ui-debug")] debug_state: None, diff --git a/client/src/state/pages/form.rs b/client/src/state/pages/form.rs index 8df94d7..f3320a4 100644 --- a/client/src/state/pages/form.rs +++ b/client/src/state/pages/form.rs @@ -228,15 +228,6 @@ impl FormState { self.autocomplete_loading = false; } - // NEW: Add these methods to change modes - pub fn set_edit_mode(&mut self) { - self.app_mode = AppMode::Edit; - } - - pub fn set_readonly_mode(&mut self) { - self.app_mode = AppMode::ReadOnly; - } - // Legacy method compatibility pub fn fields(&self) -> Vec<&str> { self.fields