autocomplete now autocompleting data not just id

This commit is contained in:
filipriec
2025-06-16 11:54:54 +02:00
parent 8fcd28832d
commit 9e0fa9ddb1
5 changed files with 149 additions and 89 deletions

View File

@@ -140,12 +140,12 @@ pub fn render_rich_autocomplete_dropdown(
let display_part = values.first().cloned().unwrap_or_default(); // Get the first value
if display_part.is_empty() {
format!("ID: {}", hit.id)
format!("{}", hit.id)
} else {
format!("{} | ID: {}", display_part, hit.id) // ID at the end
format!("{} | {}", display_part, hit.id) // ID at the end
}
} else {
format!("ID: {} (parse error)", hit.id)
format!("{} (parse error)", hit.id)
}
})
.collect();

View File

@@ -1,16 +1,16 @@
// src/components/handlers/canvas.rs
use ratatui::{
widgets::{Paragraph, Block, Borders},
layout::{Layout, Constraint, Direction, Rect},
style::{Style, Modifier},
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Paragraph},
Frame,
prelude::Alignment,
};
use crate::config::colors::themes::Theme;
use crate::state::app::highlight::HighlightState;
use crate::state::pages::canvas_state::CanvasState;
use crate::state::app::highlight::HighlightState; // Ensure correct import path
use std::cmp::{min, max};
use std::cmp::{max, min};
pub fn render_canvas(
f: &mut Frame,
@@ -21,9 +21,8 @@ pub fn render_canvas(
inputs: &[&String],
theme: &Theme,
is_edit_mode: bool,
highlight_state: &HighlightState, // Using the enum state
highlight_state: &HighlightState,
) -> Option<Rect> {
// ... (setup code remains the same) ...
let columns = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
@@ -58,46 +57,47 @@ pub fn render_canvas(
let mut active_field_input_rect = None;
// Render labels
for (i, field) in fields.iter().enumerate() {
let label = Paragraph::new(Line::from(Span::styled(
format!("{}:", field),
Style::default().fg(theme.fg)),
));
f.render_widget(label, Rect {
x: columns[0].x,
y: input_block.y + 1 + i as u16,
width: columns[0].width,
height: 1,
});
Style::default().fg(theme.fg),
)));
f.render_widget(
label,
Rect {
x: columns[0].x,
y: input_block.y + 1 + i as u16,
width: columns[0].width,
height: 1,
},
);
}
// Render inputs and cursor
for (i, input) in inputs.iter().enumerate() {
for (i, _input) in inputs.iter().enumerate() {
let is_active = i == *current_field_idx;
let current_cursor_pos = form_state.current_cursor_pos();
let text = input.as_str();
let text_len = text.chars().count();
// Use the trait method to get display value
let text = form_state.get_display_value_for_field(i);
let text_len = text.chars().count();
let line: Line;
// --- Use match on the highlight_state enum ---
match highlight_state {
HighlightState::Off => {
// Not in highlight mode, render normally
line = Line::from(Span::styled(
text,
if is_active { Style::default().fg(theme.highlight) } else { Style::default().fg(theme.fg) }
if is_active {
Style::default().fg(theme.highlight)
} else {
Style::default().fg(theme.fg)
},
));
}
HighlightState::Characterwise { anchor } => {
// --- Character-wise Highlight Logic ---
let (anchor_field, anchor_char) = *anchor;
let start_field = min(anchor_field, *current_field_idx);
let end_field = max(anchor_field, *current_field_idx);
// Use start_char and end_char consistently
let (start_char, end_char) = if anchor_field == *current_field_idx {
(min(anchor_char, current_cursor_pos), max(anchor_char, current_cursor_pos))
} else if anchor_field < *current_field_idx {
@@ -111,24 +111,20 @@ pub fn render_canvas(
let normal_style_outside = Style::default().fg(theme.fg);
if i >= start_field && i <= end_field {
// This line is within the character-wise highlight range
if start_field == end_field { // Case 1: Single Line Highlight
// Use start_char and end_char here
if start_field == end_field {
let clamped_start = start_char.min(text_len);
let clamped_end = end_char.min(text_len); // Use text_len for slicing logic
let clamped_end = end_char.min(text_len);
let before: String = text.chars().take(clamped_start).collect();
let highlighted: String = text.chars().skip(clamped_start).take(clamped_end.saturating_sub(clamped_start) + 1).collect();
// Define 'after' here
let after: String = text.chars().skip(clamped_end + 1).collect();
line = Line::from(vec![
Span::styled(before, normal_style_in_highlight),
Span::styled(highlighted, highlight_style),
Span::styled(after, normal_style_in_highlight), // Use defined 'after'
Span::styled(after, normal_style_in_highlight),
]);
} else if i == start_field { // Case 2: Multi-Line Highlight - Start Line
// Use start_char here
} else if i == start_field {
let safe_start = start_char.min(text_len);
let before: String = text.chars().take(safe_start).collect();
let highlighted: String = text.chars().skip(safe_start).collect();
@@ -136,8 +132,7 @@ pub fn render_canvas(
Span::styled(before, normal_style_in_highlight),
Span::styled(highlighted, highlight_style),
]);
} else if i == end_field { // Case 3: Multi-Line Highlight - End Line (Corrected index)
// Use end_char here
} else if i == end_field {
let safe_end_inclusive = if text_len > 0 { end_char.min(text_len - 1) } else { 0 };
let highlighted: String = text.chars().take(safe_end_inclusive + 1).collect();
let after: String = text.chars().skip(safe_end_inclusive + 1).collect();
@@ -145,19 +140,17 @@ pub fn render_canvas(
Span::styled(highlighted, highlight_style),
Span::styled(after, normal_style_in_highlight),
]);
} else { // Case 4: Multi-Line Highlight - Middle Line (Corrected index)
line = Line::from(Span::styled(text, highlight_style)); // Highlight whole line
} else {
line = Line::from(Span::styled(text, highlight_style));
}
} else { // Case 5: Line Outside Character-wise Highlight Range
} else {
line = Line::from(Span::styled(
text,
// Use normal styling (active or inactive)
if is_active { normal_style_in_highlight } else { normal_style_outside }
));
}
}
HighlightState::Linewise { anchor_line } => {
// --- Linewise Highlight Logic ---
let start_field = min(*anchor_line, *current_field_idx);
let end_field = max(*anchor_line, *current_field_idx);
let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD);
@@ -165,25 +158,31 @@ pub fn render_canvas(
let normal_style_outside = Style::default().fg(theme.fg);
if i >= start_field && i <= end_field {
// Highlight the entire line
line = Line::from(Span::styled(text, highlight_style));
} else {
// Line outside linewise highlight range
line = Line::from(Span::styled(
text,
// Use normal styling (active or inactive)
if is_active { normal_style_in_highlight } else { normal_style_outside }
));
}
}
} // End match highlight_state
}
let input_display = Paragraph::new(line).alignment(Alignment::Left);
f.render_widget(input_display, input_rows[i]);
if is_active {
active_field_input_rect = Some(input_rows[i]);
let cursor_x = input_rows[i].x + form_state.current_cursor_pos() as u16;
// --- CORRECTED CURSOR POSITIONING LOGIC ---
// Use the new generic trait method to check for an override.
let cursor_x = if form_state.has_display_override(i) {
// If an override exists, place the cursor at the end.
input_rows[i].x + text.chars().count() as u16
} else {
// Otherwise, use the real cursor position.
input_rows[i].x + form_state.current_cursor_pos() as u16
};
let cursor_y = input_rows[i].y;
f.set_cursor_position((cursor_x, cursor_y));
}
@@ -191,4 +190,3 @@ pub fn render_canvas(
active_field_input_rect
}