working autocomplete, need more fixes soon

This commit is contained in:
filipriec
2025-05-26 11:54:28 +02:00
parent 116db3566f
commit 3463a52960
3 changed files with 346 additions and 25 deletions

View File

@@ -21,13 +21,217 @@ pub fn handle_add_logic_navigation(
add_logic_state: &mut AddLogicState,
is_edit_mode: &mut bool,
buffer_state: &mut BufferState,
grpc_client: GrpcClient,
save_logic_sender: SaveLogicResultSender,
_grpc_client: GrpcClient,
_save_logic_sender: SaveLogicResultSender,
command_message: &mut String,
) -> bool {
// === FULLSCREEN SCRIPT EDITING - COMPLETE ISOLATION ===
if add_logic_state.current_focus == AddLogicFocus::InsideScriptContent {
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
// === AUTOCOMPLETE HANDLING ===
if add_logic_state.script_editor_autocomplete_active {
match key_event.code {
KeyCode::Char(c) if c.is_alphanumeric() || c == '_' => {
// Update filter text first
add_logic_state.script_editor_filter_text.push(c);
add_logic_state.update_script_editor_suggestions();
// Then handle editor input
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
} // Drop editor borrow
*command_message = format!("Filtering: @{}", add_logic_state.script_editor_filter_text);
return true;
}
KeyCode::Backspace => {
if !add_logic_state.script_editor_filter_text.is_empty() {
// Remove last character from filter
add_logic_state.script_editor_filter_text.pop();
add_logic_state.update_script_editor_suggestions();
// Then handle editor input
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
} // Drop editor borrow
*command_message = if add_logic_state.script_editor_filter_text.is_empty() {
"Autocomplete: @".to_string()
} else {
format!("Filtering: @{}", add_logic_state.script_editor_filter_text)
};
} else {
// Check if we're deleting the @ trigger
let should_deactivate = if let Some((trigger_line, trigger_col)) = add_logic_state.script_editor_trigger_position {
let current_cursor = {
let editor_borrow = add_logic_state.script_content_editor.borrow();
editor_borrow.cursor()
};
current_cursor.0 == trigger_line && current_cursor.1 == trigger_col + 1
} else {
false
};
if should_deactivate {
add_logic_state.deactivate_script_editor_autocomplete();
*command_message = "Autocomplete cancelled".to_string();
}
// Handle editor input
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
} // Drop editor borrow
}
return true;
}
KeyCode::Tab | KeyCode::Down => {
// Navigate suggestions down
if !add_logic_state.script_editor_suggestions.is_empty() {
let current = add_logic_state.script_editor_selected_suggestion_index.unwrap_or(0);
let next = (current + 1) % add_logic_state.script_editor_suggestions.len();
add_logic_state.script_editor_selected_suggestion_index = Some(next);
*command_message = format!("Selected: {}", add_logic_state.script_editor_suggestions[next]);
}
return true; // Consume the key
}
KeyCode::Up => {
// Navigate suggestions up
if !add_logic_state.script_editor_suggestions.is_empty() {
let current = add_logic_state.script_editor_selected_suggestion_index.unwrap_or(0);
let prev = if current == 0 {
add_logic_state.script_editor_suggestions.len() - 1
} else {
current - 1
};
add_logic_state.script_editor_selected_suggestion_index = Some(prev);
*command_message = format!("Selected: {}", add_logic_state.script_editor_suggestions[prev]);
}
return true; // Consume the key
}
KeyCode::Enter => {
// Select current suggestion
if let Some(selected_idx) = add_logic_state.script_editor_selected_suggestion_index {
if let Some(suggestion) = add_logic_state.script_editor_suggestions.get(selected_idx).cloned() {
// Get trigger position and filter length
let trigger_pos = add_logic_state.script_editor_trigger_position;
let filter_len = add_logic_state.script_editor_filter_text.len();
// Deactivate autocomplete first
add_logic_state.deactivate_script_editor_autocomplete();
add_logic_state.has_unsaved_changes = true;
// Then replace text
if let Some(pos) = trigger_pos {
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
replace_autocomplete_text(
&mut editor_borrow,
pos,
filter_len,
&suggestion,
);
}
*command_message = format!("Inserted: {}", suggestion);
return true; // Consume the key
}
}
// If no suggestion selected, pass Enter to editor
add_logic_state.deactivate_script_editor_autocomplete();
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
}
return true;
}
KeyCode::Esc => {
// Cancel autocomplete first
add_logic_state.deactivate_script_editor_autocomplete();
*command_message = "Autocomplete cancelled".to_string();
// Then handle normal Esc behavior (vim mode, exit script, etc.)
// Fall through to normal Esc handling below
}
_ => {
// Other keys deactivate autocomplete and pass through
add_logic_state.deactivate_script_editor_autocomplete();
*command_message = "Autocomplete cancelled".to_string();
// Pass key to editor
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
}
return true;
}
}
}
// === AUTOCOMPLETE TRIGGER ===
if key_event.code == KeyCode::Char('@') && key_event.modifiers == KeyModifiers::NONE {
// Only trigger in insert mode for Vim, or always for other modes
let should_trigger = match add_logic_state.editor_keybinding_mode {
EditorKeybindingMode::Vim => *is_edit_mode, // Only in Vim insert mode
_ => true, // Always for non-Vim modes when editing
};
if should_trigger {
// Get cursor position before inserting @
let cursor_before = {
let editor_borrow = add_logic_state.script_content_editor.borrow();
editor_borrow.cursor()
};
// Handle editor input first
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
} // Drop editor borrow
// Activate autocomplete at the @ position
add_logic_state.script_editor_trigger_position = Some(cursor_before);
add_logic_state.script_editor_autocomplete_active = true;
add_logic_state.script_editor_filter_text.clear();
add_logic_state.update_script_editor_suggestions();
add_logic_state.has_unsaved_changes = true;
*command_message = "Autocomplete: @ (Tab/↑↓ to navigate, Enter to select, Esc to cancel)".to_string();
return true;
}
}
// Handle ONLY Escape to exit fullscreen mode
if key_event.code == KeyCode::Esc && key_event.modifiers == KeyModifiers::NONE {
@@ -35,12 +239,15 @@ pub fn handle_add_logic_navigation(
EditorKeybindingMode::Vim => {
if *is_edit_mode {
// First escape: try to go to Vim Normal mode
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
{
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
}
if TextEditor::is_vim_normal_mode(&add_logic_state.vim_state) {
*is_edit_mode = false;
*command_message = "VIM: Normal Mode. Esc again to exit script.".to_string();
@@ -70,14 +277,17 @@ pub fn handle_add_logic_navigation(
}
// ALL OTHER KEYS: Pass directly to textarea without any interference
let changed = TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
);
if changed {
add_logic_state.has_unsaved_changes = true;
let changed = {
let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut();
TextEditor::handle_input(
&mut editor_borrow,
key_event,
&add_logic_state.editor_keybinding_mode,
&mut add_logic_state.vim_state,
)
};
if changed {
add_logic_state.has_unsaved_changes = true;
}
// Update edit mode status for Vim
@@ -236,3 +446,25 @@ pub fn handle_add_logic_navigation(
handled
}
// Helper function for text replacement
fn replace_autocomplete_text(
editor: &mut tui_textarea::TextArea,
trigger_pos: (usize, usize),
filter_len: usize,
replacement: &str,
) {
use tui_textarea::CursorMove;
// Move cursor to the position right after the @ symbol (where filter text starts)
let filter_start_pos = (trigger_pos.0, trigger_pos.1 + 1);
editor.move_cursor(CursorMove::Jump(filter_start_pos.0 as u16, filter_start_pos.1 as u16));
// Delete only the filter text (not the @ symbol)
for _ in 0..filter_len {
editor.delete_next_char();
}
// Insert replacement text (this will be appended to the @ symbol)
editor.insert_str(replacement);
}