diff --git a/Cargo.lock b/Cargo.lock index b0a4d44..b1f9829 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -38,52 +38,12 @@ dependencies = [ ] [[package]] -name = "anstream" -version = "0.6.14" +name = "ansi_term" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", + "winapi", ] [[package]] @@ -137,6 +97,17 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -159,9 +130,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -242,51 +213,19 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "clap" -version = "4.5.4" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim 0.11.1", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.66", + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", ] -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - [[package]] name = "colored" version = "2.1.0" @@ -671,9 +610,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "git-ai" @@ -681,7 +620,6 @@ version = "0.1.38" dependencies = [ "anyhow", "async-openai", - "clap", "colored", "config", "console", @@ -699,6 +637,7 @@ dependencies = [ "serde_derive", "serde_ini", "serde_json", + "structopt", "tempfile", "thiserror", "tokio", @@ -755,9 +694,21 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" -version = "0.5.0" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] [[package]] name = "hermit-abi" @@ -925,17 +876,11 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - [[package]] name = "itoa" version = "1.0.11" @@ -1134,7 +1079,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -1146,9 +1091,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -1300,6 +1245,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.84" @@ -1692,6 +1661,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.10.0" @@ -1699,10 +1674,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "strsim" -version = "0.11.1" +name = "structopt" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "syn" @@ -1775,13 +1768,12 @@ dependencies = [ ] [[package]] -name = "terminal_size" -version = "0.3.0" +name = "textwrap" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "rustix", - "windows-sys 0.48.0", + "unicode-width", ] [[package]] @@ -1985,6 +1977,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.12" @@ -2008,18 +2006,18 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" @@ -2136,6 +2134,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.8" @@ -2145,6 +2159,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 78ce6ed..a12dd47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ path = "src/bin/hook.rs" [dependencies] anyhow = "1.0.86" async-openai = "0.18.3" -clap = { version = "4.5.4", features = ["derive", "wrap_help"] } colored = "2.1.0" config = "0.13.4" console = "0.15.8" @@ -38,6 +37,7 @@ serde = { version = "1", features = ["derive"] } serde_derive = "1.0.203" serde_ini = "0.2.0" serde_json = "1.0.117" +structopt = { version = "0.3.26", features = ["color", "suggestions"] } thiserror = "1.0.61" tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] } diff --git a/src/bin/hook.rs b/src/bin/hook.rs index f92d688..ace537e 100644 --- a/src/bin/hook.rs +++ b/src/bin/hook.rs @@ -1,19 +1,30 @@ -// Hook: prepare-commit-msg - use std::time::Duration; +use structopt::StructOpt; use indicatif::{ProgressBar, ProgressStyle}; use anyhow::{Context, Result}; use git2::{Oid, Repository}; use ai::{commit, config}; -use clap::Parser; use ai::hook::*; +#[derive(StructOpt, Debug)] +#[structopt(name = "commit-msg-hook")] +struct Args { + #[structopt(short = "t", long = "type")] + commit_type: Option, + + #[structopt(short = "s", long = "sha1")] + sha1: Option, + + #[structopt(parse(from_os_str))] + commit_msg_file: std::path::PathBuf +} + #[tokio::main] async fn main() -> Result<()> { env_logger::init(); - let args = Args::parse(); + let args = Args::from_args(); let max_tokens = config::APP.max_tokens; let pb = ProgressBar::new_spinner(); let repo = Repository::open_from_env().context("Failed to open repository")?; @@ -66,10 +77,7 @@ async fn main() -> Result<()> { let response = commit::generate(patch.to_string()).await?; // Write the response to the commit message file - args - .commit_msg_file - .write(response.response.trim().to_string()) - .unwrap(); + std::fs::write(&args.commit_msg_file, response.response.trim())?; pb.finish_and_clear(); diff --git a/src/config.rs b/src/config.rs index 88cb651..80bba27 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,8 +6,7 @@ use serde::{Deserialize, Serialize}; use config::{Config, FileFormat}; use anyhow::{Context, Result}; use lazy_static::lazy_static; -use console::{style, Emoji}; -use clap::ArgMatches; +use console::Emoji; #[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)] pub struct App { @@ -27,10 +26,10 @@ impl App { } lazy_static! { - pub static ref CONFIG_DIR: PathBuf = home::home_dir().unwrap().join(".config/git-ai"); - #[derive(Debug)] - pub static ref APP: App = App::new().expect("Failed to load config"); - pub static ref CONFIG_PATH: PathBuf = CONFIG_DIR.join("config.ini"); + pub static ref CONFIG_DIR: PathBuf = home::home_dir().unwrap().join(".config/git-ai"); + #[derive(Debug)] + pub static ref APP: App = App::new().expect("Failed to load config"); + pub static ref CONFIG_PATH: PathBuf = CONFIG_DIR.join("config.ini"); } impl App { @@ -49,9 +48,9 @@ impl App { .add_source(config::File::new(CONFIG_PATH.to_str().unwrap(), FileFormat::Ini)) .set_default("language", "en")? .set_default("timeout", 30)? - .set_default("max_commit_length", 72)? - .set_default("max_tokens", 512)? - .set_default("model", "gpt-4-turbo-preview")? + .set_default("max-commit-length", 72)? + .set_default("max-tokens", 2024)? + .set_default("model", "gpt-4o")? .build()?; config @@ -68,51 +67,30 @@ impl App { } } -pub fn run(args: &ArgMatches) -> Result<()> { +pub fn run_model(value: String) -> Result<()> { let mut app = App::new()?; - match args.subcommand() { - Some(("model", args)) => { - app.model.clone_from( - args - .get_one::("") - .context("Failed to parse model")? - ); - } - Some(("language", args)) => { - app.language.clone_from( - args - .get_one::("") - .context("Failed to parse language")? - ); - } - Some(("max-tokens", args)) => { - app.max_tokens.clone_from( - args - .get_one("max-tokens") - .context("Failed to parse max-tokens")? - ); - } - Some(("max-commit-length", args)) => { - app.max_commit_length.clone_from( - args - .get_one("max-commit-length") - .context("Failed to parse max-commit-length")? - ); - } - Some(("openai-api-key", args)) => { - app.openai_api_key.clone_from(&Some( - args - .get_one::("") - .context("Failed to parse openai-api-key")? - .to_owned() - )); - } - _ => unreachable!() - } + app.model = value; + println!("{} Configuration option model updated!", Emoji("✨", ":-)")); + app.save() +} - if let Some(key) = args.subcommand_name() { - println!("{} Configuration option {} updated!", Emoji("✨", ":-)"), style(key).italic()); - } +pub fn run_max_tokens(max_tokens: usize) -> Result<()> { + let mut app = App::new()?; + app.max_tokens = max_tokens; + println!("{} Configuration option max-tokens updated!", Emoji("✨", ":-)")); + app.save() +} + +pub fn run_max_commit_length(max_commit_length: usize) -> Result<()> { + let mut app = App::new()?; + app.max_commit_length = max_commit_length; + println!("{} Configuration option max-commit-length updated!", Emoji("✨", ":-)")); + app.save() +} +pub fn run_openai_api_key(value: String) -> Result<()> { + let mut app = App::new()?; + app.openai_api_key = Some(value); + println!("{} Configuration option openai-api-key updated!", Emoji("✨", ":-)")); app.save() } diff --git a/src/hook.rs b/src/hook.rs index c7800e7..f4788ae 100644 --- a/src/hook.rs +++ b/src/hook.rs @@ -3,10 +3,10 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::fs::File; +use structopt::StructOpt; use git2::{Diff, DiffFormat, DiffOptions, Repository, Tree}; use anyhow::{Context, Result}; use thiserror::Error; -use clap::Parser; use crate::commit::ChatError; @@ -87,24 +87,24 @@ impl PatchDiff for Diff<'_> { } #[rustfmt::skip] - self.print(DiffFormat::Patch, |diff, _hunk, line| { - let diff_path = diff.path(); - let Some(tokens) = token_table.get_mut(&diff_path) else { - return true; - }; - - let content = line.content(); - let curr_tokens = content.to_utf8().split_whitespace().count(); - if *tokens + curr_tokens < tokens_per_file { - *tokens += curr_tokens; - patch_acc.extend_from_slice(content); - } else { - patch_acc.extend_from_slice(truncated_message.as_bytes()); - token_table.remove(&diff_path); - } - - true - }).context("Failed to print diff")?; + self.print(DiffFormat::Patch, |diff, _hunk, line| { + let diff_path = diff.path(); + let Some(tokens) = token_table.get_mut(&diff_path) else { + return true; + }; + + let content = line.content(); + let curr_tokens = content.to_utf8().split_whitespace().count(); + if *tokens + curr_tokens < tokens_per_file { + *tokens += curr_tokens; + patch_acc.extend_from_slice(content); + } else { + patch_acc.extend_from_slice(truncated_message.as_bytes()); + token_table.remove(&diff_path); + } + + true + }).context("Failed to print diff")?; Ok(patch_acc.to_utf8()) } @@ -144,15 +144,15 @@ impl PatchRepository for Repository { } } -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] +#[derive(StructOpt, Debug)] +#[structopt(name = "commit-msg-hook", about = "A tool for generating commit messages.")] pub struct Args { pub commit_msg_file: PathBuf, - #[clap(required = false)] + #[structopt(short = "t", long = "type")] pub commit_type: Option, - #[clap(required = false)] + #[structopt(short = "s", long = "sha1")] pub sha1: Option } diff --git a/src/main.rs b/src/main.rs index 1f54848..ba387ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,68 +3,63 @@ mod install; mod reinstall; mod config; -use clap::{Arg, Command}; +use structopt::StructOpt; use anyhow::Result; use dotenv::dotenv; -fn cli() -> Command { - Command::new("git-ai") - .about("A git extension that uses OpenAI to generate commit messages") - .subcommand_required(true) - .arg_required_else_help(true) - .subcommand( - Command::new("hook") - .about("Installs the git-ai hook") - .subcommand(Command::new("install").about("Installs the git-ai hook")) - .subcommand(Command::new("uninstall").about("Uninstalls the git-ai hook")) - .subcommand(Command::new("reinstall").about("Reinstalls the git-ai hook")) - ) - .subcommand( - Command::new("config") - .about("Sets or gets configuration values") - .subcommand( - Command::new("set") - .about("Sets a configuration value") - .subcommand( - Command::new("model").about("Sets the model to use").arg( - Arg::new("") - .required(true) - .index(1) - .value_parser(clap::builder::NonEmptyStringValueParser::new()) - ) - ) - .subcommand( - Command::new("max-tokens") - .about("Sets the maximum number of tokens to use for the diff") - .arg( - Arg::new("max-tokens") - .required(true) - .index(1) - .value_parser(clap::value_parser!(usize)) - ) - ) - .subcommand( - Command::new("max-commit-length") - .about("Sets the maximum length of the commit message") - .arg( - Arg::new("max-commit-length") - .required(true) - .index(1) - .value_parser(clap::value_parser!(usize)) - ) - ) - .subcommand( - Command::new("openai-api-key") - .about("Sets the OpenAI API key") - .arg( - Arg::new("") - .required(true) - .index(1) - .value_parser(clap::builder::NonEmptyStringValueParser::new()) - ) - ) - ) - ) +#[derive(StructOpt)] +#[structopt(name = "git-ai", about = "A git extension that uses OpenAI to generate commit messages")] +enum Cli { + #[structopt(about = "Installs the git-ai hook")] + Hook(HookSubcommand), + #[structopt(about = "Sets or gets configuration values")] + Config(ConfigSubcommand) +} + +#[derive(StructOpt)] +enum HookSubcommand { + #[structopt(about = "Installs the git-ai hook")] + Install, + #[structopt(about = "Uninstalls the git-ai hook")] + Uninstall, + #[structopt(about = "Reinstalls the git-ai hook")] + Reinstall +} + +#[derive(StructOpt)] +enum ConfigSubcommand { + #[structopt(about = "Sets a configuration value")] + Set(SetSubcommand) +} + +#[derive(StructOpt)] +enum SetSubcommand { + #[structopt(about = "Sets the model to use")] + Model(Model), + + #[structopt(about = "Sets the maximum number of tokens to use for the diff")] + MaxTokens { + #[structopt(help = "The maximum number of tokens", name = "max-tokens")] + max_tokens: usize + }, + + #[structopt(about = "Sets the maximum length of the commit message")] + MaxCommitLength { + #[structopt(help = "The maximum length of the commit message", name = "max-commit-length")] + max_commit_length: usize + }, + + #[structopt(about = "Sets the OpenAI API key")] + OpenaiApiKey { + #[structopt(help = "The OpenAI API key", name = "VALUE")] + value: String + } +} + +#[derive(StructOpt)] +struct Model { + #[structopt(help = "The value to set", name = "VALUE")] + value: String } #[tokio::main(flavor = "multi_thread")] @@ -72,32 +67,39 @@ async fn main() -> Result<()> { env_logger::init(); dotenv().ok(); - let args = cli().get_matches(); + let args = Cli::from_args(); - match args.subcommand() { - Some(("hook", sub)) => - match sub.subcommand() { - Some(("install", _)) => { + match args { + Cli::Hook(sub) => + match sub { + HookSubcommand::Install => { install::run()?; } - - Some(("uninstall", _)) => { + HookSubcommand::Uninstall => { uninstall::run()?; } - - Some(("reinstall", _)) => { + HookSubcommand::Reinstall => { reinstall::run()?; } - _ => unreachable!() }, - Some(("config", args)) => - match args.subcommand() { - Some(("set", args)) => { - config::run(args)?; - } - _ => unreachable!() + Cli::Config(config) => + match config { + ConfigSubcommand::Set(set) => + match set { + SetSubcommand::Model(model) => { + config::run_model(model.value)?; + } + SetSubcommand::MaxTokens { max_tokens } => { + config::run_max_tokens(max_tokens)?; + } + SetSubcommand::MaxCommitLength { max_commit_length } => { + config::run_max_commit_length(max_commit_length)?; + } + SetSubcommand::OpenaiApiKey { value } => { + config::run_openai_api_key(value)?; + } + }, }, - _ => unreachable!() } Ok(())