diff --git a/README.md b/README.md index 0a2cd94..a4968b1 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Features: - zsh autocomplete - nushell autocomplete - manpage +- configurable mod search result display like [Starship](https://starship.rs) +- `display` command or something that displays (cached?) mod info - parallel mod downloading Long-term/host-dependent: @@ -111,13 +113,6 @@ $ hopper add sodium --mc-version 1.17 :: ... ``` -- configurable mod search results like [Starship](https://starship.rs) -- pad mod indices based on largest number -- option in config to reverse sorting order -- add parameter to restrict target Minecraft version -- manually pick out Minecraft version -- square colored creeper face progress indicator (from top-left clockwise spiral in) - ## `hopper get` Just like `hopper add` but simply downloads a mod jar to the current directory. diff --git a/src/main.rs b/src/main.rs index eb8dc72..ec023c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,18 +7,23 @@ use std::io::Write; use std::path::PathBuf; use structopt::StructOpt; +// TODO parameter to restrict target Minecraft version +#[derive(StructOpt, Clone, Debug)] +struct SearchArgs { + package_name: String, +} + // TODO use ColoredHelp by default? -// TODO move each enum value to a dedicated struct #[derive(StructOpt, Clone, Debug)] enum Command { /// Adds a mod to the current instance #[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] - Add { package_name: String }, + Add(SearchArgs), /// Removes a mod #[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] Remove { package_name: String }, #[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] - Get { package_name: String }, + Get(SearchArgs), #[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] Update, #[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] @@ -148,7 +153,7 @@ impl ModResult { let index = style(index).magenta(); let info = self.format_info(); let description = self.format_description(); - println!("{} {}\n {}", index, info, description); + println!("{:>2} {}\n {}", index, info, description); } } @@ -163,8 +168,7 @@ struct ModInfo { published: String, // TODO serialize datetime updated: String, // TODO serialize datetime status: String, - // TODO License object - // license: String, + license: License, client_side: String, // TODO serialize as enum server_side: String, // TODO serialize as enum downloads: isize, @@ -179,6 +183,13 @@ struct ModInfo { donation_urls: Vec, } +#[derive(Deserialize, Debug)] +struct License { + id: String, + name: String, + url: String, +} + #[derive(Deserialize, Debug)] struct ModVersion { id: String, // version id @@ -206,10 +217,10 @@ struct ModVersionFile { filename: String, } -async fn search_mods(ctx: &AppContext, query: String) -> anyhow::Result { +async fn search_mods(ctx: &AppContext, search_args: &SearchArgs) -> anyhow::Result { let client = reqwest::Client::new(); let url = format!("https://{}/api/v1/mod", ctx.config.upstream.server_address); - let params = [("query", query.as_str())]; + let params = [("query", search_args.package_name.as_str())]; let url = reqwest::Url::parse_with_params(url.as_str(), ¶ms)?; let response = client .get(url) @@ -220,7 +231,6 @@ async fn search_mods(ctx: &AppContext, query: String) -> anyhow::Result anyho let total_size = response.content_length().unwrap(); // TODO better colors and styling! + // TODO square colored creeper face progress indicator (from top-left clockwise spiral in) use indicatif::{ProgressBar, ProgressStyle}; let pb = ProgressBar::new(total_size); pb.set_style(ProgressStyle::default_bar().template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").progress_chars("#>-")); @@ -337,8 +348,8 @@ async fn download_version_file(ctx: &AppContext, file: &ModVersionFile) -> anyho Ok(()) } -async fn cmd_get(ctx: &AppContext, package_name: String) -> anyhow::Result<()> { - let response = search_mods(ctx, package_name).await?; +async fn cmd_get(ctx: &AppContext, search_args: SearchArgs) -> anyhow::Result<()> { + let response = search_mods(ctx, &search_args).await?; if response.hits.is_empty() { // TODO formatting @@ -378,7 +389,7 @@ async fn main() -> anyhow::Result<()> { let config = args.load_config()?; let ctx = AppContext { args, config }; match ctx.args.to_owned().command { - Command::Get { package_name } => cmd_get(&ctx, package_name).await, + Command::Get(search_args) => cmd_get(&ctx, search_args).await, _ => unimplemented!("unimplemented subcommand"), } }