use log::{error, info};
use std::io::BufRead;
use std::path::Path;
use std::{fs, io};
#[cfg(test)]
#[path = "completion_test.rs"]
mod completion_test;
pub fn generate_completions(shell: &str) -> Result<(), Box<dyn std::error::Error>> {
match shell {
"zsh" => {
generate_completion_zsh(None)?; Ok(()) }
_ => {
Err(Box::from(format!(
"Unsupported shell for completion: {}",
shell
)))
}
}
}
fn generate_completion_zsh(
input: Option<&mut dyn io::Read>,
) -> Result<(), Box<dyn std::error::Error>> {
let home_dir = std::env::var("HOME")?;
let zfunc_dir = format!("{}/.zfunc", home_dir);
let completion_file = format!("{}/_cargo-make", zfunc_dir);
if !Path::new(&zfunc_dir).exists() {
if let Err(e) = fs::create_dir_all(&zfunc_dir) {
error!("Failed to create directory {}: {}", zfunc_dir, e);
return Err(Box::new(e));
}
info!("Created directory: {}", zfunc_dir);
}
if Path::new(&completion_file).exists() {
let mut input_str = String::new();
let reader: Box<dyn io::Read> = match input {
Some(input) => Box::new(input),
None => Box::new(io::stdin()),
};
let mut buf_reader = io::BufReader::new(reader);
println!(
"File {} already exists. Overwrite? (y/n): ",
completion_file
);
buf_reader.read_line(&mut input_str)?;
if input_str.trim().to_lowercase() != "y" {
println!("Aborted overwriting the file.");
return Ok(());
}
}
let completion_script = r#"
#compdef cargo make cargo-make
_cargo_make() {
local tasks
local makefile="Makefile.toml"
if [[ ! -f $makefile ]]; then
return 1
fi
tasks=($(awk -F'[\\[\\.\\]]' '/^\[tasks/ {print $3}' "$makefile"))
if [[ ${#tasks[@]} -eq 0 ]]; then
return 1
fi
_describe -t tasks 'cargo-make tasks' tasks
}
_cargo_make "$@"
"#;
fs::write(&completion_file, completion_script)?;
println!("\nWrote tasks completion script to: {}", completion_file);
println!("To enable Zsh completion, add the following lines to your ~/.zshrc:\n");
println!(" fpath=(~/.zfunc $fpath)");
println!(" autoload -Uz compinit && compinit");
println!("\nThen, restart your terminal or run 'source ~/.zshrc'.");
Ok(())
}