diff --git a/Cargo.lock b/Cargo.lock index d0ebf11..7c34012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,12 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bumpalo" version = "3.11.1" @@ -163,6 +169,18 @@ dependencies = [ "windows-targets 0.52.0", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags", + "clap_lex 0.2.4", + "indexmap", + "textwrap", +] + [[package]] name = "clap" version = "4.5.4" @@ -181,10 +199,28 @@ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", - "clap_lex", + "clap_lex 0.7.0", "strsim", ] +[[package]] +name = "clap_complete" +version = "3.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" +dependencies = [ + "clap 3.2.25", +] + +[[package]] +name = "clap_complete" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" +dependencies = [ + "clap 4.5.4", +] + [[package]] name = "clap_derive" version = "4.5.4" @@ -197,6 +233,25 @@ dependencies = [ "syn 2.0.10", ] +[[package]] +name = "clap_generate" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1b28c4a802ac3628604fd267cac62aaea74dc61af3410db6b1c44c03b42599" +dependencies = [ + "clap 3.2.25", + "clap_complete 3.2.5", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.7.0" @@ -275,6 +330,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.5.0" @@ -314,6 +375,16 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.4" @@ -351,7 +422,9 @@ dependencies = [ "base64 0.22.0", "bunt", "chrono", - "clap", + "clap 4.5.4", + "clap_complete 4.5.1", + "clap_generate", "jsonwebtoken", "parse_duration", "serde", @@ -499,6 +572,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "parse_duration" version = "2.1.1" @@ -723,6 +802,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + [[package]] name = "thiserror" version = "1.0.37" diff --git a/Cargo.toml b/Cargo.toml index 1d95e17..a8177a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,8 @@ chrono = "0.4" parse_duration = "2.1.1" atty = "0.2" base64 = "0.22.0" +clap_generate = "3.0.3" +clap_complete = "4.5.1" [dev-dependencies] tempdir = "0.3.7" diff --git a/README.md b/README.md index 3540b6c..7295f49 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,22 @@ curl | jq -r .access_token | jwt decode - Currently the underlying token encoding and decoding library, [`jsonwebtoken`](https://github.com/Keats/jsonwebtoken), doesn't support the SEC1 private key format and requires a conversion to the PKCS8 type. You can read more from [their own README](https://github.com/Keats/jsonwebtoken/blob/8fba79b25459eacc33a80e1ee37ff8eba64079ca/README.md#convert-sec1-private-key-to-pkcs8). +## Shell completion + +`jwt-cli` supports shell completion for `bash`, `elvish`, `fish`, `powershell`, and `zsh`. To enable it, run the following command: + +```sh +source <(jwt completion bash) +``` + +You may want to add this to your shell profile to have it available every time you open a new shell: + +```sh +if hash jwt > /dev/null; then + source <(jwt completion bash) +fi +``` + # Contributing I welcome all issues and pull requests! This is my first project in rust, so this project almost certainly could be better written. All I ask is that you follow the [code of conduct](code_of_conduct.md) and use [rustfmt](https://github.com/rust-lang-nursery/rustfmt) to have a consistent project code style. diff --git a/src/cli_config.rs b/src/cli_config.rs index 65cbafa..e5fb82f 100644 --- a/src/cli_config.rs +++ b/src/cli_config.rs @@ -2,6 +2,7 @@ use crate::translators::{PayloadItem, SupportedTypes, TimeFormat}; use crate::utils::parse_duration_string; use chrono::format::{parse, Parsed, StrftimeItems}; use clap::{Parser, Subcommand, ValueEnum}; +use clap_complete::Shell; use jsonwebtoken::Algorithm; use std::path::PathBuf; @@ -22,6 +23,17 @@ pub enum Commands { /// Decode a JWT Decode(DecodeArgs), + + /// Print completion + Completion(CompletionArgs), +} + +#[derive(Debug, Clone, Parser)] +pub struct CompletionArgs { + /// the shell to generate completions for + #[clap(value_enum)] + #[clap(index = 1)] + pub shell: Shell, } #[derive(Debug, Clone, Parser)] diff --git a/src/main.rs b/src/main.rs index fcc8c2c..f13fda9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ -use clap::Parser; +use clap::{Command, CommandFactory, Parser}; +use clap_complete::{generate, Generator}; use cli_config::{App, Commands, EncodeArgs}; +use std::io; use std::process::exit; use translators::decode::{decode_token, print_decoded_token}; use translators::encode::{encode_token, print_encoded_token}; @@ -14,6 +16,10 @@ fn warn_unsupported(arguments: &EncodeArgs) { }; } +fn print_completions(gen: G, cmd: &mut Command) { + generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout()); +} + fn main() { let app = App::parse(); // let matches = config_options().get_matches(); @@ -41,5 +47,10 @@ fn main() { }, ); } + Commands::Completion(arguments) => { + let mut cmd = App::command(); + print_completions(arguments.shell, &mut cmd); + exit(0) + } }; }