diff --git a/Cargo.lock b/Cargo.lock index 7eb1975..132549d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "3.6.0" dependencies = [ "chrono", "clap", + "clap_complete", "colored", "libc", "mimalloc", @@ -124,6 +125,21 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap_complete" +version = "3.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4179da71abd56c26b54dd0c248cc081c1f43b0a1a7e8448e28e57a29baa993d" +dependencies = [ + "clap", + "clap_lex", + "is_executable", + "os_str_bytes", + "pathdiff", + "shlex", + "unicode-xid", +] + [[package]] name = "clap_derive" version = "3.2.17" @@ -271,6 +287,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "is_executable" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +dependencies = [ + "winapi", +] + [[package]] name = "itoa" version = "1.0.3" @@ -437,6 +462,12 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -620,6 +651,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "smawk" version = "0.3.1" @@ -795,6 +832,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + [[package]] name = "ureq" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 960b01f..9a05059 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ codegen-units = 1 [dependencies] mimalloc = { version = "0.1.29", default-features = false } clap = { version = "3.2.8", features = [ "derive", "wrap_help" ] } +clap_complete = { version = "3.2.4", features = [ "unstable-dynamic" ] } regex = { version = "1.5.6", default-features = false, features = [ "std", "unicode-perl" ] } colored = "2.0.0" ureq = { version = "2.4.0", default-features = false, features = [ "native-tls", "json" ] } diff --git a/src/args.rs b/src/args.rs index 4e2ec66..f8a46f5 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,9 +1,9 @@ #![allow(clippy::module_name_repetitions)] -use clap::{Parser, Subcommand}; +use clap::{Parser, Subcommand, ValueHint}; #[derive(Debug, Clone, Parser)] -#[clap(name = "Amethyst", version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"), infer_subcommands = true)] +#[clap(bin_name = "ame", name = "Amethyst", version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"), infer_subcommands = true)] pub struct Args { #[clap(subcommand)] pub subcommand: Option, @@ -21,7 +21,7 @@ pub struct Args { pub sudoloop: bool, /// Sets a custom AUR clone and build directory for the specified operation - #[clap(long, short, global = true)] + #[clap(long, short, global = true, value_hint = ValueHint::DirPath)] pub cachedir: Option, } @@ -51,6 +51,10 @@ pub enum Operation { #[clap(name = "upgrade", visible_aliases = & ["-Syu"])] Upgrade(UpgradeArgs), + /// Generates shell completions for supported shells (bash, zsh, fish, elvish, pwsh) + #[clap(name = "gencomp", visible_aliases = & ["-g"])] + GenComp(GenCompArgs), + /// Removes all orphaned packages #[clap(name = "clean", visible_aliases = & ["-Sc"])] Clean, @@ -131,3 +135,10 @@ pub struct UpgradeArgs { #[clap(long, short)] pub aur: bool, } + +#[derive(Default, Debug, Clone, Parser)] +pub struct GenCompArgs { + /// The shell to generate completions for + #[clap(required = true)] + pub shell: String, +} diff --git a/src/main.rs b/src/main.rs index b1a08ed..4659e03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,13 +7,16 @@ use internal::commands::ShellCommand; use internal::error::SilentUnwrap; use std::fs; use std::path::Path; +use std::str::FromStr; use crate::args::{ - InfoArgs, InstallArgs, Operation, QueryArgs, RemoveArgs, SearchArgs, UpgradeArgs, + GenCompArgs, InfoArgs, InstallArgs, Operation, QueryArgs, RemoveArgs, SearchArgs, UpgradeArgs, }; use crate::internal::exit_code::AppExitCode; use crate::internal::{detect, init, sort, start_sudoloop, structs::Options}; +use clap_complete::{Generator, Shell}; + #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -86,6 +89,10 @@ fn main() { info!("Running pacdiff"); detect(); } + Operation::GenComp(gencomp_args) => { + info!("Generating shell completions for {}. Please pipe `stderr` to a file to get completions as a file, e.g. `ame gencomp fish 2> file.fish`", gencomp_args.shell); + cmd_gencomp(&gencomp_args); + } } } @@ -205,3 +212,14 @@ fn cmd_upgrade(args: UpgradeArgs, options: Options, cachedir: &str) { info!("Performing system upgrade"); operations::upgrade(options, args, cachedir); } + +fn cmd_gencomp(args: &GenCompArgs) { + let shell: Shell = Shell::from_str(&args.shell).unwrap_or_else(|e| { + crash!(AppExitCode::Other, "Invalid shell: {}", e); + }); + + shell.generate( + &::command(), + &mut std::io::stderr(), + ); +}