git_iris/
commands.rs

1use crate::common::CommonParams;
2use crate::config::Config;
3use crate::instruction_presets::get_instruction_preset_library;
4use crate::llm_providers::get_available_providers;
5use crate::log_debug;
6use crate::ui;
7use crate::ProviderConfig;
8use anyhow::Context;
9use anyhow::{anyhow, Result};
10use colored::Colorize;
11use std::collections::HashMap;
12
13use unicode_width::UnicodeWidthStr;
14
15/// Handle the 'config' command
16#[allow(clippy::too_many_lines)]
17pub fn handle_config_command(
18    common: CommonParams,
19    api_key: Option<String>,
20    model: Option<String>,
21    token_limit: Option<usize>,
22    param: Option<Vec<String>>,
23) -> anyhow::Result<()> {
24    log_debug!("Starting 'config' command with common: {:?}, api_key: {:?}, model: {:?}, token_limit: {:?}, param: {:?}",
25               common, api_key, model, token_limit, param);
26
27    let mut config = Config::load()?;
28    common.apply_to_config(&mut config)?;
29    let mut changes_made = false;
30
31    if let Some(provider) = common.provider {
32        if !get_available_providers()
33            .iter()
34            .any(|p| p.to_string() == provider)
35        {
36            return Err(anyhow!("Invalid provider: {}", provider));
37        }
38        if config.default_provider != provider {
39            config.default_provider.clone_from(&provider);
40            changes_made = true;
41        }
42        if !config.providers.contains_key(&provider) {
43            config
44                .providers
45                .insert(provider.clone(), ProviderConfig::default());
46            changes_made = true;
47        }
48    }
49
50    let provider_config = config
51        .providers
52        .get_mut(&config.default_provider)
53        .context("Could not get default provider")?;
54
55    if let Some(key) = api_key {
56        if provider_config.api_key != key {
57            provider_config.api_key = key;
58            changes_made = true;
59        }
60    }
61    if let Some(model) = model {
62        if provider_config.model != model {
63            provider_config.model = model;
64            changes_made = true;
65        }
66    }
67    if let Some(params) = param {
68        let additional_params = parse_additional_params(&params);
69        if provider_config.additional_params != additional_params {
70            provider_config.additional_params = additional_params;
71            changes_made = true;
72        }
73    }
74    if let Some(use_gitmoji) = common.gitmoji {
75        if config.use_gitmoji != use_gitmoji {
76            config.use_gitmoji = use_gitmoji;
77            changes_made = true;
78        }
79    }
80    if let Some(instr) = common.instructions {
81        if config.instructions != instr {
82            config.instructions = instr;
83            changes_made = true;
84        }
85    }
86    if let Some(limit) = token_limit {
87        if provider_config.token_limit != Some(limit) {
88            provider_config.token_limit = Some(limit);
89            changes_made = true;
90        }
91    }
92    if let Some(preset) = common.preset {
93        let preset_library = get_instruction_preset_library();
94        if preset_library.get_preset(&preset).is_some() {
95            if config.instruction_preset != preset {
96                config.instruction_preset = preset;
97                changes_made = true;
98            }
99        } else {
100            return Err(anyhow!("Invalid preset: {}", preset));
101        }
102    }
103
104    if changes_made {
105        config.save()?;
106        ui::print_success("Configuration updated successfully.");
107    }
108
109    ui::print_info(&format!(
110        "Current configuration:\nDefault Provider: {}\nUse Gitmoji: {}\nInstructions: {}\nInstruction Preset: {}",
111        config.default_provider,
112        config.use_gitmoji,
113        if config.instructions.is_empty() {
114            "None".to_string()
115        } else {
116            config.instructions.replace('\n', ", ")
117        },
118        config.instruction_preset
119    ));
120    for (provider, provider_config) in &config.providers {
121        ui::print_info(&format!(
122            "\nProvider: {}\nAPI Key: {}\nModel: {}\nToken Limit: {}\nAdditional Parameters: {:?}",
123            provider,
124            if provider_config.api_key.is_empty() {
125                "Not set"
126            } else {
127                "Set"
128            },
129            provider_config.model,
130            provider_config
131                .token_limit
132                .map_or("Default".to_string(), |limit| limit.to_string()),
133            provider_config.additional_params
134        ));
135    }
136
137    Ok(())
138}
139
140/// Parse additional parameters from the command line
141fn parse_additional_params(params: &[String]) -> HashMap<String, String> {
142    params
143        .iter()
144        .filter_map(|param| {
145            let parts: Vec<&str> = param.splitn(2, '=').collect();
146            if parts.len() == 2 {
147                Some((parts[0].to_string(), parts[1].to_string()))
148            } else {
149                None
150            }
151        })
152        .collect()
153}
154
155/// Handle the '`list_presets`' command
156pub fn handle_list_presets_command() -> Result<()> {
157    let preset_library = get_instruction_preset_library();
158
159    println!(
160        "{}",
161        "\nšŸ”® Available Instruction Presets šŸ”®"
162            .bright_purple()
163            .bold()
164    );
165    println!("{}", "━".repeat(50).bright_purple());
166
167    let mut presets = preset_library.list_presets();
168    presets.sort_by(|a, b| a.0.cmp(b.0)); // Sort alphabetically by key
169
170    let max_key_length = presets
171        .iter()
172        .map(|(key, _)| key.width())
173        .max()
174        .unwrap_or(0);
175
176    for (key, preset) in presets {
177        println!(
178            "{} {:<width$} {}",
179            "•".bright_cyan(),
180            key.bright_green().bold(),
181            preset.name.cyan().italic(),
182            width = max_key_length
183        );
184        println!("  {}", format!("\"{}\"", preset.description).bright_white());
185        println!(); // Add a blank line between presets
186    }
187
188    println!("{}", "━".repeat(50).bright_purple());
189    println!(
190        "{}",
191        "Use with: git-iris gen --preset <preset-name>"
192            .bright_yellow()
193            .italic()
194    );
195
196    Ok(())
197}