xbp 10.46.0

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
//! Shared interactive pickers (type-to-filter FuzzySelect + ANSI theme).

use dialoguer::theme::ColorfulTheme;
use dialoguer::{FuzzySelect, MultiSelect};
use std::fmt::Display;

/// Rich dialoguer theme used across XBP interactive prompts.
pub fn xbp_theme() -> ColorfulTheme {
    ColorfulTheme::default()
}

/// Searchable single-select (type to filter). Returns `None` if cancelled.
pub fn searchable_select<T: Display>(
    prompt: &str,
    items: &[T],
    default: usize,
) -> Result<Option<usize>, String> {
    if items.is_empty() {
        return Ok(None);
    }
    let default = default.min(items.len().saturating_sub(1));
    FuzzySelect::with_theme(&xbp_theme())
        .with_prompt(format!("{prompt} (type to search)"))
        .items(items)
        .default(default)
        .interact_opt()
        .map_err(|error| format!("Prompt failed: {error}"))
}

/// Searchable multi-select. Returns selected indices (may be empty).
pub fn searchable_multi_select<T: Display>(
    prompt: &str,
    items: &[T],
    defaults: &[bool],
) -> Result<Vec<usize>, String> {
    if items.is_empty() {
        return Ok(Vec::new());
    }
    let defaults = if defaults.len() == items.len() {
        defaults.to_vec()
    } else {
        vec![false; items.len()]
    };
    MultiSelect::with_theme(&xbp_theme())
        .with_prompt(format!("{prompt} (space to toggle, type to filter if supported)"))
        .items(items)
        .defaults(&defaults)
        .interact()
        .map_err(|error| format!("Prompt failed: {error}"))
}