Skip to content

Commit 69c82e9

Browse files
authored
Merge pull request #158 from schilkp/schilkp/autocomplete
cmd: add 'completion' command
2 parents 755177c + 6540fe6 commit 69c82e9

File tree

9 files changed

+94
-7
lines changed

9 files changed

+94
-7
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ tokio = { version = "1.27", features = ["full"] }
1818
async-recursion = "1.0"
1919

2020
clap = { version = "4.0", features = ["derive"] }
21+
clap_complete = "4.0"
2122
semver = { version = "1.0", features = ["serde"] }
2223
blake2 = "0.10"
2324
typed-arena = "2"

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ Calling update with the `--fetch/-f` flag will force all git dependencies to be
445445

446446
### `clone` --- Clone dependency to make modifications
447447

448-
The `bender clone <PKG>` command checks out the package `PKG` into a directory (default `working_dir`, can be overridden with `-p / --path <DIR>`).
448+
The `bender clone <PKG>` command checks out the package `PKG` into a directory (default `working_dir`, can be overridden with `-p / --path <DIR>`).
449449
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.
450450

451451
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,23 @@ This branch can then be rebased and a pull request can be opened from it as usua
535535
Note: when using mappings in your `vendor_package`, the patches will be relative to the mapped directory.
536536
Hence, for upstreaming, you might need to use `git am --directory=<mapping.from>` instead of plain `git am`.
537537

