use crate::selectors::base::SelectableItem;
use crate::selectors::error::{SelectorError, SelectorResult};
use inquire::Select;
#[derive(Debug, Clone)]
pub enum NavigationResult<T> {
Selected(T),
CreateNew,
Back,
Exit,
}
pub struct NavigationManager;
impl NavigationManager {
pub fn select_from_list<T: SelectableItem + Clone>(
items: &[T],
title: &str,
allow_create: bool,
help_message: Option<&str>,
) -> SelectorResult<NavigationResult<T>> {
Self::select_from_list_with_create(items, title, allow_create, help_message)
}
pub fn select_from_list_with_create<T: SelectableItem + Clone>(
items: &[T],
title: &str,
allow_create: bool,
help_message: Option<&str>,
) -> SelectorResult<NavigationResult<T>> {
let mut options = Vec::new();
if allow_create {
options.push("➕ Create New...".to_string());
}
for item in items {
options.push(item.format_for_list());
}
if options.is_empty() {
return Err(SelectorError::Failed("No options available".to_string()));
}
let mut select = Select::new(title, options);
if let Some(help) = help_message {
select = select.with_help_message(help);
}
let selection = select.prompt().map_err(|e| {
if e.to_string().contains("canceled") || e.to_string().contains("cancelled") {
SelectorError::Cancelled
} else {
SelectorError::Failed(format!("Selection failed: {}", e))
}
})?;
if allow_create && selection == "➕ Create New..." {
return Ok(NavigationResult::CreateNew);
}
for item in items {
if selection == item.format_for_list() || selection.starts_with(&item.display_name()) {
return Ok(NavigationResult::Selected(item.clone()));
}
}
Err(SelectorError::NotFound)
}
pub fn confirm(message: &str, default: bool) -> SelectorResult<bool> {
use inquire::Confirm;
if !atty::is(atty::Stream::Stdin) {
return Ok(default);
}
Confirm::new(message)
.with_default(default)
.with_help_message("Y for Yes, N for No")
.prompt()
.map_err(|e| {
if e.to_string().contains("canceled") || e.to_string().contains("cancelled") {
SelectorError::Cancelled
} else {
SelectorError::Failed(format!("Confirmation failed: {}", e))
}
})
}
pub fn select_option(
title: &str,
options: &[&str],
help_message: Option<&str>,
) -> SelectorResult<String> {
let options: Vec<String> = options.iter().map(|s| s.to_string()).collect();
let mut select = Select::new(title, options);
if let Some(help) = help_message {
select = select.with_help_message(help);
}
select.prompt().map_err(|e| {
if e.to_string().contains("canceled") || e.to_string().contains("cancelled") {
SelectorError::Cancelled
} else {
SelectorError::Failed(format!("Option selection failed: {}", e))
}
})
}
pub fn get_text_input(
message: &str,
placeholder: Option<&str>,
help_message: Option<&str>,
) -> SelectorResult<String> {
use inquire::Text;
let mut prompt = Text::new(message);
if let Some(placeholder) = placeholder {
prompt = prompt.with_placeholder(placeholder);
}
if let Some(help) = help_message {
prompt = prompt.with_help_message(help);
}
prompt.prompt().map_err(|e| {
if e.to_string().contains("canceled") || e.to_string().contains("cancelled") {
SelectorError::Cancelled
} else {
SelectorError::Failed(format!("Input failed: {}", e))
}
})
}
}