1use log::{error, info};
2use std::io::BufRead;
3use std::path::Path;
4use std::{fs, io};
5
6#[cfg(test)]
24#[path = "completion_test.rs"]
25mod completion_test;
26
27pub fn generate_completions(shell: &str) -> Result<(), Box<dyn std::error::Error>> {
28 match shell {
29 "zsh" => {
30 generate_completion_zsh(None)?; Ok(()) }
33 _ => {
34 Err(Box::from(format!(
36 "Unsupported shell for completion: {}",
37 shell
38 )))
39 }
40 }
41}
42
43fn generate_completion_zsh(
45 input: Option<&mut dyn io::Read>,
46) -> Result<(), Box<dyn std::error::Error>> {
47 let home_dir = std::env::var("HOME")?;
48 let zfunc_dir = format!("{}/.zfunc", home_dir);
49 let completion_file = format!("{}/_cargo-make", zfunc_dir);
50
51 if !Path::new(&zfunc_dir).exists() {
52 if let Err(e) = fs::create_dir_all(&zfunc_dir) {
53 error!("Failed to create directory {}: {}", zfunc_dir, e);
54 return Err(Box::new(e));
55 }
56 info!("Created directory: {}", zfunc_dir);
57 }
58
59 if Path::new(&completion_file).exists() {
60 let mut input_str = String::new();
61 let reader: Box<dyn io::Read> = match input {
62 Some(input) => Box::new(input),
63 None => Box::new(io::stdin()),
64 };
65
66 let mut buf_reader = io::BufReader::new(reader);
68 println!(
69 "File {} already exists. Overwrite? (y/n): ",
70 completion_file
71 );
72 buf_reader.read_line(&mut input_str)?;
73
74 if input_str.trim().to_lowercase() != "y" {
75 println!("Aborted overwriting the file.");
76 return Ok(());
77 }
78 }
79
80 let completion_script = r#"
81#compdef cargo make cargo-make
82
83_cargo_make() {
84 local tasks
85 local makefile="Makefile.toml"
86
87 if [[ ! -f $makefile ]]; then
88 return 1
89 fi
90
91 tasks=($(awk -F'[\\[\\.\\]]' '/^\[tasks/ {print $3}' "$makefile"))
92
93 if [[ ${#tasks[@]} -eq 0 ]]; then
94 return 1
95 fi
96
97 _describe -t tasks 'cargo-make tasks' tasks
98}
99
100_cargo_make "$@"
101"#;
102
103 fs::write(&completion_file, completion_script)?;
104 println!("\nWrote tasks completion script to: {}", completion_file);
105
106 println!("To enable Zsh completion, add the following lines to your ~/.zshrc:\n");
107 println!(" fpath=(~/.zfunc $fpath)");
108 println!(" autoload -Uz compinit && compinit");
109 println!("\nThen, restart your terminal or run 'source ~/.zshrc'.");
110
111 Ok(())
112}