more improvements
This commit is contained in:
@@ -8,7 +8,7 @@ license.workspace = true
|
|||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
async-trait = "0.1.88"
|
async-trait = "0.1.88"
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
canvas = { path = "../canvas", features = ["gui", "suggestions"] }
|
canvas = { path = "../canvas", features = ["gui", "suggestions", "cursor-style"] }
|
||||||
|
|
||||||
ratatui = { workspace = true }
|
ratatui = { workspace = true }
|
||||||
crossterm = { workspace = true }
|
crossterm = { workspace = true }
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// src/components/form/form.rs
|
// src/components/form/form.rs
|
||||||
use crate::config::colors::themes::Theme;
|
use crate::config::colors::themes::Theme;
|
||||||
|
use crate::state::app::state::AppState;
|
||||||
use crate::state::pages::form::FormState;
|
use crate::state::pages::form::FormState;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Constraint, Direction, Layout, Margin, Rect},
|
layout::{Alignment, Constraint, Direction, Layout, Margin, Rect},
|
||||||
@@ -8,19 +9,17 @@ use ratatui::{
|
|||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
use canvas::canvas::HighlightState;
|
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(
|
pub fn render_form(
|
||||||
f: &mut Frame,
|
f: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
form_state: &FormState,
|
app_state: &AppState,
|
||||||
fields: &[&str], // no longer needed, FormEditor handles this
|
form_state: &FormState, // not needed directly anymore, editor holds it
|
||||||
current_field_idx: &usize, // no longer needed
|
|
||||||
inputs: &[&String], // no longer needed
|
|
||||||
table_name: &str,
|
table_name: &str,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
is_edit_mode: bool, // FormEditor tracks mode internally
|
|
||||||
highlight_state: &HighlightState,
|
|
||||||
total_count: u64,
|
total_count: u64,
|
||||||
current_position: u64,
|
current_position: u64,
|
||||||
) {
|
) {
|
||||||
@@ -62,15 +61,9 @@ pub fn render_form(
|
|||||||
.alignment(Alignment::Left);
|
.alignment(Alignment::Left);
|
||||||
f.render_widget(count_para, main_layout[0]);
|
f.render_widget(count_para, main_layout[0]);
|
||||||
|
|
||||||
// --- FORM RENDERING (Using new canvas API) ---
|
// --- FORM RENDERING (Using persistent FormEditor) ---
|
||||||
let editor = FormEditor::new(form_state.clone());
|
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 ---
|
// --- SUGGESTIONS DROPDOWN ---
|
||||||
if let Some(active_rect) = active_field_rect {
|
if let Some(active_rect) = active_field_rect {
|
||||||
@@ -79,7 +72,8 @@ pub fn render_form(
|
|||||||
main_layout[1],
|
main_layout[1],
|
||||||
active_rect,
|
active_rect,
|
||||||
&DefaultCanvasTheme,
|
&DefaultCanvasTheme,
|
||||||
&editor,
|
editor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use crate::modes::{
|
|||||||
};
|
};
|
||||||
use crate::services::auth::AuthClient;
|
use crate::services::auth::AuthClient;
|
||||||
use crate::services::grpc_client::GrpcClient;
|
use crate::services::grpc_client::GrpcClient;
|
||||||
use canvas::FormEditor;
|
use canvas::{FormEditor, AppMode as CanvasMode};
|
||||||
use crate::state::{
|
use crate::state::{
|
||||||
app::{
|
app::{
|
||||||
buffer::{AppView, BufferState},
|
buffer::{AppView, BufferState},
|
||||||
@@ -42,7 +42,6 @@ use crate::ui::handlers::context::UiContext;
|
|||||||
use crate::ui::handlers::rat_state::UiStateHandler;
|
use crate::ui::handlers::rat_state::UiStateHandler;
|
||||||
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::cursor::SetCursorStyle;
|
|
||||||
use crossterm::event::KeyModifiers;
|
use crossterm::event::KeyModifiers;
|
||||||
use crossterm::event::{Event, KeyCode, KeyEvent};
|
use crossterm::event::{Event, KeyCode, KeyEvent};
|
||||||
use tokio::sync::mpsc;
|
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")
|
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)
|
&& 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.is_edit_mode = true;
|
||||||
self.edit_mode_cooldown = true;
|
self.edit_mode_cooldown = true;
|
||||||
self.command_message = "Edit mode".to_string();
|
self.command_message = "Edit mode".to_string();
|
||||||
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
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")
|
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.is_edit_mode = true;
|
||||||
self.edit_mode_cooldown = true;
|
self.edit_mode_cooldown = true;
|
||||||
app_state.ui.focus_outside_canvas = false;
|
app_state.ui.focus_outside_canvas = false;
|
||||||
self.command_message = "Edit mode (after cursor)".to_string();
|
self.command_message = "Edit mode (after cursor)".to_string();
|
||||||
terminal.set_cursor_style(SetCursorStyle::BlinkingBar)?;
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
}
|
}
|
||||||
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode")
|
else if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_command_mode")
|
||||||
&& ModeManager::can_enter_command_mode(current_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_mode = true;
|
||||||
self.command_input.clear();
|
self.command_input.clear();
|
||||||
self.command_message.clear();
|
self.command_message.clear();
|
||||||
@@ -772,25 +778,28 @@ impl EventHandler {
|
|||||||
|
|
||||||
// Try canvas action for form first
|
// Try canvas action for form first
|
||||||
if app_state.ui.show_form {
|
if app_state.ui.show_form {
|
||||||
let mut editor = FormEditor::new(form_state.clone());
|
if let Some(editor) = &mut app_state.form_editor {
|
||||||
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
|
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
|
||||||
key_event,
|
key_event,
|
||||||
&mut editor,
|
editor,
|
||||||
config,
|
config,
|
||||||
false,
|
false,
|
||||||
).await {
|
).await {
|
||||||
return Ok(EventOutcome::Ok(canvas_message));
|
return Ok(EventOutcome::Ok(canvas_message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
AppMode::Highlight => {
|
AppMode::Highlight => {
|
||||||
if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") {
|
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.highlight_state = HighlightState::Off;
|
||||||
self.command_message = "Exited highlight mode".to_string();
|
self.command_message = "Exited highlight mode".to_string();
|
||||||
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
} else if config.get_highlight_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") {
|
} else if config.get_highlight_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise") {
|
||||||
if let HighlightState::Characterwise { anchor } = self.highlight_state {
|
if let HighlightState::Characterwise { anchor } = self.highlight_state {
|
||||||
@@ -827,10 +836,10 @@ impl EventHandler {
|
|||||||
|
|
||||||
// Try canvas action for form first
|
// Try canvas action for form first
|
||||||
if app_state.ui.show_form {
|
if app_state.ui.show_form {
|
||||||
let mut editor = FormEditor::new(form_state.clone());
|
if let Some(editor) = &mut app_state.form_editor {
|
||||||
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
|
if let Ok(Some(canvas_message)) = self.handle_form_canvas_action(
|
||||||
key_event,
|
key_event,
|
||||||
&mut editor,
|
editor,
|
||||||
config,
|
config,
|
||||||
true,
|
true,
|
||||||
).await {
|
).await {
|
||||||
@@ -840,6 +849,7 @@ impl EventHandler {
|
|||||||
return Ok(EventOutcome::Ok(canvas_message));
|
return Ok(EventOutcome::Ok(canvas_message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
}
|
}
|
||||||
@@ -850,6 +860,9 @@ impl EventHandler {
|
|||||||
self.command_message.clear();
|
self.command_message.clear();
|
||||||
self.command_mode = false;
|
self.command_mode = false;
|
||||||
self.key_sequence_tracker.reset();
|
self.key_sequence_tracker.reset();
|
||||||
|
if let Some(editor) = &mut app_state.form_editor {
|
||||||
|
editor.set_mode(CanvasMode::ReadOnly);
|
||||||
|
}
|
||||||
return Ok(EventOutcome::Ok(
|
return Ok(EventOutcome::Ok(
|
||||||
"Exited command mode".to_string(),
|
"Exited command mode".to_string(),
|
||||||
));
|
));
|
||||||
@@ -1079,6 +1092,9 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"force_quit" => {
|
"force_quit" => {
|
||||||
|
if let Some(editor) = &mut app_state.form_editor {
|
||||||
|
editor.cleanup_cursor()?;
|
||||||
|
}
|
||||||
terminal.cleanup()?;
|
terminal.cleanup()?;
|
||||||
Ok(EventOutcome::Exit(
|
Ok(EventOutcome::Exit(
|
||||||
"Force exiting without saving.".to_string(),
|
"Force exiting without saving.".to_string(),
|
||||||
@@ -1106,6 +1122,9 @@ impl EventHandler {
|
|||||||
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
SaveOutcome::CreatedNew(_) => "New entry created.".to_string(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if let Some(editor) = &mut app_state.form_editor {
|
||||||
|
editor.cleanup_cursor()?;
|
||||||
|
}
|
||||||
terminal.cleanup()?;
|
terminal.cleanup()?;
|
||||||
Ok(EventOutcome::Exit(format!(
|
Ok(EventOutcome::Exit(format!(
|
||||||
"{}. Exiting application.",
|
"{}. Exiting application.",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use common::proto::komp_ac::table_structure::TableStructureResponse;
|
|||||||
use crate::modes::handlers::mode_manager::AppMode;
|
use crate::modes::handlers::mode_manager::AppMode;
|
||||||
use crate::state::app::search::SearchState;
|
use crate::state::app::search::SearchState;
|
||||||
use crate::ui::handlers::context::DialogPurpose;
|
use crate::ui::handlers::context::DialogPurpose;
|
||||||
|
use canvas::FormEditor;
|
||||||
|
use crate::state::pages::form::FormState;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -67,6 +69,8 @@ pub struct AppState {
|
|||||||
// UI preferences
|
// UI preferences
|
||||||
pub ui: UiState,
|
pub ui: UiState,
|
||||||
|
|
||||||
|
pub form_editor: Option<FormEditor<FormState>>,
|
||||||
|
|
||||||
#[cfg(feature = "ui-debug")]
|
#[cfg(feature = "ui-debug")]
|
||||||
pub debug_state: Option<DebugState>,
|
pub debug_state: Option<DebugState>,
|
||||||
}
|
}
|
||||||
@@ -86,6 +90,7 @@ impl AppState {
|
|||||||
pending_table_structure_fetch: None,
|
pending_table_structure_fetch: None,
|
||||||
search_state: None,
|
search_state: None,
|
||||||
ui: UiState::default(),
|
ui: UiState::default(),
|
||||||
|
form_editor: None,
|
||||||
|
|
||||||
#[cfg(feature = "ui-debug")]
|
#[cfg(feature = "ui-debug")]
|
||||||
debug_state: None,
|
debug_state: None,
|
||||||
|
|||||||
@@ -228,15 +228,6 @@ impl FormState {
|
|||||||
self.autocomplete_loading = false;
|
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
|
// Legacy method compatibility
|
||||||
pub fn fields(&self) -> Vec<&str> {
|
pub fn fields(&self) -> Vec<&str> {
|
||||||
self.fields
|
self.fields
|
||||||
|
|||||||
Reference in New Issue
Block a user