diff --git a/Cargo.lock b/Cargo.lock index 30636e1..5fb04a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -175,6 +175,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.18" @@ -424,6 +433,7 @@ version = "0.2.2" dependencies = [ "anyhow", "clap", + "clap_complete", "copypasta", "dirs", "human-panic", diff --git a/Cargo.toml b/Cargo.toml index be4a16d..410139a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ categories = ["development-tools", "command-line-utilities"] [dependencies] anyhow = "1.0.89" clap = { version = "4.5.20", features = ["derive"] } +clap_complete = "^4.5" copypasta = "0.8.2" dirs = "5.0.1" human-panic = "2.0.2" @@ -25,7 +26,10 @@ ratatui = "0.28.1" serde = { version = "1.0.210", features = ["default", "derive"] } serde_json = "1.0.128" tui-input = "0.10.1" -ureq = { version = "2.10.1", features = ["gzip", "native-tls"], default-features = false } +ureq = { version = "2.10.1", features = [ + "gzip", + "native-tls", +], default-features = false } url = "2.5.2" yansi = "1.0.1" @@ -53,16 +57,16 @@ pkg-url = "{ repo }/releases/download/v{ version }/{ name }-macos-arm64" [package.metadata.cross.target.x86_64-unknown-linux-gnu] pre-build = [ - "dpkg --add-architecture $CROSS_DEB_ARCH", - "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH" + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH", ] [package.metadata.cross.target.i686-unknown-linux-gnu] pre-build = [ - "dpkg --add-architecture $CROSS_DEB_ARCH", - "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH" + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH", ] [package.metadata.cross.target.aarch64-unknown-linux-gnu] pre-build = [ - "dpkg --add-architecture $CROSS_DEB_ARCH", - "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH" + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update && apt-get --assume-yes install pkg-config libssl-dev:$CROSS_DEB_ARCH", ] diff --git a/src/cli.rs b/src/cli.rs index ea71f18..e629db9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,6 +2,7 @@ use crate::template::item::Template; use crate::template::list::TemplateList; use anyhow::{bail, Context, Result}; use clap::{Args, Parser, Subcommand}; +use clap_complete::Shell; use once_cell::sync::Lazy; const LONG_ABOUT: &str = r" @@ -18,7 +19,7 @@ You can also browse the available templates at the GitHub & TopTal collections using the `search` command."; #[derive(Parser, Debug)] -#[command(author, version, about, long_about = LONG_ABOUT)] +#[command(author, version, about, long_about = LONG_ABOUT, arg_required_else_help = true)] pub struct Cli { /// Refresh the cache (templates are cached for 1h) #[arg(short = 'r', long = "refresh", global = true)] @@ -66,6 +67,11 @@ pub enum Commands { Create(CommandCreate), /// Choose templates interactively from the GitHub & TopTal collections Search, + /// Generate completions to stdout + Completions { + /// Specify desired shell + shell: Shell, + }, } impl Cli { @@ -76,6 +82,9 @@ impl Cli { Some(Commands::Search) => { bail!("Cannot provide template arguments to 'search' command") } + Some(Commands::Completions { shell: _ }) => { + bail!("Cannot provide template arguments to 'completions' command") + } None => bail!("Cannot provide template arguments to an unknown command"), }; diff --git a/src/commands/completions.rs b/src/commands/completions.rs new file mode 100644 index 0000000..f258606 --- /dev/null +++ b/src/commands/completions.rs @@ -0,0 +1,15 @@ +use std::io; + +use anyhow::Result; +use clap::CommandFactory; +use clap_complete::{generate, Shell}; + +use crate::cli::Cli; + +pub fn command(shell: &Shell) -> Result<()> { + let cmd = &mut Cli::command(); + + generate(*shell, cmd, cmd.get_name().to_string(), &mut io::stdout()); + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index eede39f..8f87748 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,2 +1,3 @@ +pub mod completions; pub mod create; pub mod search; diff --git a/src/commands/search/framework/mod.rs b/src/commands/search/framework/mod.rs index 23053e2..7931655 100644 --- a/src/commands/search/framework/mod.rs +++ b/src/commands/search/framework/mod.rs @@ -1,5 +1,5 @@ /// From: https://github.com/ratatui-org/rust-tui-template - +/// /// Terminal UI events handler pub mod event; diff --git a/src/main.rs b/src/main.rs index 9959175..ef20d1a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod tests; mod util; use crate::cli::{get_cli, Commands}; +use crate::commands::completions; use crate::commands::create; use crate::commands::search; use anyhow::{anyhow, Result}; @@ -20,6 +21,7 @@ fn main() -> Result<()> { let result = match &get_cli().command { Some(Commands::Create(cmd)) => create::command(cmd), Some(Commands::Search) => search::command(), + Some(Commands::Completions { shell }) => completions::command(shell), None => Err(anyhow!("No command specified")), }; diff --git a/src/template/item/mod.rs b/src/template/item/mod.rs index e13e203..3f3e3f8 100644 --- a/src/template/item/mod.rs +++ b/src/template/item/mod.rs @@ -223,7 +223,7 @@ impl Template { } _ => { let url = self.value.url()?; - return match TemplateCache::get(&url)? { + match TemplateCache::get(&url)? { Some(content) => Ok(content), None => { let content: String = http().get(&url) @@ -239,7 +239,7 @@ impl Template { TemplateCache::set(&url, content)?; Ok(content.to_string()) } - }; + } } } }