feat: add --generate-completion for shell tab completion

- Add clap_complete dependency for bash/zsh/fish/elvish/powershell
- Add --generate-completion <shell> flag that prints completion script to stdout
- profile.bash sources completions via command keep --generate-completion bash
- @ and @@ aliases get completions via wrapper functions that delegate to _keep
- README updated with Shell Completion section
This commit is contained in:
2026-03-14 11:02:38 -03:00
parent 158bf50864
commit 1a8ed56b68
6 changed files with 58 additions and 0 deletions

10
Cargo.lock generated
View File

@@ -435,6 +435,15 @@ dependencies = [
"strsim", "strsim",
] ]
[[package]]
name = "clap_complete"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb"
dependencies = [
"clap",
]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.6.0" version = "4.6.0"
@@ -1649,6 +1658,7 @@ dependencies = [
"base64", "base64",
"chrono", "chrono",
"clap", "clap",
"clap_complete",
"comfy-table", "comfy-table",
"config", "config",
"ctor", "ctor",

View File

@@ -18,6 +18,7 @@ thiserror = "2.0"
base64 = "0.22" base64 = "0.22"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.6", features = ["derive", "env"] } clap = { version = "4.6", features = ["derive", "env"] }
clap_complete = "4"
config = "0.15" config = "0.15"
ctor = "0.2" ctor = "0.2"
directories = "6.0" directories = "6.0"

View File

@@ -90,6 +90,24 @@ source $KEEP_BASH_PROFILE
The modulefile prepends `keep/bin` to `PATH` and sets `KEEP_BASH_PROFILE` pointing to `profile.bash`. The modulefile prepends `keep/bin` to `PATH` and sets `KEEP_BASH_PROFILE` pointing to `profile.bash`.
### Shell Completion
Tab completion is available for `bash`, `zsh`, `fish`, `elvish`, and `powershell`.
**Bash** — add to `~/.bashrc`:
```sh
. <(keep --generate-completion bash)
```
**Zsh** — add to `~/.zshrc`:
```sh
. <(keep --generate-completion zsh)
```
**With `profile.bash`**: Completions for `keep`, `@` (save), and `@@` (get) are loaded automatically when sourcing `profile.bash`.
### Build with Server/Client Features ### Build with Server/Client Features
```sh ```sh

View File

@@ -40,4 +40,22 @@ function @@ {
keep --get "$@" keep --get "$@"
} }
# Shell completions
. <(command keep --generate-completion bash)
___keep_save_completion() {
COMP_WORDS=(keep --save "${COMP_WORDS[@]:1}")
COMP_CWORD=$((COMP_CWORD + 1))
_keep
}
___keep_get_completion() {
COMP_WORDS=(keep --get "${COMP_WORDS[@]:1}")
COMP_CWORD=$((COMP_CWORD + 1))
_keep
}
complete -F ___keep_save_completion @
complete -F ___keep_get_completion @@
__keep_preexec_init __keep_preexec_init

View File

@@ -2,6 +2,7 @@ use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use clap::*; use clap::*;
use clap_complete::Shell;
/// Main struct for command-line arguments, parsed via Clap. /// Main struct for command-line arguments, parsed via Clap.
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
@@ -68,6 +69,10 @@ pub struct ModeArgs {
#[arg(help("Generate default configuration and output to stdout"))] #[arg(help("Generate default configuration and output to stdout"))]
pub generate_config: bool, pub generate_config: bool,
#[arg(help_heading("Mode Options"), long, conflicts_with_all(["save", "get", "diff", "list", "delete", "info", "status", "server", "generate_config"]))]
#[arg(help("Generate shell completion script (bash, zsh, fish, elvish, powershell)"))]
pub generate_completion: Option<Shell>,
#[arg(help_heading("Server Options"), long, env("KEEP_SERVER_ADDRESS"))] #[arg(help_heading("Server Options"), long, env("KEEP_SERVER_ADDRESS"))]
#[arg(help("Server address to bind to"))] #[arg(help("Server address to bind to"))]
pub server_address: Option<String>, pub server_address: Option<String>,

View File

@@ -28,6 +28,12 @@ fn main() -> Result<(), Error> {
cmd.error(ErrorKind::ValueValidation, e).exit(); cmd.error(ErrorKind::ValueValidation, e).exit();
} }
// Handle --generate-completion early (prints to stdout and exits)
if let Some(shell) = args.mode.generate_completion {
clap_complete::generate(shell, &mut Args::command(), "keep", &mut std::io::stdout());
std::process::exit(0);
}
let start = Instant::now(); let start = Instant::now();
let mut builder = env_logger::Builder::new(); let mut builder = env_logger::Builder::new();
let show_module = args.options.verbose >= 2; let show_module = args.options.verbose >= 2;