use crate::Result;
use crate::daemon_id::DaemonId;
use demand::{DemandOption, MultiSelect};
use std::io::IsTerminal;
pub(crate) fn require_interactive_terminal() -> Result<()> {
if !std::io::stdin().is_terminal() || !std::io::stdout().is_terminal() {
miette::bail!(
"No daemon ID specified. Provide one or more daemon IDs, \
or run in an interactive terminal to use the selection prompt."
);
}
Ok(())
}
pub(crate) fn select_daemons_interactively(
candidates: &[DaemonId],
action: &str,
) -> Result<Vec<DaemonId>> {
if candidates.is_empty() {
miette::bail!("No daemons available to {action}");
}
require_interactive_terminal()?;
let title = format!("Select daemon(s) to {action}");
let mut sorted: Vec<DaemonId> = candidates.to_vec();
sorted.sort();
let mut ms = MultiSelect::new(&title)
.filterable(true)
.description("Use / to filter, space to toggle, enter to confirm");
for id in &sorted {
ms = ms.option(DemandOption::with_label(id.qualified(), id.clone()));
}
let selected: Vec<DaemonId> = ms.run().map_err(|e| {
if e.kind() == std::io::ErrorKind::Interrupted {
miette::miette!("Selection cancelled")
} else {
miette::miette!("Interactive selection failed: {e}")
}
})?;
if selected.is_empty() {
miette::bail!("No daemons selected");
}
Ok(selected)
}