1use inquire::PasswordDisplayMode;
2
3pub fn welcome_message() {
4 println!();
5 println!("============================================");
6 println!(" Welcome to comma!");
7 println!(" AI-powered git commit generator.");
8 println!("============================================");
9 println!();
10 println!("First, we need a bit of configuration.");
11 println!();
12}
13
14pub fn error_message(message: &str) {
15 eprintln!();
16 eprintln!("============================================");
17 eprintln!(" ERROR");
18 eprintln!("============================================");
19 eprintln!();
20 eprintln!(" {}", message);
21 println!();
22}
23
24pub fn api_key_prompt() -> String {
25 inquire::Password::new("Enter OpenRouter API Key (sk-or-v1-...):")
26 .with_display_mode(PasswordDisplayMode::Masked)
27 .with_help_message("API key can be obtained at https://openrouter.ai/keys")
28 .prompt()
29 .expect("User cancelled")
30}
31
32pub fn model_select_prompt(models: &[String]) -> String {
33 use inquire::Select;
34
35 let mut options: Vec<String> = vec!["[ Type Manual Model ID... ]".to_string()];
36 options.extend(models.iter().cloned());
37
38 let sel = Select::new("Select model (type to search):", options)
39 .with_page_size(20)
40 .prompt()
41 .expect("User cancelled");
42
43 sel
44}
45
46pub fn manual_model_prompt() -> String {
47 inquire::Text::new("Enter model ID manually (e.g. anthropic/claude-3-haiku):")
48 .prompt()
49 .expect("User cancelled")
50}
51
52pub fn save_confirmation() {
53 println!();
54 println!("Configuration saved!");
55 println!();
56}
57
58pub fn fetching_models_message() {
59 print!("Fetching model list from OpenRouter...");
60 std::io::Write::flush(&mut std::io::stdout()).ok();
61}
62
63pub fn models_loaded(count: usize) {
64 println!(" done! {} models found.", count);
65 println!("Type to search...");
66 println!();
67}
68
69pub fn rate_limited_message() {
70 error_message("Too many requests. Please wait a moment and try again.");
71}
72
73pub fn prompt_model_switch(model_name: &str) -> Result<bool, ()> {
74 println!();
75 println!("❌ Oops! API Error");
76 println!("The provider rejected the request for the '{}' model.", model_name);
77 println!();
78 inquire::Confirm::new("Do you want to change the AI model now?")
79 .with_default(true)
80 .prompt()
81 .map_err(|_| ())
82}
83
84pub fn confirm_large_diff(size: usize) -> Result<bool, ()> {
85 println!();
86 println!("⚠️ Diff too large ({} characters).", size);
87 println!();
88 println!("Committing with such a large diff is a Git anti-pattern:");
89 println!("- You may have staged files that shouldn't be there (lock files, dist/)");
90 println!("- Better to split into smaller commits per feature");
91 println!();
92 inquire::Confirm::new("Continue anyway?")
93 .with_default(false)
94 .prompt()
95 .map_err(|_| ())
96}
97
98pub fn print_unstaged_files(files: &[crate::preflight::UnstagedFile]) {
99 println!("⚠️ No files staged for commit.");
100 println!();
101 println!("Changed files that are not staged:");
102 for file in files {
103 println!(" {} {}", file.status, file.path);
104 }
105 println!();
106}
107
108pub fn prompt_git_add() -> bool {
109 inquire::Confirm::new("Do you want to run 'git add .' now?")
110 .with_default(true)
111 .prompt()
112 .unwrap_or(false)
113}