claude_code_switcher/
confirm_selector.rs1use anyhow::{Result, anyhow};
4use console::style;
5use inquire::{Confirm, Select};
6
7pub struct ConfirmSelector {
9 message: String,
10 default: bool,
11}
12
13impl ConfirmSelector {
14 pub fn new(message: &str, default: bool) -> Self {
15 Self {
16 message: message.to_string(),
17 default,
18 }
19 }
20
21 pub fn run(&self) -> Result<bool> {
23 if !atty::is(atty::Stream::Stdin) {
25 return Ok(self.default);
26 }
27
28 if let Ok(result) = self.run_enhanced_selector() {
30 return Ok(result);
31 }
32
33 Confirm::new(&self.message)
35 .with_default(self.default)
36 .with_help_message("Press Y for Yes, N for No, or Q to Quit")
37 .prompt()
38 .map_err(|e| anyhow!("Failed to get confirmation: {}", e))
39 }
40
41 fn run_enhanced_selector(&self) -> Result<bool> {
42 let options = vec![
44 format!("✓ Yes {}", style("(Y)").green()),
45 format!("✗ No {}", style("(N)").red()),
46 format!("⚠ Quit {}", style("(Q)").yellow()),
47 ];
48
49 let prompt = self.message.clone();
50
51 match Select::new(&prompt, options).prompt() {
52 Ok(choice) => {
53 match choice.as_str() {
54 choice if choice.contains("Yes") => Ok(true),
55 choice if choice.contains("No") => Ok(false),
56 choice if choice.contains("Quit") => {
57 println!("{}", style("🚫 Operation cancelled by user.").yellow());
58 std::process::exit(0);
59 }
60 _ => Ok(self.default), }
62 }
63 Err(e) => Err(anyhow!("Enhanced selector failed: {}", e)),
64 }
65 }
66}
67
68pub fn confirm_with_enhanced_selector(message: &str, default: bool) -> Result<bool> {
70 let selector = ConfirmSelector::new(message, default);
71 selector.run()
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_confirm_selector_creation() {
80 let selector = ConfirmSelector::new("Test message", true);
81 assert_eq!(selector.message, "Test message");
82 assert_eq!(selector.default, true);
83 }
84}