use crate::app::App;
use crate::input::CommandDef;
use ratatui::Frame;
use ratatui::layout::{Alignment, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
#[allow(dead_code)]
pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
let input = &app.command_input;
let matches = app.command_registry.find_matches(input);
if matches.is_empty() {
return;
}
if app.completion_selected_index.is_none()
|| app.completion_selected_index >= Some(matches.len())
{
app.completion_selected_index = Some(0);
}
let total_height = area.height.min(20); let input_height = 2; let list_height = total_height - input_height;
let input_area = Rect {
x: area.x,
y: area.y,
width: area.width,
height: input_height,
};
let completion_area = Rect {
x: area.x,
y: area.y + input_height,
width: area.width,
height: list_height,
};
render_command_input(f, input_area, input);
render_command_list(f, completion_area, &matches, app.completion_selected_index);
if matches.len() == 1
|| (!input.is_empty()
&& matches
.iter()
.any(|cmd| cmd.name == input || cmd.aliases.contains(&input.as_str())))
{
let cmd = matches[0];
render_command_detail(f, area, cmd);
}
}
#[allow(dead_code)]
fn render_command_input(f: &mut Frame, area: Rect, input: &str) {
f.render_widget(Clear, area);
let block = Block::default()
.title(" 输入命令 ")
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Rgb(136, 192, 208)))
.border_type(ratatui::widgets::BorderType::Rounded)
.style(Style::default().bg(Color::Rgb(46, 52, 64)));
f.render_widget(block.clone(), area);
let inner = block.inner(area);
let input_text = format!(":{}", input);
let line = Line::from(vec![Span::raw(input_text)]);
let paragraph = Paragraph::new(line)
.style(Style::default().fg(Color::White))
.alignment(Alignment::Left);
f.render_widget(paragraph, inner);
}
#[allow(dead_code)]
fn render_command_list(
f: &mut Frame,
area: Rect,
commands: &[&CommandDef],
selected_index: Option<usize>,
) {
f.render_widget(Clear, area);
let bg_block = Block::default().style(Style::default().bg(Color::Rgb(30, 30, 30)));
f.render_widget(bg_block, area);
let column_width = 20;
let columns = (area.width as usize / column_width).clamp(1, 5);
let max_rows = (area.height.saturating_sub(0)) as usize;
let max_commands = columns * max_rows;
let display_commands = &commands[..commands.len().min(max_commands)];
let mut lines = Vec::new();
let rows = display_commands.len().div_ceil(columns);
for row in 0..rows {
let mut spans = Vec::new();
for col in 0..columns {
let idx = row + col * rows;
if idx < display_commands.len() {
let cmd = display_commands[idx];
let absolute_idx = idx;
let display_name = if cmd.aliases.is_empty() {
cmd.name
} else {
cmd.aliases[0]
};
let is_selected = selected_index.map(|i| i == absolute_idx).unwrap_or(false);
let style = if is_selected {
Style::default()
.bg(Color::Rgb(136, 192, 208))
.fg(Color::Black)
.add_modifier(Modifier::BOLD)
} else {
Style::default().fg(Color::Rgb(136, 192, 208))
};
spans.push(Span::styled(
format!("{:<width$}", display_name, width = column_width - 1),
style,
));
} else {
spans.push(Span::raw(" ".repeat(column_width)));
}
}
lines.push(Line::from(spans));
}
let paragraph = Paragraph::new(lines).alignment(Alignment::Left);
f.render_widget(paragraph, area);
}
#[allow(dead_code)]
fn render_command_detail(f: &mut Frame, area: Rect, cmd: &CommandDef) {
let popup_width = 60.min(area.width.saturating_sub(4));
let popup_height = 6;
let popup_area = Rect {
x: (area.width.saturating_sub(popup_width)) / 2,
y: (area.height.saturating_sub(popup_height)) / 2,
width: popup_width,
height: popup_height,
};
f.render_widget(Clear, popup_area);
let mut lines = Vec::new();
lines.push(Line::from(vec![Span::styled(
cmd.name,
Style::default()
.fg(Color::Rgb(136, 192, 208))
.add_modifier(Modifier::BOLD),
)]));
lines.push(Line::from(""));
lines.push(Line::from(vec![Span::styled(
cmd.description,
Style::default().fg(Color::White),
)]));
if !cmd.aliases.is_empty() {
lines.push(Line::from(""));
let aliases_str = format!("Aliases: {}", cmd.aliases.join(", "));
lines.push(Line::from(vec![Span::styled(
aliases_str,
Style::default().fg(Color::Gray),
)]));
}
let paragraph = Paragraph::new(lines)
.block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::Rgb(136, 192, 208)))
.border_type(ratatui::widgets::BorderType::Rounded)
.style(Style::default().bg(Color::Rgb(40, 40, 40))),
)
.alignment(Alignment::Left);
f.render_widget(paragraph, popup_area);
}