use crate::application::cli::error::CliError;
use dialoguer::{Confirm, Input};
use std::io::{self, IsTerminal};
fn ensure_tty() -> Result<(), CliError> {
if io::stdin().is_terminal() && io::stdout().is_terminal() {
Ok(())
} else {
Err(CliError::validation(
"Interactive prompts require a TTY environment (not supported in pipes or scripts)"
.to_string(),
))
}
}
pub fn prompt_for_input(prompt: &str) -> Result<String, CliError> {
ensure_tty()?;
Input::<String>::new()
.with_prompt(prompt)
.interact_text()
.map_err(|e| match e {
dialoguer::Error::IO(io_err) if io_err.kind() == io::ErrorKind::Interrupted => {
CliError::Cancelled
}
_ => CliError::user_input(format!("Failed to read input: {}", e)),
})
}
pub fn confirm(prompt: &str, default: bool) -> Result<bool, CliError> {
ensure_tty()?;
Confirm::new()
.with_prompt(prompt)
.default(default)
.interact()
.map_err(|e| match e {
dialoguer::Error::IO(io_err) if io_err.kind() == io::ErrorKind::Interrupted => {
CliError::Cancelled
}
_ => CliError::user_input(format!("Failed to read confirmation: {}", e)),
})
}
pub fn prompt_with_validation<F>(prompt: &str, validator: F) -> Result<String, CliError>
where
F: Fn(&str) -> Result<(), String>,
{
ensure_tty()?;
Input::<String>::new()
.with_prompt(prompt)
.validate_with(|input: &String| -> Result<(), String> { validator(input) })
.interact_text()
.map_err(|e| match e {
dialoguer::Error::IO(io_err) if io_err.kind() == io::ErrorKind::Interrupted => {
CliError::Cancelled
}
_ => CliError::user_input(format!("Failed to read input: {}", e)),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ensure_tty_detection() {
let _ = ensure_tty();
}
}