From 3c1749f5eb81bf5dbb69ee0b29459f22639fca3e Mon Sep 17 00:00:00 2001 From: schilkp Date: Thu, 7 Mar 2024 10:56:12 +0100 Subject: [PATCH] cmd: add completion command Add `bender completion` command that generates completion scripts for common shells (bash, zsh, fish, ...) using clap's clap_complete crate. --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + README.md | 13 ++++++++++++- src/cli.rs | 8 +++++++- src/cmd/completion.rs | 44 +++++++++++++++++++++++++++++++++++++++++++ src/cmd/mod.rs | 1 + 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/cmd/completion.rs diff --git a/Cargo.lock b/Cargo.lock index 79d84390..03da166d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,7 @@ dependencies = [ "async-recursion", "blake2", "clap", + "clap_complete", "common-path", "dirs", "dunce", @@ -270,6 +271,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.0" diff --git a/Cargo.toml b/Cargo.toml index f6650710..102eeb09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ tokio = { version = "1.27", features = ["full"] } async-recursion = "1.0" clap = { version = "4.0", features = ["derive"] } +clap_complete = "4.0" semver = { version = "1.0", features = ["serde"] } blake2 = "0.10" typed-arena = "2" diff --git a/README.md b/README.md index 98fb1cbd..201654bc 100644 --- a/README.md +++ b/README.md @@ -445,7 +445,7 @@ Calling update with the `--fetch/-f` flag will force all git dependencies to be ### `clone` --- Clone dependency to make modifications -The `bender clone ` command checks out the package `PKG` into a directory (default `working_dir`, can be overridden with `-p / --path `). +The `bender clone ` command checks out the package `PKG` into a directory (default `working_dir`, can be overridden with `-p / --path `). To ensure the package is correctly linked in bender, the `Bender.local` file is modified to include a `path` dependency override, linking to the corresponding package. This can be used for development of dependent packages within the parent repository, allowing to test uncommitted and committed changes, without the worry that bender would update the dependency. @@ -535,6 +535,17 @@ This branch can then be rebased and a pull request can be opened from it as usua Note: when using mappings in your `vendor_package`, the patches will be relative to the mapped directory. Hence, for upstreaming, you might need to use `git am --directory=` instead of plain `git am`. +### `completion` --- Generate shell completion script + +The `bender completion ` command prints a completion script for the given shell. + +Supported shells: +- `bash` +- `elvish` +- `fish` +- `powershell` +- `zsh` + [aur-bender]: https://aur.archlinux.org/packages/bender [releases]: https://github.com/pulp-platform/bender/releases [rust-installation]: https://doc.rust-lang.org/book/ch01-01-installation.html diff --git a/src/cli.rs b/src/cli.rs index 7ccc42a1..6b7c6e64 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -77,6 +77,7 @@ pub fn main() -> Result<()> { .subcommand(cmd::clone::new()) .subcommand(cmd::packages::new()) .subcommand(cmd::sources::new()) + .subcommand(cmd::completion::new()) .subcommand(cmd::config::new()) .subcommand(cmd::script::new()) .subcommand(cmd::checkout::new()) @@ -99,7 +100,7 @@ pub fn main() -> Result<()> { }; // Parse the arguments. - let matches = app.get_matches(); + let matches = app.clone().get_matches(); // Enable debug outputs if needed. if matches.contains_id("debug") && matches.get_flag("debug") { @@ -110,6 +111,11 @@ pub fn main() -> Result<()> { return cmd::init::run(matches); } + if let Some(("completion", matches)) = matches.subcommand() { + let mut app = app; + return cmd::completion::run(matches, &mut app); + } + let mut force_fetch = false; if let Some(("update", intern_matches)) = matches.subcommand() { force_fetch = intern_matches.get_flag("fetch"); diff --git a/src/cmd/completion.rs b/src/cmd/completion.rs new file mode 100644 index 00000000..925f2a22 --- /dev/null +++ b/src/cmd/completion.rs @@ -0,0 +1,44 @@ +// Copyright (c) 2017-2024 ETH Zurich +// Philipp Schilk + +//! The `completion` subcommand. + +use std::io; + +use crate::error::*; +use clap::{builder::PossibleValue, Arg, ArgMatches, Command}; + +/// Assemble the `completion` subcommand. +pub fn new() -> Command { + Command::new("completion") + .about("Emit shell completion script") + .arg( + Arg::new("completion_shell") + .help("Shell completion script style") + .required(true) + .num_args(1) + .value_name("SHELL") + .value_parser([ + PossibleValue::new("bash"), + PossibleValue::new("elvish"), + PossibleValue::new("fish"), + PossibleValue::new("powershell"), + PossibleValue::new("zsh"), + ]), + ) +} + +/// Execute the `completion` subcommand. +pub fn run(matches: &ArgMatches, app: &mut Command) -> Result<()> { + let shell = matches.get_one::("completion_shell").unwrap(); + let shell = match shell.as_str() { + "bash" => clap_complete::Shell::Bash, + "elvish" => clap_complete::Shell::Elvish, + "fish" => clap_complete::Shell::Fish, + "powershell" => clap_complete::Shell::PowerShell, + "zsh" => clap_complete::Shell::Zsh, + _ => unreachable!(), + }; + clap_complete::generate(shell, app, "bender", &mut io::stdout()); + Ok(()) +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 3c383995..abd9236d 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -9,6 +9,7 @@ pub mod checkout; pub mod clone; +pub mod completion; pub mod config; pub mod fusesoc; pub mod init;