diff --git a/src/cli.rs b/src/cli.rs index 57827f3..4135d0b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, env::current_dir, fs, path::PathBuf}; +use std::{ + collections::HashMap, + env::current_dir, + fs, + io::{BufRead, Write}, + path::PathBuf, +}; use clap::Parser; @@ -37,6 +43,8 @@ struct AddCommand { enum Command { Cook(CookCommand), Add { + #[clap(short, long)] + force: bool, #[clap(subcommand)] command: AddModuleCommand, }, @@ -51,16 +59,70 @@ struct Args { command: Command, } -pub fn cook( +fn tui_question(question: &str, default: bool) -> bool { + print!("{question}: ({}) ", if default { "Y/n" } else { "y/N" }); + + std::io::stdout() + .flush() + .expect("Flushing stdout shouldn't fail"); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let value = loop { + let mut buffer = String::new(); + handle + .read_line(&mut buffer) + .expect("Input string shouldn't fail"); + break match buffer.to_lowercase().trim() { + "" => default, + "y" => true, + "n" => false, + _ => continue, + }; + }; + + value +} + +fn cook( current_dir: PathBuf, cook_files: HashMap, + force: bool, ) -> Result<(), Box> { for (file_name, file_content) in cook_files { let file_path = ¤t_dir.join(file_name); - if file_content.trim().is_empty() { - fs::remove_file(file_path)?; + let file_exists = file_path.exists(); + let is_empty_file_content = file_content.trim().is_empty(); + + println!("{}", file_path.to_str().unwrap()); + if !force && file_exists { + if !(tui_question( + &format!( + " > already exists. Do you want to {} it?", + if is_empty_file_content { + "delete" + } else { + "overwrite" + } + ), + false, + )) { + println!(" > skipped"); + continue; + } + } + + if is_empty_file_content { + if file_exists { + fs::remove_file(file_path)?; + println!(" > deleted") + } } else { fs::write(file_path, file_content)?; + if file_exists { + println!(" > overwritten") + } else { + println!(" > created") + } } } @@ -87,9 +149,9 @@ pub fn run() -> Result<(), Box> { cook_files.extend(GitIgnoreModule.cook(cfg.into())); } - cook(current_dir, cook_files) + cook(current_dir, cook_files, true) } - Command::Add { command } => { + Command::Add { force, command } => { let mut cook_files: HashMap = HashMap::new(); match command { AddModuleCommand::Direnv(args) => cook_files.extend(DirenvModule.cook(args.into())), @@ -101,7 +163,7 @@ pub fn run() -> Result<(), Box> { } }; - cook(current_dir, cook_files) + cook(current_dir, cook_files, force) } } }