canvasstate is now officially nonexistent as dep

This commit is contained in:
Priec
2025-07-30 19:14:35 +02:00
parent e4982f871f
commit 72c38f613f
10 changed files with 126 additions and 192 deletions

View File

@@ -3,7 +3,7 @@ use crate::config::colors::themes::Theme;
use crate::state::app::highlight::HighlightState;
use crate::state::app::state::AppState;
use crate::state::pages::add_table::{AddTableFocus, AddTableState};
use canvas::canvas::{render_canvas, CanvasState, HighlightState as CanvasHighlightState}; // Use canvas library
use canvas::canvas::{render_canvas, CanvasState, HighlightState as CanvasHighlightState};
use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Modifier, Style},

View File

@@ -9,43 +9,14 @@ use ratatui::{
};
use crate::config::colors::themes::Theme;
use crate::state::app::highlight::HighlightState;
use crate::state::pages::canvas_state::CanvasState as LegacyCanvasState;
use canvas::canvas::CanvasState as LibraryCanvasState;
use canvas::canvas::CanvasState;
use std::cmp::{max, min};
/// Render canvas for legacy CanvasState (AddTableState, LoginState, RegisterState, AddLogicState)
/// Render canvas (FormState)
pub fn render_canvas(
f: &mut Frame,
area: Rect,
form_state: &impl LegacyCanvasState,
fields: &[&str],
current_field_idx: &usize,
inputs: &[&String],
theme: &Theme,
is_edit_mode: bool,
highlight_state: &HighlightState,
) -> Option<Rect> {
render_canvas_impl(
f,
area,
fields,
current_field_idx,
inputs,
theme,
is_edit_mode,
highlight_state,
form_state.current_cursor_pos(),
form_state.has_unsaved_changes(),
|i| form_state.get_display_value_for_field(i).to_string(),
|i| form_state.has_display_override(i),
)
}
/// Render canvas for library CanvasState (FormState)
pub fn render_canvas_library(
f: &mut Frame,
area: Rect,
form_state: &impl LibraryCanvasState,
form_state: &impl CanvasState,
fields: &[&str],
current_field_idx: &usize,
inputs: &[&String],

View File

@@ -5,7 +5,6 @@ use crate::config::binds::key_sequences::KeySequenceTracker;
use crate::services::grpc_client::GrpcClient;
use crate::state::pages::auth::LoginState;
use crate::state::pages::auth::RegisterState;
use crate::state::pages::canvas_state::CanvasState as LocalCanvasState;
use crate::state::pages::form::FormState;
use crate::state::pages::add_logic::AddLogicState;
use crate::state::pages::add_table::AddTableState;

View File

@@ -1,4 +1,3 @@
// src/modes/handlers.rs
pub mod event;
pub mod event_helper;
pub mod mode_manager;

View File

@@ -15,23 +15,20 @@ 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::{canvas::CanvasAction, dispatcher::ActionDispatcher};
use canvas::canvas::CanvasState as LibraryCanvasState;
use super::event_helper::*;
use canvas::canvas::CanvasState; // Only need this import now
use crate::state::{
app::{
buffer::{AppView, BufferState},
highlight::HighlightState,
search::SearchState, // Correctly imported
search::SearchState,
state::AppState,
},
pages::{
admin::AdminState,
auth::{AuthState, LoginState, RegisterState},
canvas_state::CanvasState,
form::FormState,
intro::IntroState,
},
@@ -89,7 +86,6 @@ pub struct EventHandler {
pub navigation_state: NavigationState,
pub search_result_sender: mpsc::UnboundedSender<Vec<Hit>>,
pub search_result_receiver: mpsc::UnboundedReceiver<Vec<Hit>>,
// --- ADDED FOR LIVE AUTOCOMPLETE ---
pub autocomplete_result_sender: mpsc::UnboundedSender<Vec<Hit>>,
pub autocomplete_result_receiver: mpsc::UnboundedReceiver<Vec<Hit>>,
}
@@ -103,7 +99,7 @@ impl EventHandler {
grpc_client: GrpcClient,
) -> Result<Self> {
let (search_tx, search_rx) = unbounded_channel();
let (autocomplete_tx, autocomplete_rx) = unbounded_channel(); // ADDED
let (autocomplete_tx, autocomplete_rx) = unbounded_channel();
Ok(EventHandler {
command_mode: false,
command_input: String::new(),
@@ -122,7 +118,6 @@ impl EventHandler {
navigation_state: NavigationState::new(),
search_result_sender: search_tx,
search_result_receiver: search_rx,
// --- ADDED ---
autocomplete_result_sender: autocomplete_tx,
autocomplete_result_receiver: autocomplete_rx,
})
@@ -136,6 +131,95 @@ impl EventHandler {
self.navigation_state.activate_find_file(options);
}
// Helper functions - replace the removed event_helper functions
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()
} else if app_state.ui.show_register {
register_state.current_field()
} else {
form_state.current_field()
}
}
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()
} else if app_state.ui.show_register {
register_state.current_cursor_pos()
} else {
form_state.current_cursor_pos()
}
}
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()
} else if app_state.ui.show_register {
register_state.has_unsaved_changes()
} else {
form_state.has_unsaved_changes()
}
}
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()
} else if app_state.ui.show_register {
register_state.get_current_input()
} else {
form_state.get_current_input()
}
}
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);
} else if app_state.ui.show_register {
register_state.set_current_cursor_pos(pos);
} else {
form_state.set_current_cursor_pos(pos);
}
}
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()
} else {
form_state.current_cursor_pos()
}
}
// This function handles state changes.
async fn handle_search_palette_event(
&mut self,
@@ -199,7 +283,6 @@ impl EventHandler {
_ => {}
}
// --- START CORRECTED LOGIC ---
if trigger_search {
search_state.is_loading = true;
search_state.results.clear();
@@ -214,7 +297,6 @@ impl EventHandler {
"--- 1. Spawning search task for query: '{}' ---",
query
);
// We now move the grpc_client into the task, just like with login.
tokio::spawn(async move {
info!("--- 2. Background task started. ---");
match grpc_client.search_table(table_name, query).await {
@@ -226,7 +308,6 @@ impl EventHandler {
let _ = sender.send(response.hits);
}
Err(e) => {
// THE FIX: Use the debug formatter `{:?}` to print the full error chain.
error!("--- 3b. gRPC call failed: {:?} ---", e);
let _ = sender.send(vec![]);
}
@@ -235,8 +316,6 @@ impl EventHandler {
}
}
// The borrow on `app_state.search_state` ends here.
// Now we can safely modify the Option itself.
if should_close {
app_state.search_state = None;
app_state.ui.show_search_palette = false;
@@ -264,7 +343,6 @@ impl EventHandler {
) -> Result<EventOutcome> {
if app_state.ui.show_search_palette {
if let Event::Key(key_event) = event {
// The call no longer passes grpc_client
return self
.handle_search_palette_event(
key_event,
@@ -581,7 +659,7 @@ impl EventHandler {
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(
let current_field_index = Self::get_current_field_for_state(
app_state,
login_state,
register_state,
@@ -596,13 +674,13 @@ impl EventHandler {
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(
let current_field_index = Self::get_current_field_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_current_cursor_pos_for_state(
let current_cursor_pos = Self::get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
@@ -627,13 +705,13 @@ impl EventHandler {
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(
let current_input = Self::get_current_input_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_cursor_pos_for_mixed_state(
let current_cursor_pos = Self::get_cursor_pos_for_mixed_state(
app_state,
login_state,
form_state
@@ -642,14 +720,14 @@ impl EventHandler {
// Move cursor forward if possible
if !current_input.is_empty() && current_cursor_pos < current_input.len() {
let new_cursor_pos = current_cursor_pos + 1;
set_current_cursor_pos_for_state(
Self::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(
self.ideal_cursor_column = Self::get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
@@ -694,13 +772,13 @@ impl EventHandler {
}
}
// Try canvas action for form first (NEW: Canvas library integration)
// Try canvas action for form first
if app_state.ui.show_form {
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
key_event,
config,
form_state,
false, // not edit mode
false,
).await {
return Ok(EventOutcome::Ok(canvas_message));
}
@@ -753,7 +831,7 @@ impl EventHandler {
&mut admin_state.add_table_state,
&mut admin_state.add_logic_state,
&mut self.key_sequence_tracker,
&mut self.grpc_client, // <-- FIX 2
&mut self.grpc_client,
&mut self.command_message,
&mut self.edit_mode_cooldown,
&mut self.ideal_cursor_column,
@@ -784,13 +862,13 @@ impl EventHandler {
}
}
// Try canvas action for form first (NEW: Canvas library integration)
// Try canvas action for form first
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
true,
).await {
if !canvas_message.is_empty() {
self.command_message = canvas_message.clone();
@@ -823,7 +901,7 @@ impl EventHandler {
self.edit_mode_cooldown = true;
// Check for unsaved changes across all states
let has_changes = get_has_unsaved_changes_for_state(
let has_changes = Self::get_has_unsaved_changes_for_state(
app_state,
login_state,
register_state,
@@ -840,13 +918,13 @@ impl EventHandler {
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
// Get current input and cursor position
let current_input = get_current_input_for_state(
let current_input = Self::get_current_input_for_state(
app_state,
login_state,
register_state,
form_state
);
let current_cursor_pos = get_current_cursor_pos_for_state(
let current_cursor_pos = Self::get_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
@@ -856,7 +934,7 @@ impl EventHandler {
// 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;
set_current_cursor_pos_for_state(
Self::set_current_cursor_pos_for_state(
app_state,
login_state,
register_state,
@@ -906,7 +984,7 @@ impl EventHandler {
form_state,
&mut self.command_input,
&mut self.command_message,
&mut self.grpc_client, // <-- FIX 5
&mut self.grpc_client,
command_handler,
terminal,
&mut current_position,
@@ -1024,11 +1102,10 @@ impl EventHandler {
async fn handle_form_canvas_action(
&mut self,
key_event: KeyEvent,
_config: &Config, // Not used anymore - canvas has its own config
_config: &Config,
form_state: &mut FormState,
is_edit_mode: bool,
) -> Result<Option<String>> {
// Load canvas config (canvas_config.toml or vim defaults)
let canvas_config = canvas::config::CanvasConfig::load();
// Handle suggestion actions first if suggestions are active
@@ -1083,7 +1160,6 @@ impl EventHandler {
}
}
// FIXED: Use canvas config instead of client config
let action_str = canvas_config.get_action_for_key(
key_event.code,
key_event.modifiers,
@@ -1092,9 +1168,8 @@ impl EventHandler {
);
if let Some(action_str) = action_str {
// Filter out mode transition actions - let legacy handlers deal with these
if Self::is_mode_transition_action(action_str) {
return Ok(None); // Let legacy handler handle mode transitions
return Ok(None);
}
let canvas_action = CanvasAction::from_string(&action_str);
@@ -1131,7 +1206,6 @@ impl EventHandler {
} else {
// In read-only mode, only handle non-character keys
let canvas_action = match key_event.code {
// Only handle special keys that don't conflict with vim bindings
KeyCode::Left => Some(CanvasAction::MoveLeft),
KeyCode::Right => Some(CanvasAction::MoveRight),
KeyCode::Up => Some(CanvasAction::MoveUp),
@@ -1164,7 +1238,6 @@ impl EventHandler {
Ok(None)
}
// ADDED: Helper function to identify mode transition actions
fn is_mode_transition_action(action: &str) -> bool {
matches!(action,
"exit" |
@@ -1181,11 +1254,11 @@ impl EventHandler {
"force_quit" |
"save_and_quit" |
"revert" |
"enter_decider" | // This is also handled specially by legacy system
"trigger_autocomplete" | // This is handled specially by legacy system
"suggestion_up" | // These are handled above in suggestion logic
"enter_decider" |
"trigger_autocomplete" |
"suggestion_up" |
"suggestion_down" |
"previous_entry" | // Navigation between records
"previous_entry" |
"next_entry" |
"toggle_sidebar" |
"toggle_buffer_list" |

View File

@@ -1,105 +0,0 @@
// 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::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
}
}

View File

@@ -16,11 +16,10 @@ use crate::components::{
};
use crate::config::colors::themes::Theme;
use crate::modes::general::command_navigation::NavigationState;
use crate::state::pages::canvas_state::CanvasState as LocalCanvasState; // Keep local one with alias
use canvas::canvas::CanvasState; // Import external library's CanvasState trait
use canvas::canvas::CanvasState;
use crate::state::app::buffer::BufferState;
use crate::state::app::highlight::HighlightState as LocalHighlightState; // CHANGED: Alias local version
use canvas::canvas::HighlightState as CanvasHighlightState; // CHANGED: Import canvas version with alias
use crate::state::app::highlight::HighlightState as LocalHighlightState;
use canvas::canvas::HighlightState as CanvasHighlightState;
use crate::state::app::state::AppState;
use crate::state::pages::admin::AdminState;
use crate::state::pages::auth::AuthState;

View File

@@ -8,9 +8,8 @@ use crate::config::storage::storage::load_auth_data;
use crate::modes::common::commands::CommandHandler;
use crate::modes::handlers::event::{EventHandler, EventOutcome};
use crate::modes::handlers::mode_manager::{AppMode, ModeManager};
use crate::state::pages::canvas_state::CanvasState as LocalCanvasState; // Keep local one with alias
use canvas::canvas::CanvasState; // Import external library's CanvasState trait
use crate::state::pages::form::{FormState, FieldDefinition}; // Import FieldDefinition
use canvas::canvas::CanvasState; // Only external library import
use crate::state::pages::form::{FormState, FieldDefinition};
use crate::state::pages::auth::AuthState;
use crate::state::pages::auth::LoginState;
use crate::state::pages::auth::RegisterState;

View File

@@ -2,8 +2,7 @@
use rstest::{fixture, rstest};
use std::collections::HashMap;
use client::state::pages::form::{FormState, FieldDefinition};
use canvas::state::CanvasState
use client::state::pages::canvas_state::CanvasState;
use canvas::canvas::CanvasState;
#[fixture]
fn test_form_state() -> FormState {

View File

@@ -2,7 +2,7 @@
pub use rstest::{fixture, rstest};
pub use client::services::grpc_client::GrpcClient;
pub use client::state::pages::form::FormState;
pub use client::state::pages::canvas_state::CanvasState;
pub use canvas::canvas::CanvasState;
pub use prost_types::Value;
pub use prost_types::value::Kind;
pub use std::collections::HashMap;