use std::collections::BTreeMap;
use crate::output::NextAction;
pub const ROOT_HELP_TEMPLATE: &str = "\
{before-help}{about-with-newline}
{usage-heading} {usage}{after-help}";
pub const GROUP_HELP_TEMPLATE: &str = "\
{before-help}{about-with-newline}
{usage-heading} {usage}
Commands:
{subcommands}{after-help}";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModuleHelpEntry {
pub category: String,
pub name: String,
pub short: String,
}
#[must_use]
pub fn build_root_long(intro: &str, entries: &[ModuleHelpEntry], has_guide: bool) -> String {
let mut by_category = BTreeMap::<&str, Vec<&ModuleHelpEntry>>::new();
for entry in entries {
by_category
.entry(entry.category.as_str())
.or_default()
.push(entry);
}
let max_width = entries
.iter()
.map(|entry| entry.name.len())
.max()
.unwrap_or_default();
let mut out = intro.to_owned();
for (category, category_entries) in &mut by_category {
category_entries.sort_by(|left, right| left.name.cmp(&right.name));
out.push_str(&format!("\n\n {category}:"));
for entry in category_entries {
out.push_str(&format!(
"\n {:<width$} {}",
entry.name,
entry.short,
width = max_width
));
}
}
out.push_str("\n\n Find Commands:");
out.push_str("\n --search <keyword> Search all commands and guides by keyword");
out.push_str("\n tree Display full command tree");
if has_guide {
out.push_str("\n guide Built-in guides for AI agents and developers");
}
out
}
#[must_use]
pub fn render_next_actions_human(actions: &[NextAction]) -> String {
if actions.is_empty() {
return String::new();
}
let max_width = actions
.iter()
.map(|action| action.command.len())
.max()
.unwrap_or_default();
let mut out = String::from("\n\n Suggested next actions:");
for action in actions {
out.push_str(&format!(
"\n {:<width$} {}",
action.command,
action.description,
width = max_width
));
}
out
}