From da1245c35c616b52f9a70446dd9225eac6e2d56e Mon Sep 17 00:00:00 2001 From: Jan Pipek Date: Tue, 23 Jul 2024 19:19:39 +0200 Subject: [PATCH 1/2] show-unchanged too --- src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++++++----------- src/main.rs | 14 +++++++--- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c10c08f..b7366dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use std::fs::rename; use std::io::ErrorKind; use std::path::{Path, PathBuf}; use std::process::{self, exit}; +use std::fmt::{Display, Formatter, Result}; extern crate unidecode; use unidecode::unidecode; @@ -19,6 +20,25 @@ impl RenameIntent { } } +impl Display for RenameIntent { + fn fmt(&self, f: &mut Formatter) -> Result { + if self.is_changed() { + write!( + f, + "{0} → {1}", + self.path.to_string_lossy().red(), + self.new_name.to_string_lossy().green() + ) + } else { + write!( + f, + "{0} =", + self.path.to_string_lossy(), + ) + } + } +} + pub enum RenameCommand { SetExtension(String), Remove(String), @@ -33,25 +53,22 @@ pub struct Config { pub dry: bool, pub files: Vec, pub auto_confirm: bool, + pub show_unchanged: bool, } fn confirm_intents(intents: &Vec) -> bool { println!("The following files will be renamed:"); - print_intents(intents); + print_intents(intents, false); println!("Do you want to continue? [y/N] "); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); input.trim().to_lowercase() == "y" } -fn print_intents(intents: &Vec) { +fn print_intents(intents: &Vec, show_unchanged: bool) { for intent in intents { - if intent.is_changed() { - println!( - "- {0} → {1}", - intent.path.to_string_lossy().red(), - intent.new_name.to_string_lossy().green() - ); + if intent.is_changed() || show_unchanged { + println!("{}", intent); } } } @@ -123,9 +140,16 @@ fn suggest_renames(files: &[PathBuf], command: &RenameCommand) -> Vec Option { +fn infer_mimetype(path: &Path, mime_type: bool) -> Option { let mut cmd = process::Command::new("file"); - let output = cmd.arg(path).arg("--brief").arg("--mime-type").output(); + let cmd_with_args = cmd.arg(path).arg("--brief"); + let cmd_with_args = if mime_type { + cmd_with_args.arg("--mime-type") + } else { + cmd_with_args + }; + + let output = cmd_with_args.output(); match output { Ok(output) => { let output_str = String::from_utf8(output.stdout).unwrap(); @@ -146,21 +170,36 @@ fn infer_mimetype(path: &Path) -> Option { } fn find_extensions_from_content(path: &Path) -> Vec { - match infer_mimetype(path) { + let mime_type_based = match infer_mimetype(path, true) { None => vec![], Some(mime_type) => { let mime_type_str = mime_type.as_str(); - dbg!(&mime_type); match mime_type_str { "application/pdf" => vec![String::from("pdf")], "image/jpeg" => vec![String::from("jpeg"), String::from("jpg")], "image/png" => vec![String::from("png")], "text/csv" => vec![String::from("csv")], "text/html" => vec![String::from("html"), String::from("htm")], + "text/x-script.python" => vec![String::from("py"), String::from("pyw")], _other => vec![], } } - } + }; + + let mut description_based = match infer_mimetype(path, false) { + None => vec![], + Some(description) => { + let description_str = description.as_str(); + match description_str { + "Apache Parquet" => vec![String::from("parquet"), String::from("pq")], + _other => vec![], + } + } + }; + + let mut extensions = mime_type_based.clone(); + extensions.append(&mut description_based); + extensions } fn has_correct_extension(path: &Path, possible_extensions: &[String]) -> bool { @@ -201,10 +240,10 @@ fn try_rename(path: &Path, new_name: &Path) -> bool { } } -fn process_command(command: &RenameCommand, files: &[PathBuf], dry: bool, auto_confirm: bool) { +fn process_command(command: &RenameCommand, files: &[PathBuf], dry: bool, auto_confirm: bool, show_unchanged: bool) { let intents = suggest_renames(files, command); if dry { - print_intents(&intents); + print_intents(&intents, show_unchanged); } else { let confirmed = auto_confirm || { let changed_count = intents.iter().filter(|i| i.is_changed()).count(); @@ -218,6 +257,9 @@ fn process_command(command: &RenameCommand, files: &[PathBuf], dry: bool, auto_c let renamed = try_rename(&intent.path, &intent.new_name); renamed_count += renamed as i32; } + if show_unchanged { + println!("{}", intent) + } } println!("{renamed_count} files renamed."); } @@ -230,5 +272,6 @@ pub fn run(config: &Config) { &config.files, config.dry, config.auto_confirm, + config.show_unchanged ); } diff --git a/src/main.rs b/src/main.rs index fa704c3..752b9d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,13 +11,12 @@ fn parse_config(matches: &ArgMatches) -> Config { Some(args) => args.cloned().collect(), None => vec![], }; - let dry = matches.get_flag("dry"); - let confirm = matches.get_flag("yes"); Config { command, - dry, + dry: matches.get_flag("dry"), files, - auto_confirm: confirm, + auto_confirm: matches.get_flag("yes"), + show_unchanged: matches.get_flag("unchanged"), } } @@ -58,6 +57,13 @@ fn create_cli_command() -> Command { .global(true) .action(clap::ArgAction::SetTrue), ) + .arg( + arg!( + -u --unchanged ... "Show unchanged files" + ) + .global(true) + .action(clap::ArgAction::SetTrue), + ) .arg( arg!( -y --yes ... "Automatically confirm all actions" From 97854dbacc416075c44e3b2bca58ff950a9e451d Mon Sep 17 00:00:00 2001 From: Jan Pipek Date: Wed, 14 Aug 2024 15:36:33 +0200 Subject: [PATCH 2/2] switch-case (downcase only currently) --- src/lib.rs | 27 +++++++++++++++++++-------- src/main.rs | 6 ++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b7366dd..de55132 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ use colored::Colorize; use regex::Regex; +use std::fmt::{Display, Formatter, Result}; use std::fs::rename; use std::io::ErrorKind; use std::path::{Path, PathBuf}; use std::process::{self, exit}; -use std::fmt::{Display, Formatter, Result}; extern crate unidecode; use unidecode::unidecode; @@ -30,11 +30,7 @@ impl Display for RenameIntent { self.new_name.to_string_lossy().green() ) } else { - write!( - f, - "{0} =", - self.path.to_string_lossy(), - ) + write!(f, "{0} =", self.path.to_string_lossy(),) } } } @@ -46,6 +42,7 @@ pub enum RenameCommand { FixExtension, Normalize, Replace(String, String, bool), + ChangeCase, } pub struct Config { @@ -136,6 +133,14 @@ fn suggest_renames(files: &[PathBuf], command: &RenameCommand) -> Vec { + let path_str = path.to_string_lossy().to_string(); + let new_name = path_str.to_lowercase(); + RenameIntent { + path: path.clone(), + new_name: PathBuf::from(new_name), + } + } }) .collect() } @@ -240,7 +245,13 @@ fn try_rename(path: &Path, new_name: &Path) -> bool { } } -fn process_command(command: &RenameCommand, files: &[PathBuf], dry: bool, auto_confirm: bool, show_unchanged: bool) { +fn process_command( + command: &RenameCommand, + files: &[PathBuf], + dry: bool, + auto_confirm: bool, + show_unchanged: bool, +) { let intents = suggest_renames(files, command); if dry { print_intents(&intents, show_unchanged); @@ -272,6 +283,6 @@ pub fn run(config: &Config) { &config.files, config.dry, config.auto_confirm, - config.show_unchanged + config.show_unchanged, ); } diff --git a/src/main.rs b/src/main.rs index 752b9d8..3326d90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ fn extract_command(args_matches: &ArgMatches) -> Option { matches.get_one::("replacement").unwrap().clone(), matches.get_flag("regex"), )), + Some(("change-case", _)) => Some(RenameCommand::ChangeCase), _ => None, } } @@ -142,6 +143,11 @@ fn create_cli_command() -> Command { ) .arg(path_arg.clone()), ) + .subcommand( + Command::new("change-case") + .about("Change case of all files.") + .arg(path_arg.clone()), + ) } fn main() {