mod layout;
mod utils;
mod preview;
mod list;
use super::filter::ScoredCommand;
use crate::app::AppState;
use ratatui::Frame;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::widgets::{Clear, ListState};
use layout::{determine_layout, center_rect};
use utils::{parse_category_filter, group_by_category, get_custom_commands};
use list::{render_command_list_with_custom, render_command_list_grouped, render_empty};
use preview::{render_preview, render_custom_preview};
pub struct PaletteRenderer;
impl PaletteRenderer {
pub fn render(
frame: &mut Frame,
area: Rect,
state: &AppState,
commands: &[ScoredCommand],
) {
if commands.is_empty() {
render_empty(frame, area, state);
return;
}
let (query, category_filter) = parse_category_filter(&state.palette_input);
let selected = state.palette_selected;
let should_group = query.is_empty() && !state.palette_input.starts_with("@");
let (width_percent, height_percent, use_two_column) = determine_layout(commands.len(), area.width);
let popup = center_rect(width_percent, height_percent, area);
frame.render_widget(Clear, popup);
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(3),
Constraint::Length(4), ])
.split(popup);
let list_area = chunks[0];
let preview_area = chunks[1];
let custom_commands = get_custom_commands(state, &query);
let total_items = commands.len() + custom_commands.len();
let adjusted_selected = selected.min(total_items.saturating_sub(1));
let is_custom_selected = adjusted_selected >= commands.len();
let custom_index = if is_custom_selected {
adjusted_selected - commands.len()
} else {
0
};
let preview_command_idx = if should_group {
let grouped = group_by_category(commands, category_filter);
let (original_idx, _) = render_command_list_grouped(
frame,
list_area,
state,
&grouped,
selected.min(commands.len().saturating_sub(1)),
use_two_column,
commands
);
original_idx
} else {
render_command_list_with_custom(
frame,
list_area,
state,
commands,
&custom_commands,
adjusted_selected
);
adjusted_selected
};
if is_custom_selected {
if let Some((name, cmd)) = custom_commands.get(custom_index) {
render_custom_preview(frame, preview_area, state, name, cmd);
}
} else if let Some(scored) = commands.get(preview_command_idx.min(commands.len().saturating_sub(1))) {
render_preview(frame, preview_area, state, scored);
}
}
}