From 83ed7ee559c5f8e9b0540aa5a5137e7b364f194d Mon Sep 17 00:00:00 2001 From: Ward Wouts Date: Wed, 27 Nov 2024 11:40:37 +0100 Subject: [PATCH] implement -n, -v and -e commandline options --- Cargo.lock | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/dirlist.rs | 36 ++++++++++----- src/main.rs | 42 +++++++++++++---- 4 files changed, 179 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af8bba4..b00504a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,55 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -20,6 +69,52 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "console" version = "0.15.8" @@ -79,6 +174,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "lazy_static" version = "1.5.0" @@ -101,6 +208,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" name = "mvw" version = "0.1.3" dependencies = [ + "clap", "dialoguer", "rand", "tempfile", @@ -188,6 +296,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.87" @@ -244,6 +358,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index f3e595b..848055b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ lto = "thin" tempfile = "3.14.0" dialoguer = "0.11.0" rand = "0.8.5" +clap = { version = "4.5.21", features = [ "derive" ]} diff --git a/src/dirlist.rs b/src/dirlist.rs index 2896581..bc412ec 100644 --- a/src/dirlist.rs +++ b/src/dirlist.rs @@ -5,13 +5,13 @@ use std::io::{ErrorKind, Write, BufRead, BufReader}; use std::collections::HashMap; use rand::distributions::{Alphanumeric, DistString}; - - -const POSTFIX_TMP_FILE: &str = ".mvwrap"; +const LOCK_FILE: &str = ".mvwrap"; pub struct DirList { safe_source: bool, - pub entries: Vec, + noop: bool, + verbose: bool, + entries: Vec, } impl DirList { @@ -27,7 +27,7 @@ impl DirList { let mut path_list : Vec = vec![]; for path in paths { let path_string = path.display().to_string(); - if path_string != format!("./{}", POSTFIX_TMP_FILE) { + if path_string != format!("./{}", LOCK_FILE) { path_list.push(path_string[2..].to_string()); } } @@ -35,6 +35,8 @@ impl DirList { Self { safe_source: true, + noop: false, + verbose: false, entries: path_list, } } @@ -48,6 +50,8 @@ impl DirList { Self { safe_source: true, + noop: false, + verbose: false, entries: lines, } } @@ -55,10 +59,20 @@ impl DirList { pub fn from_list(list: &Vec) -> Self { Self { safe_source: false, + noop: false, + verbose: false, entries: list.to_vec(), } } + pub fn set_noop(&mut self) { + self.noop = true; + } + + pub fn set_verbose(&mut self) { + self.verbose = true; + } + pub fn to_file(&self, target_file: &String) { let mut file = File::create(target_file).expect("no such file"); @@ -83,17 +97,17 @@ impl DirList { if self.entries.iter().any(|j| j==&target_list.entries[i]) { let unique = Self::get_unique_entry(&target_list); intermediate_files.insert(unique.clone(), target_list.entries[i].clone()); - fs::rename(&self.entries[i], &unique).expect("failed to rename file"); - println!("Moving {} -> {}", self.entries[i], unique); + if ! self.noop { fs::rename(&self.entries[i], &unique).expect("failed to rename file"); } + if self.verbose { println!("Moving {} -> {}", self.entries[i], unique); } } else { - fs::rename(&self.entries[i], &target_list.entries[i]).expect("failed to rename file"); - println!("Moving {} -> {}", self.entries[i], target_list.entries[i]); + if ! self.noop { fs::rename(&self.entries[i], &target_list.entries[i]).expect("failed to rename file"); } + if self.verbose { println!("Moving {} -> {}", self.entries[i], target_list.entries[i]); } } } } for (src, dst) in intermediate_files.iter() { - fs::rename(src, dst).expect("failed to rename file"); - println!("Moving {} -> {}", src, dst); + if ! self.noop { fs::rename(src, dst).expect("failed to rename file"); } + if self.verbose { println!("Moving {} -> {}", src, dst); } } Ok(()) } diff --git a/src/main.rs b/src/main.rs index 09d1034..adcb9b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod dirlist; - pub use crate::dirlist::*; use std::env; @@ -10,8 +9,11 @@ use std::process; use std::process::Command; use tempfile::NamedTempFile; use dialoguer::Confirm; +use clap::Parser; const LOCK_FILE: &str = ".mvwrap"; +const SUFFIX_TMPFILE: &str = ".mvwrap"; +const DEFAULT_EDITOR: &str = "vi"; struct Cleanup; @@ -21,6 +23,24 @@ impl Drop for Cleanup { } } +/// Wrapper to use an editor for renaming files +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct Cli { + /// Only show actions, but don't move files + #[arg(short, long)] + noop: bool, + + /// Show moves + #[arg(short, long)] + verbose: bool, + + /// Override editor to use + #[arg(short, long)] + editor: Option, +} + + fn lock_dir() { if Path::new(LOCK_FILE).is_file() { panic!("Lock file \"{}\" already exists!", LOCK_FILE); @@ -35,7 +55,7 @@ fn unlock_dir() { } fn create_temp_file() -> String { - let tmpfile = NamedTempFile::with_suffix(".mvwrap").expect("Could not create tempfile"); + let tmpfile = NamedTempFile::with_suffix(SUFFIX_TMPFILE).expect("Could not create tempfile"); let filepath = tmpfile.path().display().to_string(); @@ -50,11 +70,10 @@ fn remove_temp_file(tmpfile: &String) { } } -fn edit_temp_file(tmpfile: &String) { - let editor = match env::var("EDITOR") { - Ok(e) => e, - Err(_) => "vi".to_string(), - }; +fn edit_temp_file(tmpfile: &String, editor_cli: &Option) { + let editor = env::var("EDITOR").unwrap_or(DEFAULT_EDITOR.to_string()); + let editor = editor_cli.clone().unwrap_or(editor); + let _output = Command::new(editor) .arg(tmpfile) .status() @@ -62,6 +81,8 @@ fn edit_temp_file(tmpfile: &String) { } fn main() { + let args = Cli::parse(); + // Place lockfile to not have multiple mvw processes running in the same dir at the same time lock_dir(); let _cleanup = Cleanup; // Cleanup LOCK_FILE on panic @@ -73,7 +94,10 @@ fn main() { let temp_file = create_temp_file(); source_list.to_file(&temp_file); - edit_temp_file(&temp_file); + if args.noop { source_list.set_noop(); source_list.set_verbose(); } + if args.verbose { source_list.set_verbose(); } + + edit_temp_file(&temp_file, &args.editor); let mut target_list = DirList::from_file(&temp_file); @@ -92,7 +116,7 @@ fn main() { process::exit(1); } - edit_temp_file(&temp_file); + edit_temp_file(&temp_file, &args.editor); target_list = DirList::from_file(&temp_file); } }