use anyhow::{Context as _, Result};
use dialoguer::{Confirm, Input, MultiSelect, Select};
pub(crate) trait ContextPrompter {
fn select(&self, prompt: &str, items: &[String], default: usize) -> Result<usize>;
fn multi_select(&self, prompt: &str, items: &[String], defaults: &[bool])
-> Result<Vec<usize>>;
fn confirm(&self, prompt: &str, default: bool) -> Result<bool>;
fn input(&self, prompt: &str, default: Option<&str>, allow_empty: bool) -> Result<String>;
fn edit(&self, prompt: &str, initial: &str) -> Result<String>;
}
pub(crate) struct DialoguerPrompter;
impl ContextPrompter for DialoguerPrompter {
fn select(&self, prompt: &str, items: &[String], default: usize) -> Result<usize> {
Select::new()
.with_prompt(prompt)
.items(items)
.default(default)
.interact()
.with_context(|| format!("failed to get selection for: {prompt}"))
}
fn multi_select(
&self,
prompt: &str,
items: &[String],
defaults: &[bool],
) -> Result<Vec<usize>> {
MultiSelect::new()
.with_prompt(prompt)
.items(items)
.defaults(defaults)
.interact()
.with_context(|| format!("failed to get multi-selection for: {prompt}"))
}
fn confirm(&self, prompt: &str, default: bool) -> Result<bool> {
Confirm::new()
.with_prompt(prompt)
.default(default)
.interact()
.with_context(|| format!("failed to get confirmation for: {prompt}"))
}
fn input(&self, prompt: &str, default: Option<&str>, allow_empty: bool) -> Result<String> {
let mut input = Input::new();
input = input.with_prompt(prompt).allow_empty(allow_empty);
if let Some(default_value) = default {
input = input.default(default_value.to_string());
}
input
.interact_text()
.with_context(|| format!("failed to get input for: {prompt}"))
}
fn edit(&self, prompt: &str, initial: &str) -> Result<String> {
dialoguer::Editor::new()
.edit(initial)
.with_context(|| format!("failed to edit content for: {prompt}"))?
.ok_or_else(|| anyhow::anyhow!("Editor was cancelled"))
}
}