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> {
73 let mut changes_made = false;
74
75 if let Some(provider_str) = &self.provider {
76 let provider: Provider = provider_str.parse()?;
78 let provider_name = provider.name().to_string();
79
80 if config.default_provider != provider_name {
82 if !config.providers.contains_key(&provider_name) {
84 config.providers.insert(
85 provider_name.clone(),
86 ProviderConfig::with_defaults(provider),
87 );
88 }
89
90 config.default_provider = provider_name;
91 changes_made = true;
92 }
93 }
94
95 if let Some(model) = &self.model {
97 let provider_name = config.default_provider.clone();
98 if let Some(provider_config) = config.providers.get_mut(&provider_name) {
99 provider_config.model.clone_from(model);
100 changes_made = true;
101 }
102 }
103
104 if let Some(instructions) = &self.instructions {
105 config.set_temp_instructions(Some(instructions.clone()));
106 }
107
108 if let Some(preset) = &self.preset {
109 config.set_temp_preset(Some(preset.clone()));
110 }
111
112 if let Some(use_gitmoji) = self.resolved_gitmoji() {
114 config.gitmoji_override = Some(use_gitmoji);
115 if config.use_gitmoji != use_gitmoji {
116 config.use_gitmoji = use_gitmoji;
117 changes_made = true;
118 }
119 }
120
121 Ok(changes_made)
122 }
123
124 #[must_use]
126 pub fn is_valid_preset_for_type(&self, preset_type: PresetType) -> bool {
127 if let Some(preset_name) = &self.preset {
128 let library = get_instruction_preset_library();
129 let valid_presets = library.list_valid_presets_for_command(preset_type);
130 return valid_presets.iter().any(|(key, _)| *key == preset_name);
131 }
132 true }
134}
135
136pub fn available_providers_parser(s: &str) -> Result<String, String> {
142 match s.parse::<Provider>() {
143 Ok(provider) => Ok(provider.name().to_string()),
144 Err(_) => Err(format!(
145 "Invalid provider '{}'. Available providers: {}",
146 s,
147 Provider::all_names().join(", ")
148 )),
149 }
150}