suggestions on tab, still not working yet

This commit is contained in:
filipriec
2025-04-12 15:31:29 +02:00
parent 6d6df7ca5c
commit 50a329fc0d
5 changed files with 67 additions and 34 deletions

View File

@@ -52,10 +52,12 @@ delete_char_forward = ["delete"]
delete_char_backward = ["backspace"]
next_field = ["enter"]
prev_field = ["backtab"]
suggestion_down = ["shift+tab"]
suggestion_up = ["tab"]
move_left = ["left"]
move_right = ["right"]
suggestion_down = ["shift+tab"]
suggestion_up = ["tab"]
select_suggestion = ["enter"]
exit_suggestion_mode = ["esc"]
[keybindings.command]
exit_command_mode = ["ctrl+g", "esc"]

View File

@@ -2,9 +2,10 @@
use crate::config::colors::themes::Theme;
use ratatui::{
buffer::Buffer,
layout::Rect,
style::{Modifier, Style},
widgets::{Block, Borders, List, ListItem, ListState},
style::{Color, Modifier, Style},
widgets::{List, ListItem, ListState, StatefulWidget, Widget},
Frame,
};
@@ -19,25 +20,27 @@ pub fn render_autocomplete_dropdown(
if suggestions.is_empty() {
return; // Don't render if no suggestions
}
// --- Render Background ---
struct GrayBackground;
impl Widget for GrayBackground {
fn render(self, area: Rect, buf: &mut Buffer) {
buf.set_style(area, Style::default().bg(Color::DarkGray)); // Set background
}
}
f.render_widget(GrayBackground, area);
// --- Render Suggestions List (without block/border) ---
let items: Vec<ListItem> = suggestions
.iter()
.map(|s| ListItem::new(s.as_str()))
.map(|s| ListItem::new(s.as_str()).style(Style::default().fg(theme.fg))) // Set default text color
.collect();
let list = List::new(items)
.block(
Block::default()
.borders(Borders::ALL)
.border_type(ratatui::widgets::BorderType::Plain)
.border_style(Style::default().fg(theme.accent)) // Highlight border
.style(Style::default().bg(theme.bg).fg(theme.fg)),
)
.highlight_style(
Style::default()
.add_modifier(Modifier::BOLD)
.bg(theme.highlight) // Highlight background for selected item
.fg(theme.bg), // Text color for selected item
.bg(theme.highlight)
.fg(theme.bg),
)
.highlight_symbol("> "); // Symbol for selected item

View File

@@ -299,13 +299,13 @@ pub async fn execute_edit_action<S: CanvasState + Any + Send>(
}
// --- Autocomplete Actions ---
"suggestion_down" | "suggestion_up" | "select_suggestion" | "hide_suggestions" => {
"suggestion_down" | "suggestion_up" | "select_suggestion" | "exit_suggestion_mode" => {
// Attempt to downcast to RegisterState
if let Some(register_state) = (state as &mut dyn Any).downcast_mut::<RegisterState>() {
// Only handle if it's the role field (index 4) and suggestions are shown (except for hide)
if register_state.current_field() == 4 {
match action {
"suggestion_down" if register_state.show_role_suggestions => {
"suggestion_down" if register_state.in_suggestion_mode => {
let max_index = register_state.role_suggestions.len().saturating_sub(1);
let current_index = register_state.selected_suggestion_index.unwrap_or(0);
register_state.selected_suggestion_index = Some(if current_index >= max_index { 0 } else { current_index + 1 });
@@ -317,7 +317,7 @@ pub async fn execute_edit_action<S: CanvasState + Any + Send>(
register_state.selected_suggestion_index = Some(if current_index == 0 { max_index } else { current_index.saturating_sub(1) });
Ok("Suggestion changed up".to_string())
}
"select_suggestion" if register_state.show_role_suggestions => {
"select_suggestion" if register_state.in_suggestion_mode => {
if let Some(selected_index) = register_state.selected_suggestion_index {
if let Some(selected_role) = register_state.role_suggestions.get(selected_index) {
register_state.role = selected_role.clone();
@@ -335,9 +335,10 @@ pub async fn execute_edit_action<S: CanvasState + Any + Send>(
Ok("No suggestion selected".to_string())
}
}
"hide_suggestions" => {
"exit_suggestion_mode" => { // Handle Esc
register_state.show_role_suggestions = false;
register_state.selected_suggestion_index = None;
register_state.in_suggestion_mode = false;
Ok("Suggestions hidden".to_string())
}
_ => Ok("".to_string()) // Action doesn't apply in this state (e.g., suggestions not shown)

View File

@@ -80,6 +80,29 @@ pub async fn handle_edit_event(
// Edit-specific actions
if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) {
// --- Special Handling for Tab/Shift+Tab in Role Field ---
if app_state.ui.show_register && register_state.current_field() == 4 {
match action {
"suggestion_up" | "suggestion_down" => { // Mapped to Tab/Shift+Tab
if !register_state.in_suggestion_mode {
// Enter suggestion mode
register_state.update_role_suggestions(); // Populate suggestions
if !register_state.role_suggestions.is_empty() {
register_state.in_suggestion_mode = true;
register_state.show_role_suggestions = true;
register_state.selected_suggestion_index = Some(0); // Select first
return Ok("Suggestions shown".to_string()); // Consume the event
} else {
return Ok("No suggestions available".to_string()); // Consume, do nothing else
}
}
// If already in suggestion mode, fall through to execute the action via auth_e
}
_ => {} // Other actions fall through
}
}
// --- End Special Handling ---
return if app_state.ui.show_login {
auth_e::execute_edit_action(
action,
@@ -115,6 +138,12 @@ pub async fn handle_edit_event(
// Character insertion
if let KeyCode::Char(_) = key.code {
// If in suggestion mode, exit it before inserting char
if app_state.ui.show_register && register_state.in_suggestion_mode {
register_state.in_suggestion_mode = false;
register_state.show_role_suggestions = false;
register_state.selected_suggestion_index = None;
}
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
// --- End Autocomplete Trigger ---
@@ -149,15 +178,16 @@ pub async fn handle_edit_event(
total_count
).await
};
// After character insertion/deletion, update suggestions if it was the role field
if is_role_field {
register_state.update_role_suggestions();
}
}
// Handle Backspace/Delete for Autocomplete Trigger
if matches!(key.code, KeyCode::Backspace | KeyCode::Delete) {
// If in suggestion mode, exit it before deleting char
if app_state.ui.show_register && register_state.in_suggestion_mode {
register_state.in_suggestion_mode = false;
register_state.show_role_suggestions = false;
register_state.selected_suggestion_index = None;
}
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
let action_str = if key.code == KeyCode::Backspace { "backspace" } else { "delete_char" };
@@ -177,9 +207,6 @@ pub async fn handle_edit_event(
Ok("Action not applicable here".to_string()) // Placeholder
}?;
if is_role_field {
register_state.update_role_suggestions();
}
return Ok(result);
}

View File

@@ -4,8 +4,10 @@ use lazy_static::lazy_static;
lazy_static! {
pub static ref AVAILABLE_ROLES: Vec<String> = vec![
"accountant".to_string(),
"admin".to_string(),
"moderator".to_string(),
"accountant".to_string(),
"viewer".to_string(),
];
}
@@ -37,6 +39,7 @@ pub struct RegisterState {
pub show_role_suggestions: bool,
pub role_suggestions: Vec<String>,
pub selected_suggestion_index: Option<usize>,
pub in_suggestion_mode: bool,
}
impl AuthState {
@@ -71,6 +74,7 @@ impl RegisterState {
show_role_suggestions: false,
role_suggestions: Vec::new(),
selected_suggestion_index: None,
in_suggestion_mode: false,
}
}
@@ -78,9 +82,7 @@ impl RegisterState {
pub fn update_role_suggestions(&mut self) {
let current_input = self.role.to_lowercase();
if current_input.is_empty() {
self.role_suggestions = Vec::new(); // Or show all? For now, clear.
self.show_role_suggestions = false;
self.selected_suggestion_index = None;
self.role_suggestions = AVAILABLE_ROLES.to_vec();
} else {
self.role_suggestions = AVAILABLE_ROLES
.iter()
@@ -88,7 +90,6 @@ impl RegisterState {
.cloned()
.collect();
self.show_role_suggestions = !self.role_suggestions.is_empty();
self.selected_suggestion_index = if self.show_role_suggestions { Some(0) } else { None }; // Default to first suggestion selected
}
}
}
@@ -269,7 +270,7 @@ impl CanvasState for RegisterState {
fn get_suggestions(&self) -> Option<&[String]> {
// Only show suggestions for the role field (index 4) when requested
if self.current_field == 4 && self.show_role_suggestions {
if self.current_field == 4 && self.in_suggestion_mode && self.show_role_suggestions {
Some(&self.role_suggestions)
} else {
None
@@ -277,8 +278,7 @@ impl CanvasState for RegisterState {
}
fn get_selected_suggestion_index(&self) -> Option<usize> {
// Only return index if suggestions are shown for the role field
if self.current_field == 4 && self.show_role_suggestions {
if self.current_field == 4 && self.in_suggestion_mode && self.show_role_suggestions {
self.selected_suggestion_index
} else {
None