fixed example, now working everything properly well
This commit is contained in:
@@ -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, _) => {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user