143 lines
5.4 KiB
Rust
143 lines
5.4 KiB
Rust
// src/components/common/find_file_palette.rs
|
|
|
|
use crate::config::colors::themes::Theme;
|
|
use crate::modes::general::command_navigation::NavigationState; // Corrected path
|
|
use ratatui::{
|
|
layout::{Constraint, Direction, Layout, Rect},
|
|
style::Style,
|
|
widgets::{Block, List, ListItem, Paragraph},
|
|
Frame,
|
|
};
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
const PALETTE_MAX_VISIBLE_OPTIONS: usize = 15;
|
|
const PADDING_CHAR: &str = " ";
|
|
|
|
pub fn render_find_file_palette(
|
|
f: &mut Frame,
|
|
area: Rect,
|
|
theme: &Theme,
|
|
navigation_state: &NavigationState,
|
|
) {
|
|
let palette_display_input = navigation_state.get_display_input(); // Use the new method
|
|
|
|
let num_total_filtered = navigation_state.filtered_options.len();
|
|
let current_selected_list_idx = navigation_state.selected_index;
|
|
|
|
let mut display_start_offset = 0;
|
|
if num_total_filtered > PALETTE_MAX_VISIBLE_OPTIONS {
|
|
if let Some(sel_idx) = current_selected_list_idx {
|
|
if sel_idx >= display_start_offset + PALETTE_MAX_VISIBLE_OPTIONS {
|
|
display_start_offset = sel_idx - PALETTE_MAX_VISIBLE_OPTIONS + 1;
|
|
} else if sel_idx < display_start_offset {
|
|
display_start_offset = sel_idx;
|
|
}
|
|
display_start_offset = display_start_offset
|
|
.min(num_total_filtered.saturating_sub(PALETTE_MAX_VISIBLE_OPTIONS));
|
|
}
|
|
}
|
|
display_start_offset = display_start_offset.max(0);
|
|
|
|
let display_end_offset = (display_start_offset + PALETTE_MAX_VISIBLE_OPTIONS)
|
|
.min(num_total_filtered);
|
|
|
|
// navigation_state.filtered_options is Vec<(usize, String)>
|
|
// We only need the String part for display.
|
|
let visible_options_slice: Vec<&String> = if num_total_filtered > 0 {
|
|
navigation_state.filtered_options
|
|
[display_start_offset..display_end_offset]
|
|
.iter()
|
|
.map(|(_, opt_str)| opt_str)
|
|
.collect()
|
|
} else {
|
|
Vec::new()
|
|
};
|
|
|
|
let chunks = Layout::default()
|
|
.direction(Direction::Vertical)
|
|
.constraints([
|
|
Constraint::Length(1), // For palette input line
|
|
Constraint::Min(0), // For options list, take remaining space
|
|
])
|
|
.split(area);
|
|
|
|
// Ensure list_area height does not exceed PALETTE_MAX_VISIBLE_OPTIONS
|
|
let list_area_height = std::cmp::min(chunks[1].height, PALETTE_MAX_VISIBLE_OPTIONS as u16);
|
|
let final_list_area = Rect::new(chunks[1].x, chunks[1].y, chunks[1].width, list_area_height);
|
|
|
|
|
|
let input_area = chunks[0];
|
|
// let list_area = chunks[1]; // Use final_list_area
|
|
|
|
let prompt_prefix = match navigation_state.navigation_type {
|
|
crate::modes::general::command_navigation::NavigationType::FindFile => "Find File: ",
|
|
crate::modes::general::command_navigation::NavigationType::TableTree => "Table Path: ",
|
|
};
|
|
let base_prompt_text = format!("{}{}", prompt_prefix, palette_display_input);
|
|
let prompt_text_width = UnicodeWidthStr::width(base_prompt_text.as_str());
|
|
let input_area_width = input_area.width as usize;
|
|
let input_padding_needed =
|
|
input_area_width.saturating_sub(prompt_text_width);
|
|
|
|
let padded_prompt_text = if input_padding_needed > 0 {
|
|
format!(
|
|
"{}{}",
|
|
base_prompt_text,
|
|
PADDING_CHAR.repeat(input_padding_needed)
|
|
)
|
|
} else {
|
|
base_prompt_text
|
|
};
|
|
|
|
let input_paragraph = Paragraph::new(padded_prompt_text)
|
|
.style(Style::default().fg(theme.accent).bg(theme.bg));
|
|
f.render_widget(input_paragraph, input_area);
|
|
|
|
let mut display_list_items: Vec<ListItem> =
|
|
Vec::with_capacity(PALETTE_MAX_VISIBLE_OPTIONS);
|
|
|
|
for (idx_in_visible_slice, opt_str) in
|
|
visible_options_slice.iter().enumerate()
|
|
{
|
|
// The selected_index in navigation_state is relative to the full filtered_options list.
|
|
// We need to check if the current item (from the visible slice) corresponds to the selected_index.
|
|
let original_filtered_idx = display_start_offset + idx_in_visible_slice;
|
|
let is_selected =
|
|
current_selected_list_idx == Some(original_filtered_idx);
|
|
|
|
let style = if is_selected {
|
|
Style::default().fg(theme.bg).bg(theme.accent)
|
|
} else {
|
|
Style::default().fg(theme.fg).bg(theme.bg)
|
|
};
|
|
|
|
let opt_width = opt_str.width() as u16;
|
|
let list_item_width = final_list_area.width;
|
|
let padding_amount = list_item_width.saturating_sub(opt_width);
|
|
let padded_opt_str = format!(
|
|
"{}{}",
|
|
opt_str,
|
|
PADDING_CHAR.repeat(padding_amount as usize)
|
|
);
|
|
display_list_items.push(ListItem::new(padded_opt_str).style(style));
|
|
}
|
|
|
|
// Fill remaining lines in the list area to maintain fixed height appearance
|
|
let num_rendered_options = display_list_items.len();
|
|
if num_rendered_options < PALETTE_MAX_VISIBLE_OPTIONS && (final_list_area.height as usize) > num_rendered_options {
|
|
for _ in num_rendered_options..(final_list_area.height as usize) {
|
|
let empty_padded_str =
|
|
PADDING_CHAR.repeat(final_list_area.width as usize);
|
|
display_list_items.push(
|
|
ListItem::new(empty_padded_str)
|
|
.style(Style::default().fg(theme.bg).bg(theme.bg)),
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
let options_list_widget = List::new(display_list_items)
|
|
.block(Block::default().style(Style::default().bg(theme.bg)));
|
|
f.render_widget(options_list_widget, final_list_area);
|
|
}
|