From c4455666812d7d5037e6b5ac4c1f93772203c1f7 Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Thu, 24 Oct 2024 10:47:18 +0200 Subject: [PATCH 1/7] Adds feature enabling task completion scripts for Zsh --- src/lib/cli_parser.rs | 23 +++++++++ src/lib/cli_test.rs | 10 ++++ src/lib/completion.rs | 97 ++++++++++++++++++++++++++++++++++++++ src/lib/completion_test.rs | 61 ++++++++++++++++++++++++ src/lib/mod.rs | 1 + src/lib/types.rs | 3 ++ 6 files changed, 195 insertions(+) create mode 100644 src/lib/completion.rs create mode 100644 src/lib/completion_test.rs diff --git a/src/lib/cli_parser.rs b/src/lib/cli_parser.rs index e14f9883..00c3848a 100644 --- a/src/lib/cli_parser.rs +++ b/src/lib/cli_parser.rs @@ -7,6 +7,8 @@ #[path = "cli_parser_test.rs"] mod cli_parser_test; +use crate::completion::generate_completions; + use crate::cli::{ AUTHOR, DEFAULT_LOG_LEVEL, DEFAULT_OUTPUT_FORMAT, DEFAULT_TASK_NAME, DESCRIPTION, VERSION, }; @@ -42,6 +44,11 @@ fn get_args( None => None, }; + cli_args.completion = match cli_parsed.get_first_value("completion") { + Some(value) => Some(value.to_string()), + None => None, + }; + cli_args.cwd = cli_parsed.get_first_value("cwd"); let default_log_level = match global_config.log_level { @@ -214,6 +221,17 @@ fn add_arguments(spec: CliSpec, default_task_name: &str, default_log_level: &str "PROFILE".to_string(), )), }) + .add_argument(Argument { + name: "completion".to_string(), + key: vec!["--completion".to_string()], + argument_occurrence: ArgumentOccurrence::Single, + value_type: ArgumentValueType::Single, + default_value: None, + help: Some(ArgumentHelp::TextAndParam( + "Will enable completion for the defined tasks for a given shell".to_string(), + "COMPLETION".to_string(), + )), + }) .add_argument(Argument { name: "cwd".to_string(), key: vec!["--cwd".to_string()], @@ -482,6 +500,10 @@ pub fn parse_args( let version_text = cliparser::version(&spec); println!("{}", version_text); Err(CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) + } else if let Some(shell) = cli_parsed.get_first_value("completion") { + // Call the function to generate completions + generate_completions(&shell); + Err(CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) } else { Ok(get_args( &cli_parsed, @@ -512,3 +534,4 @@ fn to_owned_vec(vec_option: Option<&Vec>) -> Option> { None => None, } } + diff --git a/src/lib/cli_test.rs b/src/lib/cli_test.rs index 0f236b11..d3e7efe9 100644 --- a/src/lib/cli_test.rs +++ b/src/lib/cli_test.rs @@ -18,6 +18,7 @@ fn run_makefile_not_found() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -57,6 +58,7 @@ fn run_empty_task() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -96,6 +98,7 @@ fn print_empty_task() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -135,6 +138,7 @@ fn list_empty_task() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -174,6 +178,7 @@ fn run_file_and_task() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -216,6 +221,7 @@ fn run_cwd_with_file() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: Some("..".to_string()), env: None, env_file: None, @@ -256,6 +262,7 @@ fn run_file_not_go_to_project_root() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -296,6 +303,7 @@ fn run_cwd_go_to_project_root_current_dir() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -339,6 +347,7 @@ fn run_cwd_go_to_project_root_child_dir() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: None, env: None, env_file: None, @@ -382,6 +391,7 @@ fn run_cwd_task_not_found() { profile: None, log_level: "error".to_string(), disable_color: true, + completion: None, cwd: Some("..".to_string()), env: None, env_file: None, diff --git a/src/lib/completion.rs b/src/lib/completion.rs new file mode 100644 index 00000000..fa953b93 --- /dev/null +++ b/src/lib/completion.rs @@ -0,0 +1,97 @@ +use std::path::Path; +use std::{fs, io}; + + +/// # Completions Module +/// +/// This module handles the generation of shell completion scripts for the `cargo-make` tool. +/// +/// ## Functionality +/// - `generate_completion_zsh`: Generates a Zsh completion script, creates the necessary directory, +/// and prompts for overwriting existing files. +/// +/// ## Improvements to Consider +/// 1. **Modularity**: Separate the completion logic into different modules for different shells +/// (e.g., Zsh, Bash, Fish) to improve code organization. +/// 2. **Cross-Platform Support**: Abstract the completion generation into a trait or interface +/// to facilitate adding support for other shell types. +/// 3. **Enhanced Error Handling**: Provide more informative error messages for file operations. +/// 4. **User Input Handling**: Ensure user input is trimmed and handled correctly. +/// 5. **Testing**: Implement unit tests to verify the correct behavior of completion generation functions. + +#[cfg(test)] +#[path = "completion_test.rs"] +mod completion_test; + +pub fn generate_completions(shell: &str) { + match shell { + "zsh" => { + if let Err(e) = generate_completion_zsh() { + eprintln!("Error generating Zsh completions: {}", e); + } + } + _ => { + eprintln!("Unsupported shell for completion: {}", shell); + } + } +} + +fn generate_completion_zsh() -> Result<(), Box> { + 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) { + eprintln!("Failed to create directory {}: {}", zfunc_dir, e); + return Err(Box::new(e)); + } + println!("Created directory: {}", zfunc_dir); + } + + if Path::new(&completion_file).exists() { + let mut input = String::new(); + println!( + "File {} already exists. Overwrite? (y/n): ", + completion_file + ); + io::stdin().read_line(&mut input)?; + if input.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(()) +} diff --git a/src/lib/completion_test.rs b/src/lib/completion_test.rs new file mode 100644 index 00000000..18c4523a --- /dev/null +++ b/src/lib/completion_test.rs @@ -0,0 +1,61 @@ +use super::*; +use std::fs; +use std::path::Path; + +#[cfg(test)] +mod tests { + use super::*; + + // Function to clean up test environment by removing the completion file + fn cleanup() { + let home_dir = std::env::var("HOME").expect("Failed to get HOME"); + let completion_file = format!("{}/.zfunc/_cargo-make", home_dir); + if Path::new(&completion_file).exists() { + fs::remove_file(&completion_file).expect("Failed to clean up test file"); + } + } + + #[test] + fn test_generate_completion_zsh_creates_directory() { + cleanup(); // Clean up before the test + + let result = generate_completion_zsh(); + assert!(result.is_ok(), "Should succeed in generating completions"); + + // Check if the directory was created + let home_dir = std::env::var("HOME").expect("Failed to get HOME"); + let zfunc_dir = format!("{}/.zfunc", home_dir); + assert!(Path::new(&zfunc_dir).exists(), "The zfunc directory should exist"); + } + + #[test] + fn test_generate_completion_zsh_creates_file() { + cleanup(); // Clean up before the test + + let result = generate_completion_zsh(); + assert!(result.is_ok(), "Should succeed in generating completions"); + + // Check if the completion file was created + let home_dir = std::env::var("HOME").expect("Failed to get HOME"); + let completion_file = format!("{}/.zfunc/_cargo-make", home_dir); + assert!(Path::new(&completion_file).exists(), "The completion file should exist"); + } + + #[test] + fn test_generate_completion_zsh_overwrite_prompt() { + cleanup(); // Clean up before the test + + // Create the directory and file first + generate_completion_zsh().expect("Should succeed in generating completions"); + + // Simulate user input for overwrite. + // You might want to refactor the `generate_completion_zsh` function to take an input parameter + // for easier testing. + + // For now, let's just check that we can call it again + let result = generate_completion_zsh(); // This will prompt in the real environment + assert!(result.is_ok(), "Should handle overwrite prompt gracefully"); + } + + // Additional tests can be added here for other scenarios +} diff --git a/src/lib/mod.rs b/src/lib/mod.rs index f013cada..ee954b36 100755 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -55,6 +55,7 @@ mod cache; pub mod cli; pub mod cli_commands; pub mod cli_parser; +pub mod completion; mod command; mod condition; pub mod config; diff --git a/src/lib/types.rs b/src/lib/types.rs index 9f4fe0a7..dae47bba 100755 --- a/src/lib/types.rs +++ b/src/lib/types.rs @@ -91,6 +91,8 @@ pub struct CliArgs { pub log_level: String, /// Disables colorful output pub disable_color: bool, + /// Task completion for given shell + pub completion: Option, /// Current working directory pub cwd: Option, /// Environment variables @@ -141,6 +143,7 @@ impl CliArgs { profile: None, log_level: "info".to_string(), disable_color: false, + completion: None, cwd: None, env: None, env_file: None, From d5227b900a5c846b22aa32038c3df3fc1973ef52 Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Thu, 24 Oct 2024 11:09:46 +0200 Subject: [PATCH 2/7] Fixes completion tests waiting for user input --- src/lib/completion.rs | 26 +++++++++++-------- src/lib/completion_test.rs | 51 ++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/lib/completion.rs b/src/lib/completion.rs index fa953b93..00dc175b 100644 --- a/src/lib/completion.rs +++ b/src/lib/completion.rs @@ -1,7 +1,7 @@ +use std::io::BufRead; use std::path::Path; use std::{fs, io}; - /// # Completions Module /// /// This module handles the generation of shell completion scripts for the `cargo-make` tool. @@ -26,7 +26,7 @@ mod completion_test; pub fn generate_completions(shell: &str) { match shell { "zsh" => { - if let Err(e) = generate_completion_zsh() { + if let Err(e) = generate_completion_zsh(None) { eprintln!("Error generating Zsh completions: {}", e); } } @@ -36,7 +36,8 @@ pub fn generate_completions(shell: &str) { } } -fn generate_completion_zsh() -> Result<(), Box> { +// Modify the function to accept an optional input stream +fn generate_completion_zsh(input: Option<&mut dyn io::Read>) -> Result<(), Box> { let home_dir = std::env::var("HOME")?; let zfunc_dir = format!("{}/.zfunc", home_dir); let completion_file = format!("{}/_cargo-make", zfunc_dir); @@ -50,13 +51,18 @@ fn generate_completion_zsh() -> Result<(), Box> { } if Path::new(&completion_file).exists() { - let mut input = String::new(); - println!( - "File {} already exists. Overwrite? (y/n): ", - completion_file - ); - io::stdin().read_line(&mut input)?; - if input.trim().to_lowercase() != "y" { + let mut input_str = String::new(); + let reader: Box = match input { + Some(input) => Box::new(input), + None => Box::new(io::stdin()), + }; + + // Create a BufReader to read from the provided input or 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(()); } diff --git a/src/lib/completion_test.rs b/src/lib/completion_test.rs index 18c4523a..50d709d6 100644 --- a/src/lib/completion_test.rs +++ b/src/lib/completion_test.rs @@ -1,11 +1,13 @@ -use super::*; use std::fs; use std::path::Path; +use std::io::Cursor; #[cfg(test)] mod tests { - use super::*; + use crate::completion::generate_completion_zsh; + use super::*; + // Function to clean up test environment by removing the completion file fn cleanup() { let home_dir = std::env::var("HOME").expect("Failed to get HOME"); @@ -15,11 +17,34 @@ mod tests { } } + #[test] + fn test_generate_completion_zsh_overwrite_prompt_yes() { + cleanup(); // Clean up before the test + let input = b"y\n"; // Simulate user input of 'y' + let mut reader = Cursor::new(input); + + let result = generate_completion_zsh(Some(&mut reader)); + assert!(result.is_ok()); + } + + #[test] + fn test_generate_completion_zsh_overwrite_prompt_no() { + cleanup(); // Clean up before the test + let input = b"n\n"; // Simulate user input of 'n' + let mut reader = Cursor::new(input); + + let result = generate_completion_zsh(Some(&mut reader)); + assert!(result.is_ok()); + } + #[test] fn test_generate_completion_zsh_creates_directory() { cleanup(); // Clean up before the test - let result = generate_completion_zsh(); + let input = b"y\n"; // Simulate user input of 'y' + let mut reader = Cursor::new(input); + + let result = generate_completion_zsh(Some(&mut reader)); assert!(result.is_ok(), "Should succeed in generating completions"); // Check if the directory was created @@ -32,7 +57,10 @@ mod tests { fn test_generate_completion_zsh_creates_file() { cleanup(); // Clean up before the test - let result = generate_completion_zsh(); + let input = b"y\n"; // Simulate user input of 'y' + let mut reader = Cursor::new(input); + + let result = generate_completion_zsh(Some(&mut reader)); assert!(result.is_ok(), "Should succeed in generating completions"); // Check if the completion file was created @@ -46,16 +74,17 @@ mod tests { cleanup(); // Clean up before the test // Create the directory and file first - generate_completion_zsh().expect("Should succeed in generating completions"); + let input = b"y\n"; // Simulate user input of 'y' + let mut reader = Cursor::new(input); + + generate_completion_zsh(Some(&mut reader)).expect("Should succeed in generating completions"); // Simulate user input for overwrite. - // You might want to refactor the `generate_completion_zsh` function to take an input parameter - // for easier testing. - - // For now, let's just check that we can call it again - let result = generate_completion_zsh(); // This will prompt in the real environment + let input = b"y\n"; // Simulate user input of 'y' again + let mut reader = Cursor::new(input); + + let result = generate_completion_zsh(Some(&mut reader)); assert!(result.is_ok(), "Should handle overwrite prompt gracefully"); } - // Additional tests can be added here for other scenarios } From bac9c0cefc4829d42d77421c0a2ea3e629016cf6 Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Mon, 4 Nov 2024 22:17:03 +0100 Subject: [PATCH 3/7] generate_completions returns result and decide success/fail --- src/lib/cli_parser.rs | 7 ++++--- src/lib/completion.rs | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lib/cli_parser.rs b/src/lib/cli_parser.rs index 00c3848a..3faa5eeb 100644 --- a/src/lib/cli_parser.rs +++ b/src/lib/cli_parser.rs @@ -502,8 +502,10 @@ pub fn parse_args( Err(CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) } else if let Some(shell) = cli_parsed.get_first_value("completion") { // Call the function to generate completions - generate_completions(&shell); - Err(CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) + if let Err(e) = generate_completions(&shell) { + eprintln!("Error generating completions: {}", e); + } + return Err(crate::error::CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)); } else { Ok(get_args( &cli_parsed, @@ -534,4 +536,3 @@ fn to_owned_vec(vec_option: Option<&Vec>) -> Option> { None => None, } } - diff --git a/src/lib/completion.rs b/src/lib/completion.rs index 00dc175b..754a0db2 100644 --- a/src/lib/completion.rs +++ b/src/lib/completion.rs @@ -23,19 +23,20 @@ use std::{fs, io}; #[path = "completion_test.rs"] mod completion_test; -pub fn generate_completions(shell: &str) { +pub fn generate_completions(shell: &str) -> Result<(), Box> { match shell { "zsh" => { - if let Err(e) = generate_completion_zsh(None) { - eprintln!("Error generating Zsh completions: {}", e); - } + generate_completion_zsh(None)?; // Use the `?` operator to propagate errors + Ok(()) // Return Ok if no error occurred } _ => { - eprintln!("Unsupported shell for completion: {}", shell); + // Return an error for unsupported shell + Err(Box::from(format!("Unsupported shell for completion: {}", shell))) } } } + // Modify the function to accept an optional input stream fn generate_completion_zsh(input: Option<&mut dyn io::Read>) -> Result<(), Box> { let home_dir = std::env::var("HOME")?; From b9edb1be4d095080789f0647db663ca96dfb6cd4 Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Mon, 4 Nov 2024 22:21:34 +0100 Subject: [PATCH 4/7] Updates eprintnl and printnl to use logger --- src/lib/completion.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/completion.rs b/src/lib/completion.rs index 754a0db2..24641553 100644 --- a/src/lib/completion.rs +++ b/src/lib/completion.rs @@ -1,6 +1,7 @@ use std::io::BufRead; use std::path::Path; use std::{fs, io}; +use log::{error,info}; /// # Completions Module /// @@ -45,10 +46,10 @@ fn generate_completion_zsh(input: Option<&mut dyn io::Read>) -> Result<(), Box Date: Tue, 5 Nov 2024 09:39:42 +0100 Subject: [PATCH 5/7] Update completion tests for sequential testing --- src/lib/completion_test.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/completion_test.rs b/src/lib/completion_test.rs index 50d709d6..fde45582 100644 --- a/src/lib/completion_test.rs +++ b/src/lib/completion_test.rs @@ -2,7 +2,6 @@ use std::fs; use std::path::Path; use std::io::Cursor; -#[cfg(test)] mod tests { use crate::completion::generate_completion_zsh; @@ -12,14 +11,19 @@ mod tests { fn cleanup() { let home_dir = std::env::var("HOME").expect("Failed to get HOME"); let completion_file = format!("{}/.zfunc/_cargo-make", home_dir); + println!("\n\n\n\n{}\n\n\n\n",completion_file); + if Path::new(&completion_file).exists() { fs::remove_file(&completion_file).expect("Failed to clean up test file"); } } #[test] + #[ignore] fn test_generate_completion_zsh_overwrite_prompt_yes() { + cleanup(); // Clean up before the test + let input = b"y\n"; // Simulate user input of 'y' let mut reader = Cursor::new(input); @@ -28,6 +32,7 @@ mod tests { } #[test] + #[ignore] fn test_generate_completion_zsh_overwrite_prompt_no() { cleanup(); // Clean up before the test let input = b"n\n"; // Simulate user input of 'n' @@ -38,6 +43,7 @@ mod tests { } #[test] + #[ignore] fn test_generate_completion_zsh_creates_directory() { cleanup(); // Clean up before the test @@ -54,6 +60,7 @@ mod tests { } #[test] + #[ignore] fn test_generate_completion_zsh_creates_file() { cleanup(); // Clean up before the test @@ -70,6 +77,7 @@ mod tests { } #[test] + #[ignore] fn test_generate_completion_zsh_overwrite_prompt() { cleanup(); // Clean up before the test From 0e2083904bedc3e9169adb2a347100c877c383e7 Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Tue, 5 Nov 2024 09:54:45 +0100 Subject: [PATCH 6/7] update fn parse_args --- src/lib/cli_parser.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/cli_parser.rs b/src/lib/cli_parser.rs index 3faa5eeb..e9e47967 100644 --- a/src/lib/cli_parser.rs +++ b/src/lib/cli_parser.rs @@ -503,9 +503,10 @@ pub fn parse_args( } else if let Some(shell) = cli_parsed.get_first_value("completion") { // Call the function to generate completions if let Err(e) = generate_completions(&shell) { - eprintln!("Error generating completions: {}", e); + error!("Error generating completions: {}", e); + return Err(CargoMakeError::ExitCode(std::process::ExitCode::FAILURE)); } - return Err(crate::error::CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)); + Err(crate::error::CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) } else { Ok(get_args( &cli_parsed, From 9b95eb9b7b522e1adb9e28c99fb2dbb71caf26cb Mon Sep 17 00:00:00 2001 From: Alberto <954alberto@gmail.com> Date: Tue, 5 Nov 2024 12:44:42 +0100 Subject: [PATCH 7/7] Updates docs --- docs/_includes/content.md | 7 +++++++ docs/_includes/nav.md | 1 + src/lib/cli_parser.rs | 4 +++- src/lib/completion.rs | 27 +++++++++++++++++---------- src/lib/completion_test.rs | 29 +++++++++++++++++------------ src/lib/mod.rs | 2 +- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/docs/_includes/content.md b/docs/_includes/content.md index 352ac455..e0d50922 100755 --- a/docs/_includes/content.md +++ b/docs/_includes/content.md @@ -3933,6 +3933,13 @@ source ./extra/shell/makers-completion.bash It will enable auto completion for the **makers** executable. + +#### Zsh Task Completion +By executing `cargo make --completion zsh` the necesary components will be created to enable task autocompletion. A restart of the shell is needed, or `source ~/.zshrc` +Then it will be possible to list the tasks defined in Makefile.toml using tab: `cargo make ` + + + #### Fig / Amazon CodeWhisperer for command line diff --git a/docs/_includes/nav.md b/docs/_includes/nav.md index cf1392fd..80ca0420 100755 --- a/docs/_includes/nav.md +++ b/docs/_includes/nav.md @@ -107,6 +107,7 @@ * [Shell Completion](#usage-shell-completion) * [Bash](#usage-shell-completion-bash) * [zsh](#usage-shell-completion-zsh) + * [Zsh Task Completion](usage-task-completion-zsh) * [Fig / Amazon CodeWhisperer for command line](#usage-shell-completion-fig) * [Global Configuration](#cargo-make-global-config) * [Makefile Definition](#descriptor-definition) diff --git a/src/lib/cli_parser.rs b/src/lib/cli_parser.rs index e9e47967..82ab96fe 100644 --- a/src/lib/cli_parser.rs +++ b/src/lib/cli_parser.rs @@ -506,7 +506,9 @@ pub fn parse_args( error!("Error generating completions: {}", e); return Err(CargoMakeError::ExitCode(std::process::ExitCode::FAILURE)); } - Err(crate::error::CargoMakeError::ExitCode(std::process::ExitCode::SUCCESS)) + Err(crate::error::CargoMakeError::ExitCode( + std::process::ExitCode::SUCCESS, + )) } else { Ok(get_args( &cli_parsed, diff --git a/src/lib/completion.rs b/src/lib/completion.rs index 24641553..75e0d472 100644 --- a/src/lib/completion.rs +++ b/src/lib/completion.rs @@ -1,20 +1,20 @@ +use log::{error, info}; use std::io::BufRead; use std::path::Path; use std::{fs, io}; -use log::{error,info}; /// # Completions Module -/// +/// /// This module handles the generation of shell completion scripts for the `cargo-make` tool. -/// +/// /// ## Functionality -/// - `generate_completion_zsh`: Generates a Zsh completion script, creates the necessary directory, +/// - `generate_completion_zsh`: Generates a Zsh completion script, creates the necessary directory, /// and prompts for overwriting existing files. -/// +/// /// ## Improvements to Consider /// 1. **Modularity**: Separate the completion logic into different modules for different shells /// (e.g., Zsh, Bash, Fish) to improve code organization. -/// 2. **Cross-Platform Support**: Abstract the completion generation into a trait or interface +/// 2. **Cross-Platform Support**: Abstract the completion generation into a trait or interface /// to facilitate adding support for other shell types. /// 3. **Enhanced Error Handling**: Provide more informative error messages for file operations. /// 4. **User Input Handling**: Ensure user input is trimmed and handled correctly. @@ -32,14 +32,18 @@ pub fn generate_completions(shell: &str) -> Result<(), Box { // Return an error for unsupported shell - Err(Box::from(format!("Unsupported shell for completion: {}", shell))) + Err(Box::from(format!( + "Unsupported shell for completion: {}", + shell + ))) } } } - // Modify the function to accept an optional input stream -fn generate_completion_zsh(input: Option<&mut dyn io::Read>) -> Result<(), Box> { +fn generate_completion_zsh( + input: Option<&mut dyn io::Read>, +) -> Result<(), Box> { let home_dir = std::env::var("HOME")?; let zfunc_dir = format!("{}/.zfunc", home_dir); let completion_file = format!("{}/_cargo-make", zfunc_dir); @@ -61,7 +65,10 @@ fn generate_completion_zsh(input: Option<&mut dyn io::Read>) -> Result<(), Box