Skip to main content

git_comma/
ui.rs

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}