1use crate::config::Config;
2use crate::instruction_presets::{PresetType, get_instruction_preset_library};
3use crate::providers::{Provider, ProviderConfig};
4use anyhow::Result;
5use clap::Args;
6
7#[derive(Args, Clone, Default, Debug)]
8pub struct CommonParams {
9 #[arg(long, help = "Override default LLM provider", value_parser = available_providers_parser)]
11 pub provider: Option<String>,
12
13 #[arg(long, help = "Override model for this operation")]
15 pub model: Option<String>,
16
17 #[arg(short, long, help = "Custom instructions for this operation")]
19 pub instructions: Option<String>,
20
21 #[arg(
23 long,
24 help = "Select an instruction preset (use 'git-iris list-presets' to see available presets for commits and reviews)"
25 )]
26 pub preset: Option<String>,
27
28 #[arg(
30 long = "gitmoji",
31 help = "Enable Gitmoji",
32 conflicts_with = "no_gitmoji",
33 action = clap::ArgAction::SetTrue
34 )]
35 pub gitmoji_flag: bool,
36
37 #[arg(long = "no-gitmoji", help = "Disable Gitmoji", action = clap::ArgAction::SetTrue)]
39 pub no_gitmoji: bool,
40
41 #[arg(skip)]
43 pub gitmoji: Option<bool>,
44
45 #[arg(
47 short = 'r',
48 long = "repo",
49 help = "Repository URL to use instead of local repository"
50 )]
51 pub repository_url: Option<String>,
52}
53
54impl CommonParams {
55 #[must_use]
58 pub fn resolved_gitmoji(&self) -> Option<bool> {
59 if self.gitmoji_flag {
60 Some(true)
61 } else if self.no_gitmoji {
62 Some(false)
63 } else {
64 self.gitmoji }
66 }
67
68 pub fn apply_to_config(&self, config: &mut Config) -> Result<bool> {
69 let mut changes_made = false;
70
71 if let Some(provider_str) = &self.provider {
72 let provider: Provider = provider_str.parse()?;
74 let provider_name = provider.name().to_string();
75
76 if config.default_provider != provider_name {
78 if !config.providers.contains_key(&provider_name) {
80 config.providers.insert(
81 provider_name.clone(),
82 ProviderConfig::with_defaults(provider),
83 );
84 }
85
86 config.default_provider = provider_name;
87 changes_made = true;
88 }
89 }
90
91 if let Some(model) = &self.model {
93 let provider_name = config.default_provider.clone();
94 if let Some(provider_config) = config.providers.get_mut(&provider_name) {
95 provider_config.model.clone_from(model);
96 changes_made = true;
97 }
98 }
99
100 if let Some(instructions) = &self.instructions {
101 config.set_temp_instructions(Some(instructions.clone()));
102 }
103
104 if let Some(preset) = &self.preset {
105 config.set_temp_preset(Some(preset.clone()));
106 }
107
108 if let Some(use_gitmoji) = self.resolved_gitmoji() {
110 config.gitmoji_override = Some(use_gitmoji);
111 if config.use_gitmoji != use_gitmoji {
112 config.use_gitmoji = use_gitmoji;
113 changes_made = true;
114 }
115 }
116
117 Ok(changes_made)
118 }
119
120 pub fn is_valid_preset_for_type(&self, preset_type: PresetType) -> bool {
122 if let Some(preset_name) = &self.preset {
123 let library = get_instruction_preset_library();
124 let valid_presets = library.list_valid_presets_for_command(preset_type);
125 return valid_presets.iter().any(|(key, _)| *key == preset_name);
126 }
127 true }
129}
130
131pub fn available_providers_parser(s: &str) -> Result<String, String> {
133 match s.parse::<Provider>() {
134 Ok(provider) => Ok(provider.name().to_string()),
135 Err(_) => Err(format!(
136 "Invalid provider '{}'. Available providers: {}",
137 s,
138 Provider::all_names().join(", ")
139 )),
140 }
141}