use rnk::prelude::*;
use crate::ui::rnk_app::theme::TerminalTheme;
use rnk::prelude::Box as RnkBox;
const BUILTIN_COMMANDS: &[(&str, &str)] = &[
("help", "Show help information"),
("clear", "Clear conversation"),
("compact", "Compact conversation context"),
("commands", "List slash commands"),
("config", "Manage configuration"),
("context", "Show context usage"),
("cost", "Show session cost and usage"),
("init", "Initialize Sage in project"),
("login", "Configure API credentials"),
("output", "Switch output mode (streaming|batch|silent)"),
("plan", "View execution plan"),
("resume", "Resume a conversation"),
("status", "Show agent status"),
("tasks", "List background tasks"),
("title", "Set session title"),
("undo", "Undo file changes"),
];
pub fn render_command_suggestions(
input: &str,
selected_index: usize,
theme: &TerminalTheme,
) -> Option<(Element, usize)> {
if !input.starts_with('/') {
return None;
}
let query = &input[1..];
let matches: Vec<_> = BUILTIN_COMMANDS
.iter()
.filter(|(name, _)| name.starts_with(query))
.take(6)
.collect();
if matches.is_empty() {
return None;
}
let match_count = matches.len();
let selected = selected_index.min(match_count.saturating_sub(1));
let mut container = RnkBox::new().flex_direction(FlexDirection::Column);
container = container.child(
Text::new("⌘ commands")
.color(theme.text_muted)
.bold()
.into_element(),
);
for (i, (name, desc)) in matches.iter().enumerate() {
let is_selected = i == selected;
let prefix = if is_selected { "▸" } else { " " };
let cmd_color = if is_selected {
theme.text_primary
} else {
theme.accent_assistant
};
let desc_color = theme.text_muted;
let row = RnkBox::new()
.flex_direction(FlexDirection::Row)
.child(
Text::new(format!("{prefix} /{name}"))
.color(cmd_color)
.bold()
.into_element(),
)
.child(
Text::new(format!(" {desc}"))
.color(desc_color)
.into_element(),
);
container = container.child(row.into_element());
}
Some((container.into_element(), match_count))
}
pub fn get_selected_command(input: &str, selected_index: usize) -> Option<String> {
if !input.starts_with('/') {
return None;
}
let query = &input[1..];
let matches: Vec<_> = BUILTIN_COMMANDS
.iter()
.filter(|(name, _)| name.starts_with(query))
.take(6)
.collect();
if matches.is_empty() {
return None;
}
let selected = selected_index.min(matches.len().saturating_sub(1));
Some(format!("/{}", matches[selected].0))
}
pub fn count_matching_commands(input: &str) -> usize {
if !input.starts_with('/') {
return 0;
}
let query = &input[1..];
BUILTIN_COMMANDS
.iter()
.filter(|(name, _)| name.starts_with(query))
.take(6)
.count()
}