fixed example, now working everything properly well

This commit is contained in:
Priec
2025-08-07 23:30:31 +02:00
parent d3e5418221
commit 8e3c85991c
3 changed files with 85 additions and 56 deletions

View File

@@ -217,6 +217,16 @@ impl<D: DataProvider> AutoCursorFormEditor<D> {
Ok(result?) Ok(result?)
} }
// === SUGGESTIONS CONTROL WRAPPERS ===
fn open_suggestions(&mut self, field_index: usize) {
self.editor.open_suggestions(field_index);
}
fn close_suggestions(&mut self) {
self.editor.close_suggestions();
}
// === MODE TRANSITIONS WITH AUTOMATIC CURSOR MANAGEMENT === // === MODE TRANSITIONS WITH AUTOMATIC CURSOR MANAGEMENT ===
fn enter_edit_mode(&mut self) { fn enter_edit_mode(&mut self) {
@@ -541,33 +551,21 @@ async fn handle_key_press(
match (mode, key, modifiers) { match (mode, key, modifiers) {
// === SUGGESTIONS HANDLING === // === SUGGESTIONS HANDLING ===
// Tab: Trigger or navigate suggestions
(_, KeyCode::Tab, _) => { (_, KeyCode::Tab, _) => {
if editor.is_suggestions_active() { if editor.is_suggestions_active() {
// Cycle through suggestions
editor.suggestions_next(); editor.suggestions_next();
editor.set_debug_message("📍 Next suggestion".to_string()); editor.set_debug_message("📍 Next suggestion".to_string());
} else if editor.data_provider().supports_suggestions(editor.current_field()) { } else if editor.data_provider().supports_suggestions(editor.current_field()) {
let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; // Open suggestions explicitly
let field_name = field_names.get(editor.current_field()).unwrap_or(&"Unknown"); editor.open_suggestions(editor.current_field());
match editor.trigger_suggestions(suggestions_provider).await { match editor.trigger_suggestions(suggestions_provider).await {
Ok(_) => { Ok(_) => {
let current_text = editor.current_text();
if editor.suggestions().is_empty() {
if current_text.is_empty() {
editor.set_debug_message(format!("🔍 No {} suggestions available", field_name.to_lowercase()));
} else {
editor.set_debug_message(format!("🔍 No {} matches for '{}'", field_name.to_lowercase(), current_text));
}
} else {
if current_text.is_empty() {
editor.set_debug_message(format!("{} {} suggestions!", editor.suggestions().len(), field_name.to_lowercase()));
} else {
editor.set_debug_message(format!("{} {} matches for '{}'!", editor.suggestions().len(), field_name.to_lowercase(), current_text));
}
}
editor.update_inline_completion(); editor.update_inline_completion();
editor.set_debug_message(format!(
"{} suggestions loaded",
editor.suggestions().len()
));
} }
Err(e) => { Err(e) => {
editor.set_debug_message(format!("❌ Suggestion error: {}", e)); editor.set_debug_message(format!("❌ Suggestion error: {}", e));
@@ -595,6 +593,26 @@ async fn handle_key_press(
} }
} }
// Escape: Close suggestions or exit mode
(_, KeyCode::Esc, _) => {
if editor.is_suggestions_active() {
editor.close_suggestions();
editor.set_debug_message("❌ Suggestions closed".to_string());
} else {
match mode {
AppMode::Edit => {
editor.exit_edit_mode();
}
AppMode::Highlight => {
editor.exit_visual_mode();
}
_ => {
editor.clear_command_buffer();
}
}
}
}
// === MODE TRANSITIONS WITH AUTOMATIC CURSOR MANAGEMENT === // === MODE TRANSITIONS WITH AUTOMATIC CURSOR MANAGEMENT ===
(AppMode::ReadOnly, KeyCode::Char('i'), _) => { (AppMode::ReadOnly, KeyCode::Char('i'), _) => {
editor.enter_edit_mode(); // 🎯 Automatic: cursor becomes bar | editor.enter_edit_mode(); // 🎯 Automatic: cursor becomes bar |
@@ -628,22 +646,6 @@ async fn handle_key_press(
editor.clear_command_buffer(); editor.clear_command_buffer();
} }
// Escape: Exit any mode back to normal (and cancel suggestions)
(_, KeyCode::Esc, _) => {
match mode {
AppMode::Edit => {
editor.exit_edit_mode(); // Exit insert mode (suggestions auto-cancelled)
}
AppMode::Highlight => {
editor.exit_visual_mode(); // Exit visual mode
}
_ => {
// Already in normal mode, just clear command buffer
editor.clear_command_buffer();
}
}
}
// === CURSOR MANAGEMENT DEMONSTRATION === // === CURSOR MANAGEMENT DEMONSTRATION ===
(AppMode::ReadOnly, KeyCode::F(1), _) => { (AppMode::ReadOnly, KeyCode::F(1), _) => {
editor.demo_manual_cursor_control()?; editor.demo_manual_cursor_control()?;
@@ -669,37 +671,21 @@ async fn handle_key_press(
} }
(AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('j'), _) (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('j'), _)
| (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Down, _) => { | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Down, _) => {
editor.close_suggestions(); // ⬅ close dropdown
editor.move_down(); editor.move_down();
let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_names = ["Fruit", "Job", "Language", "Country", "Color"];
let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field");
editor.set_debug_message(format!("↓ moved to {} field", field_name)); editor.set_debug_message(format!("↓ moved to {} field", field_name));
editor.clear_command_buffer(); editor.clear_command_buffer();
// Auto-show suggestions when entering a suggestion-enabled field with existing text
if editor.data_provider().supports_suggestions(editor.current_field()) {
let current_text = editor.current_text();
if !current_text.is_empty() {
let _ = editor.trigger_suggestions(suggestions_provider).await;
editor.update_inline_completion();
}
}
} }
(AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('k'), _) (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Char('k'), _)
| (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Up, _) => { | (AppMode::ReadOnly | AppMode::Highlight, KeyCode::Up, _) => {
editor.close_suggestions(); // ⬅ close dropdown
editor.move_up(); editor.move_up();
let field_names = ["Fruit", "Job", "Language", "Country", "Color"]; let field_names = ["Fruit", "Job", "Language", "Country", "Color"];
let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field"); let field_name = field_names.get(editor.current_field()).unwrap_or(&"Field");
editor.set_debug_message(format!("↑ moved to {} field", field_name)); editor.set_debug_message(format!("↑ moved to {} field", field_name));
editor.clear_command_buffer(); editor.clear_command_buffer();
// Auto-show suggestions when entering a suggestion-enabled field with existing text
if editor.data_provider().supports_suggestions(editor.current_field()) {
let current_text = editor.current_text();
if !current_text.is_empty() {
let _ = editor.trigger_suggestions(suggestions_provider).await;
editor.update_inline_completion();
}
}
} }
// Word movement // Word movement
@@ -765,9 +751,11 @@ async fn handle_key_press(
editor.move_right(); editor.move_right();
} }
(AppMode::Edit, KeyCode::Up, _) => { (AppMode::Edit, KeyCode::Up, _) => {
editor.close_suggestions();
editor.move_up(); editor.move_up();
} }
(AppMode::Edit, KeyCode::Down, _) => { (AppMode::Edit, KeyCode::Down, _) => {
editor.close_suggestions();
editor.move_down(); editor.move_down();
} }
(AppMode::Edit, KeyCode::Home, _) => { (AppMode::Edit, KeyCode::Home, _) => {

View File

@@ -134,7 +134,12 @@ impl EditorState {
} }
} }
pub(crate) fn set_cursor(&mut self, position: usize, max_position: usize, for_edit_mode: bool) { pub(crate) fn set_cursor(
&mut self,
position: usize,
max_position: usize,
for_edit_mode: bool,
) {
if for_edit_mode { if for_edit_mode {
// Edit mode: can go past end for insertion // Edit mode: can go past end for insertion
self.cursor_pos = position.min(max_position); self.cursor_pos = position.min(max_position);
@@ -145,6 +150,7 @@ impl EditorState {
self.ideal_cursor_column = self.cursor_pos; self.ideal_cursor_column = self.cursor_pos;
} }
/// Legacy internal activation (still used internally if needed)
pub(crate) fn activate_suggestions(&mut self, field_index: usize) { pub(crate) fn activate_suggestions(&mut self, field_index: usize) {
self.suggestions.is_active = true; self.suggestions.is_active = true;
self.suggestions.is_loading = true; self.suggestions.is_loading = true;
@@ -153,6 +159,7 @@ impl EditorState {
self.suggestions.completion_text = None; self.suggestions.completion_text = None;
} }
/// Legacy internal deactivation
pub(crate) fn deactivate_suggestions(&mut self) { pub(crate) fn deactivate_suggestions(&mut self) {
self.suggestions.is_active = false; self.suggestions.is_active = false;
self.suggestions.is_loading = false; self.suggestions.is_loading = false;
@@ -160,6 +167,24 @@ impl EditorState {
self.suggestions.selected_index = None; self.suggestions.selected_index = None;
self.suggestions.completion_text = None; self.suggestions.completion_text = None;
} }
/// Explicitly open suggestions — should only be called on Tab
pub(crate) fn open_suggestions(&mut self, field_index: usize) {
self.suggestions.is_active = true;
self.suggestions.is_loading = true;
self.suggestions.active_field = Some(field_index);
self.suggestions.selected_index = None;
self.suggestions.completion_text = None;
}
/// Explicitly close suggestions — should be called on Esc or field change
pub(crate) fn close_suggestions(&mut self) {
self.suggestions.is_active = false;
self.suggestions.is_loading = false;
self.suggestions.active_field = None;
self.suggestions.selected_index = None;
self.suggestions.completion_text = None;
}
} }
impl Default for EditorState { impl Default for EditorState {

View File

@@ -152,6 +152,22 @@ impl<D: DataProvider> FormEditor<D> {
&self.ui_state &self.ui_state
} }
/// Mutable access to UI state for internal crate use only.
pub(crate) fn ui_state_mut(&mut self) -> &mut EditorState {
&mut self.ui_state
}
/// Open the suggestions UI for `field_index` (UI-only; does not fetch).
pub fn open_suggestions(&mut self, field_index: usize) {
self.ui_state.open_suggestions(field_index);
}
/// Close suggestions UI and clear the current suggestion results.
pub fn close_suggestions(&mut self) {
self.ui_state.close_suggestions();
self.suggestions.clear();
}
/// Set external validation state for a field (Feature 5) /// Set external validation state for a field (Feature 5)
#[cfg(feature = "validation")] #[cfg(feature = "validation")]
pub fn set_external_validation( pub fn set_external_validation(