538+
### `completion` --- Generate shell completion script
539+
540+
The `bender completion <SHELL>` command prints a completion script for the given shell.
541+
542+
Installation and usage of these scripts is shell-dependent. Please refer to your shell's documentation
543+
for information on how to install and use the generated script
544+
([bash](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html),
545+
[zsh](https://zsh.sourceforge.io/Doc/Release/Completion-System.html),
546+
[fish](https://fishshell.com/docs/current/completions.html)).
547+
548+
Supported shells:
549+
- `bash`
550+
- `elvish`
551+
- `fish`
552+
- `powershell`
553+
- `zsh`
554+
538555
[aur-bender]: https://aur.archlinux.org/packages/bender
539556
[releases]: https://github.com/pulp-platform/bender/releases
540557
[rust-installation]: https://doc.rust-lang.org/book/ch01-01-installation.html

src/cli.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ pub fn main() -> Result<()> {
3737
.version(env!("CARGO_PKG_VERSION"))
3838
.author(env!("CARGO_PKG_AUTHORS"))
3939
.about("A dependency management tool for hardware projects.")
40+
.after_help(
41+
"Type 'bender <SUBCOMMAND> --help' for more information about a bender subcommand.",
42+
)
4043
.arg(
4144
Arg::new("dir")
4245
.short('d')
@@ -77,6 +80,7 @@ pub fn main() -> Result<()> {
7780
.subcommand(cmd::clone::new())
7881
.subcommand(cmd::packages::new())
7982
.subcommand(cmd::sources::new())
83+
.subcommand(cmd::completion::new())
8084
.subcommand(cmd::config::new())
8185
.subcommand(cmd::script::new())
8286
.subcommand(cmd::checkout::new())
@@ -99,7 +103,7 @@ pub fn main() -> Result<()> {
99103
};
100104

101105
// Parse the arguments.
102-
let matches = app.get_matches();
106+
let matches = app.clone().get_matches();
103107

104108
// Enable debug outputs if needed.
105109
if matches.contains_id("debug") && matches.get_flag("debug") {
@@ -110,6 +114,11 @@ pub fn main() -> Result<()> {
110114
return cmd::init::run(matches);
111115
}
112116

117+
if let Some(("completion", matches)) = matches.subcommand() {
118+
let mut app = app;
119+
return cmd::completion::run(matches, &mut app);
120+
}
121+
113122
let mut force_fetch = false;
114123
if let Some(("update", intern_matches)) = matches.subcommand() {
115124
force_fetch = intern_matches.get_flag("fetch");

src/cmd/completion.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2017-2024 ETH Zurich
2+
// Philipp Schilk <[email protected]>
3+
4+
//! The `completion` subcommand.
5+
6+
use std::io;
7+
8+
use crate::error::*;
9+
use clap::{builder::PossibleValue, Arg, ArgMatches, Command};
10+
11+
/// Assemble the `completion` subcommand.
12+
pub fn new() -> Command {
13+
Command::new("completion")
14+
.about("Emit shell completion script")
15+
.arg(
16+
Arg::new("completion_shell")
17+
.help("Shell completion script style")
18+
.required(true)
19+
.num_args(1)
20+
.value_name("SHELL")
21+
.value_parser([
22+
PossibleValue::new("bash"),
23+
PossibleValue::new("elvish"),
24+
PossibleValue::new("fish"),
25+
PossibleValue::new("powershell"),
26+
PossibleValue::new("zsh"),
27+
]),
28+
)
29+
}
30+
31+
/// Execute the `completion` subcommand.
32+
pub fn run(matches: &ArgMatches, app: &mut Command) -> Result<()> {
33+
let shell = matches.get_one::<String>("completion_shell").unwrap();
34+
let shell = match shell.as_str() {
35+
"bash" => clap_complete::Shell::Bash,
36+
"elvish" => clap_complete::Shell::Elvish,
37+
"fish" => clap_complete::Shell::Fish,
38+
"powershell" => clap_complete::Shell::PowerShell,
39+
"zsh" => clap_complete::Shell::Zsh,
40+
_ => unreachable!(),
41+
};
42+
clap_complete::generate(shell, app, "bender", &mut io::stdout());
43+
Ok(())
44+
}

src/cmd/fusesoc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::target::TargetSpec;
2727
/// Assemble the `fusesoc` subcommand.
2828
pub fn new() -> Command {
2929
Command::new("fusesoc")
30-
.about("Creates a FuseSoC `.core` file for all dependencies where none is present.")
30+
.about("Creates a FuseSoC `.core` file for all dependencies where none is present")
3131
.arg(
3232
Arg::new("single")
3333
.long("single")

src/cmd/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
pub mod checkout;
1111
pub mod clone;
12+
pub mod completion;
1213
pub mod config;
1314
pub mod fusesoc;
1415
pub mod init;

src/cmd/packages.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ pub fn new() -> Command {
2424
.long("flat")
2525
.num_args(0)
2626
.action(ArgAction::SetTrue)
27-
.help("Do not group packages by topological rank. If the `--graph` option is specified, print multiple lines per package, one for each dependency.")
27+
.help("Do not group packages by topological rank")
28+
.long_help("Do not group packages by topological rank. If the `--graph` option is specified, print multiple lines per package, one for each dependency.")
2829
)
2930
}
3031

src/cmd/vendor.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ pub struct PatchLink {
3434
pub fn new() -> Command {
3535
Command::new("vendor")
3636
.subcommand_required(true).arg_required_else_help(true)
37-
.about("Copy source code from upstream external repositories into this repository. Functions similar to the lowrisc vendor.py script. Type bender vendor <SUBCOMMAND> --help for more information about the subcommands.")
37+
.about("Copy source code from upstream external repositories into this repository")
38+
.long_about("Copy source code from upstream external repositories into this repository. Functions similar to the lowrisc vendor.py script.")
39+
.after_help("Type 'bender vendor <SUBCOMMAND> --help' for more information about a vendor subcommand.")
3840
.subcommand(Command::new("diff")
3941
.about("Display a diff of the local tree and the upstream tree with patches applied.")
4042
.arg(
@@ -46,7 +48,8 @@ pub fn new() -> Command {
4648
)
4749
)
4850
.subcommand(Command::new("init")
49-
.about("(Re-)initialize the external dependencies. Copies the upstream files into the target directories and applies existing patches.")
51+
.about("(Re-)initialize the external dependencies.")
52+
.long_about("(Re-)initialize the external dependencies. Copies the upstream files into the target directories and applies existing patches.")
5053
.arg(
5154
Arg::new("no_patch")
5255
.short('n')
@@ -61,7 +64,8 @@ pub fn new() -> Command {
6164
Arg::new("plain")
6265
.action(ArgAction::SetTrue)
6366
.long("plain")
64-
.help("Generate a plain diff instead of a format-patch. Includes all local changes (not only the staged ones)."),
67+
.help("Generate a plain diff instead of a format-patch.")
68+
.long_help("Generate a plain diff instead of a format-patch. Includes all local changes (not only the staged ones)."),
6569
)
6670
.arg(
6771
Arg::new("message")

0 commit comments

Comments
 (0)