use std::ffi::OsStr;
use clap::CommandFactory;
use clap_complete::engine::{ArgValueCompleter, CompletionCandidate};
use clap_complete::CompleteEnv;
use crate::config;
use crate::Cli;
pub fn init() {
CompleteEnv::with_factory(build_cli).complete();
}
fn build_cli() -> clap::Command {
Cli::command()
.mut_subcommand("activate", add_profile_completer)
.mut_subcommand("edit", add_profile_completer)
.mut_subcommand("show", add_profile_completer)
.mut_subcommand("remove", add_profile_completer)
.mut_subcommand("encrypt", add_profile_completer)
.mut_subcommand("decrypt", add_profile_completer)
}
fn add_profile_completer(cmd: clap::Command) -> clap::Command {
cmd.mut_arg("profile", |arg| {
arg.add(ArgValueCompleter::new(complete_profiles))
})
}
fn complete_profiles(current: &OsStr) -> Vec<CompletionCandidate> {
let current_str = current.to_string_lossy();
let Ok(profile_dir) = config::get_profile_dir() else {
return vec![];
};
let Ok(entries) = std::fs::read_dir(&profile_dir) else {
return vec![];
};
let mut seen = std::collections::HashSet::new();
entries
.flatten()
.filter_map(|entry| {
let path = entry.path();
if !path.is_file() {
return None;
}
let file_name = path.file_name()?.to_str()?;
if file_name.starts_with('.') {
return None;
}
let name = file_name.strip_suffix(".gpg").unwrap_or(file_name);
if name.starts_with(&*current_str) && seen.insert(name.to_string()) {
Some(CompletionCandidate::new(name))
} else {
None
}
})
.collect()
}