implement -n, -v and -e commandline options
This commit is contained in:
parent
11ce644fca
commit
83ed7ee559
4 changed files with 179 additions and 20 deletions
120
Cargo.lock
generated
120
Cargo.lock
generated
|
|
@ -2,6 +2,55 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
|
@ -20,6 +69,52 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.15.8"
|
version = "0.15.8"
|
||||||
|
|
@ -79,6 +174,18 @@ dependencies = [
|
||||||
"wasi",
|
"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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -101,6 +208,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
name = "mvw"
|
name = "mvw"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"rand",
|
"rand",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
@ -188,6 +296,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.87"
|
version = "2.0.87"
|
||||||
|
|
@ -244,6 +358,12 @@ version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,4 @@ lto = "thin"
|
||||||
tempfile = "3.14.0"
|
tempfile = "3.14.0"
|
||||||
dialoguer = "0.11.0"
|
dialoguer = "0.11.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
clap = { version = "4.5.21", features = [ "derive" ]}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ use std::io::{ErrorKind, Write, BufRead, BufReader};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use rand::distributions::{Alphanumeric, DistString};
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
|
|
||||||
|
const LOCK_FILE: &str = ".mvwrap";
|
||||||
|
|
||||||
const POSTFIX_TMP_FILE: &str = ".mvwrap";
|
|
||||||
|
|
||||||
pub struct DirList {
|
pub struct DirList {
|
||||||
safe_source: bool,
|
safe_source: bool,
|
||||||
pub entries: Vec<String>,
|
noop: bool,
|
||||||
|
verbose: bool,
|
||||||
|
entries: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirList {
|
impl DirList {
|
||||||
|
|
@ -27,7 +27,7 @@ impl DirList {
|
||||||
let mut path_list : Vec<String> = vec![];
|
let mut path_list : Vec<String> = vec![];
|
||||||
for path in paths {
|
for path in paths {
|
||||||
let path_string = path.display().to_string();
|
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());
|
path_list.push(path_string[2..].to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,8 @@ impl DirList {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
safe_source: true,
|
safe_source: true,
|
||||||
|
noop: false,
|
||||||
|
verbose: false,
|
||||||
entries: path_list,
|
entries: path_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +50,8 @@ impl DirList {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
safe_source: true,
|
safe_source: true,
|
||||||
|
noop: false,
|
||||||
|
verbose: false,
|
||||||
entries: lines,
|
entries: lines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,10 +59,20 @@ impl DirList {
|
||||||
pub fn from_list(list: &Vec<String>) -> Self {
|
pub fn from_list(list: &Vec<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
safe_source: false,
|
safe_source: false,
|
||||||
|
noop: false,
|
||||||
|
verbose: false,
|
||||||
entries: list.to_vec(),
|
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) {
|
pub fn to_file(&self, target_file: &String) {
|
||||||
let mut file = File::create(target_file).expect("no such file");
|
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]) {
|
if self.entries.iter().any(|j| j==&target_list.entries[i]) {
|
||||||
let unique = Self::get_unique_entry(&target_list);
|
let unique = Self::get_unique_entry(&target_list);
|
||||||
intermediate_files.insert(unique.clone(), target_list.entries[i].clone());
|
intermediate_files.insert(unique.clone(), target_list.entries[i].clone());
|
||||||
fs::rename(&self.entries[i], &unique).expect("failed to rename file");
|
if ! self.noop { fs::rename(&self.entries[i], &unique).expect("failed to rename file"); }
|
||||||
println!("Moving {} -> {}", self.entries[i], unique);
|
if self.verbose { println!("Moving {} -> {}", self.entries[i], unique); }
|
||||||
} else {
|
} else {
|
||||||
fs::rename(&self.entries[i], &target_list.entries[i]).expect("failed to rename file");
|
if ! self.noop { 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.verbose { println!("Moving {} -> {}", self.entries[i], target_list.entries[i]); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (src, dst) in intermediate_files.iter() {
|
for (src, dst) in intermediate_files.iter() {
|
||||||
fs::rename(src, dst).expect("failed to rename file");
|
if ! self.noop { fs::rename(src, dst).expect("failed to rename file"); }
|
||||||
println!("Moving {} -> {}", src, dst);
|
if self.verbose { println!("Moving {} -> {}", src, dst); }
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
src/main.rs
42
src/main.rs
|
|
@ -1,5 +1,4 @@
|
||||||
mod dirlist;
|
mod dirlist;
|
||||||
|
|
||||||
pub use crate::dirlist::*;
|
pub use crate::dirlist::*;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
@ -10,8 +9,11 @@ use std::process;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use dialoguer::Confirm;
|
use dialoguer::Confirm;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
const LOCK_FILE: &str = ".mvwrap";
|
const LOCK_FILE: &str = ".mvwrap";
|
||||||
|
const SUFFIX_TMPFILE: &str = ".mvwrap";
|
||||||
|
const DEFAULT_EDITOR: &str = "vi";
|
||||||
|
|
||||||
struct Cleanup;
|
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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn lock_dir() {
|
fn lock_dir() {
|
||||||
if Path::new(LOCK_FILE).is_file() {
|
if Path::new(LOCK_FILE).is_file() {
|
||||||
panic!("Lock file \"{}\" already exists!", LOCK_FILE);
|
panic!("Lock file \"{}\" already exists!", LOCK_FILE);
|
||||||
|
|
@ -35,7 +55,7 @@ fn unlock_dir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_temp_file() -> String {
|
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();
|
let filepath = tmpfile.path().display().to_string();
|
||||||
|
|
||||||
|
|
@ -50,11 +70,10 @@ fn remove_temp_file(tmpfile: &String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_temp_file(tmpfile: &String) {
|
fn edit_temp_file(tmpfile: &String, editor_cli: &Option<String>) {
|
||||||
let editor = match env::var("EDITOR") {
|
let editor = env::var("EDITOR").unwrap_or(DEFAULT_EDITOR.to_string());
|
||||||
Ok(e) => e,
|
let editor = editor_cli.clone().unwrap_or(editor);
|
||||||
Err(_) => "vi".to_string(),
|
|
||||||
};
|
|
||||||
let _output = Command::new(editor)
|
let _output = Command::new(editor)
|
||||||
.arg(tmpfile)
|
.arg(tmpfile)
|
||||||
.status()
|
.status()
|
||||||
|
|
@ -62,6 +81,8 @@ fn edit_temp_file(tmpfile: &String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let args = Cli::parse();
|
||||||
|
|
||||||
// Place lockfile to not have multiple mvw processes running in the same dir at the same time
|
// Place lockfile to not have multiple mvw processes running in the same dir at the same time
|
||||||
lock_dir();
|
lock_dir();
|
||||||
let _cleanup = Cleanup; // Cleanup LOCK_FILE on panic
|
let _cleanup = Cleanup; // Cleanup LOCK_FILE on panic
|
||||||
|
|
@ -73,7 +94,10 @@ fn main() {
|
||||||
let temp_file = create_temp_file();
|
let temp_file = create_temp_file();
|
||||||
source_list.to_file(&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);
|
let mut target_list = DirList::from_file(&temp_file);
|
||||||
|
|
||||||
|
|
@ -92,7 +116,7 @@ fn main() {
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
edit_temp_file(&temp_file);
|
edit_temp_file(&temp_file, &args.editor);
|
||||||
target_list = DirList::from_file(&temp_file);
|
target_list = DirList::from_file(&temp_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue