cli/completion: Static shell completion for `rad`

Introduce the use of `clap_completion` for generating static completion.
The shells that are supported are the ones that are included in `clap_complete`:
- `bash`,
- `elvish`,
- `zsh`,
- `fish`, and
- `powershell`.

Co-authored-by: Michael Uti <utimichael9@gmail.com>
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
This commit is contained in:
Fintan Halpenny 2025-11-04 11:13:11 +00:00 committed by Lorenz Leutgeb
parent 7e5a1ababc
commit 93d2ed8c61
3 changed files with 32 additions and 1 deletions

10
Cargo.lock generated
View File

@ -477,6 +477,15 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.41"
@ -2819,6 +2828,7 @@ dependencies = [
"anyhow",
"chrono",
"clap",
"clap_complete",
"dunce",
"human-panic",
"itertools",

View File

@ -17,6 +17,7 @@ path = "src/main.rs"
anyhow = "1"
chrono = { workspace = true, features = ["clock", "std"] }
clap = { version = "4.5.44", features = ["derive"] }
clap_complete = "4.5"
dunce = { workspace = true }
human-panic.workspace = true
itertools.workspace = true

View File

@ -7,7 +7,7 @@ use std::{io::ErrorKind, process};
use anyhow::anyhow;
use clap::builder::styling::AnsiColor;
use clap::builder::Styles;
use clap::{Parser, Subcommand};
use clap::{CommandFactory as _, Parser, Subcommand};
use radicle::version::Version;
use radicle_cli::commands::*;
@ -98,6 +98,13 @@ enum Command {
json: bool,
},
/// Print static completion information for a given shell
#[command(hide = true)]
Completion {
/// The type of shell to output a static completion script for.
shell: clap_complete::Shell,
},
#[command(external_subcommand)]
External(Vec<OsString>),
}
@ -176,10 +183,23 @@ fn run_command(command: Command, ctx: impl term::Context) -> Result<(), anyhow::
Command::Unseed(args) => unseed::run(args, ctx),
Command::Watch(args) => watch::run(args, ctx),
Command::Version { json } => write_version(json),
Command::Completion { shell } => {
print_completion(shell, &mut CliArgs::command());
Ok(())
}
Command::External(args) => ExternalCommand::new(args).run(),
}
}
fn print_completion<G: clap_complete::Generator>(generator: G, cmd: &mut clap::Command) {
clap_complete::generate(
generator,
cmd,
cmd.get_name().to_string(),
&mut io::stdout(),
);
}
struct ExternalCommand {
command: OsString,
args: Vec<OsString>,