summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqkzk <qu3nt1n@gmail.com>2022-10-16 20:30:33 +0200
committerqkzk <qu3nt1n@gmail.com>2022-10-16 20:30:33 +0200
commit3991d97879a4e8a4f97504cc45bd7eb4bdfbf14a (patch)
treee69200bb96a92e103b297fdba9ba26520914aff5
parent104fe9c0f4513b3fe67f08038f8cc2018890d09d (diff)
refactor bulkrename, bug fix wrong comparisonbulkrename
-rw-r--r--src/actioner.rs1
-rw-r--r--src/bulkrename.rs61
-rw-r--r--src/config.rs6
-rw-r--r--src/event_char.rs2
-rw-r--r--src/fileinfo.rs4
-rw-r--r--src/help.rs1
-rw-r--r--src/tabs.rs19
7 files changed, 79 insertions, 15 deletions
diff --git a/src/actioner.rs b/src/actioner.rs
index 88d64c1..a75efb2 100644
--- a/src/actioner.rs
+++ b/src/actioner.rs
@@ -50,6 +50,7 @@ impl Actioner {
(keybindings.preview, EventChar::Preview),
(keybindings.history, EventChar::History),
(keybindings.shortcut, EventChar::Shortcut),
+ (keybindings.bulkrename, EventChar::Bulkrename),
]);
Self { binds, term }
}
diff --git a/src/bulkrename.rs b/src/bulkrename.rs
index 99da1d0..f67bec0 100644
--- a/src/bulkrename.rs
+++ b/src/bulkrename.rs
@@ -1,6 +1,8 @@
use rand::Rng;
-use std::io::{self, BufRead};
+use std::io::{self, BufRead, Write};
use std::path::PathBuf;
+use std::thread;
+use std::time::{Duration, SystemTime};
use crate::opener::{ExtensionKind, Opener};
@@ -8,20 +10,48 @@ use crate::opener::{ExtensionKind, Opener};
static TMP_FOLDER: &str = "/tmp";
-struct BulkRenamer {
+pub struct Bulkrename {
original_filepath: Vec<PathBuf>,
temp_file: PathBuf,
}
-impl BulkRenamer {
+impl Bulkrename {
pub fn new(original_filepath: Vec<PathBuf>) -> Result<Self, io::Error> {
- let temp_file = Self::create_random_file()?;
+ let temp_file = Self::generate_random_filepath()?;
Ok(Self {
original_filepath,
temp_file,
})
}
+ pub fn rename(&mut self, opener: &Opener) -> Result<(), io::Error> {
+ self.write_original_names()?;
+ let original_modification = Self::get_modified_date(&self.temp_file)?;
+ self.open_temp_file_with_editor(opener)?;
+
+ Self::watch_modification_in_thread(self.temp_file.clone(), original_modification);
+
+ self.rename_all(self.get_new_filenames()?)?;
+ self.delete_temp_file()?;
+ Ok(())
+ }
+
+ fn watch_modification_in_thread(filepath: PathBuf, original_modification: SystemTime) {
+ let handle = thread::spawn(move || loop {
+ if Self::is_file_modified(&filepath, original_modification.clone())
+ .unwrap_or_else(|_| true)
+ {
+ break;
+ }
+ thread::sleep(Duration::from_millis(10));
+ });
+ handle.join().unwrap();
+ }
+
+ fn get_modified_date(filepath: &PathBuf) -> Result<SystemTime, io::Error> {
+ std::fs::metadata(filepath)?.modified()
+ }
+
fn random_name() -> String {
let mut rand_str = String::with_capacity(10);
rand_str.push_str("fm-");
@@ -32,19 +62,20 @@ impl BulkRenamer {
rand_str
}
- fn create_random_file() -> Result<PathBuf, io::Error> {
+ fn generate_random_filepath() -> Result<PathBuf, io::Error> {
let mut filepath = PathBuf::from(&TMP_FOLDER);
filepath.push(Self::random_name());
- let _ = std::fs::File::create(&filepath)?;
Ok(filepath)
}
fn write_original_names(&self) -> Result<(), io::Error> {
- let filepath = &self.temp_file;
+ let mut file = std::fs::File::create(&self.temp_file)?;
for path in self.original_filepath.iter() {
if let Some(os_filename) = path.file_name() {
if let Some(filename) = os_filename.to_str() {
- std::fs::write(&filepath, filename)?
+ let b = filename.as_bytes();
+ file.write_all(b)?;
+ file.write_all(&[b'\n'])?;
}
}
}
@@ -60,15 +91,15 @@ impl BulkRenamer {
}
fn is_file_modified(
- filepath: PathBuf,
+ path: &PathBuf,
original_modification: std::time::SystemTime,
) -> Result<bool, io::Error> {
- let last_modification = std::fs::metadata(&filepath)?.modified()?;
- Ok(last_modification <= original_modification)
+ let last_modification = Self::get_modified_date(path)?;
+ Ok(last_modification > original_modification)
}
- fn get_new_filenames(&self, filepath: PathBuf) -> Result<Vec<String>, io::Error> {
- let file = std::fs::File::open(&filepath)?;
+ fn get_new_filenames(&self) -> Result<Vec<String>, io::Error> {
+ let file = std::fs::File::open(&self.temp_file)?;
let reader = std::io::BufReader::new(file);
let mut new_names = vec![];
@@ -93,12 +124,12 @@ impl BulkRenamer {
fn rename_all(&self, new_filenames: Vec<String>) -> Result<(), io::Error> {
for (path, filename) in self.original_filepath.iter().zip(new_filenames.iter()) {
- self.rename(path, filename)?
+ self.rename_file(path, filename)?
}
Ok(())
}
- fn rename(&self, path: &PathBuf, filename: &str) -> Result<(), io::Error> {
+ fn rename_file(&self, path: &PathBuf, filename: &str) -> Result<(), io::Error> {
let mut parent = path.clone();
parent.pop();
Ok(std::fs::rename(path, parent.join(&filename))?)
diff --git a/src/config.rs b/src/config.rs
index a75daca..d343c91 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -200,6 +200,8 @@ pub struct Keybindings {
pub history: char,
/// Display predefined shortcuts
pub shortcut: char,
+ /// Bulkrename
+ pub bulkrename: char,
}
impl Keybindings {
@@ -287,6 +289,9 @@ impl Keybindings {
if let Some(shortcut) = yaml["shortcut"].as_str().map(|s| s.to_string()) {
self.shortcut = shortcut.chars().next().unwrap_or('G');
}
+ if let Some(bulkrename) = yaml["bulkrename"].as_str().map(|s| s.to_string()) {
+ self.bulkrename = bulkrename.chars().next().unwrap_or('B');
+ }
}
/// Returns a new `Keybindings` instance with hardcoded values.
@@ -319,6 +324,7 @@ impl Keybindings {
preview: 'P',
history: 'H',
shortcut: 'G',
+ bulkrename: 'B',
}
}
}
diff --git a/src/event_char.rs b/src/event_char.rs
index 7816e4a..88d9036 100644
--- a/src/event_char.rs
+++ b/src/event_char.rs
@@ -28,6 +28,7 @@ pub enum EventChar {
Symlink,
Preview,
Shortcut,
+ Bulkrename,
}
impl EventChar {
@@ -61,6 +62,7 @@ impl EventChar {
EventChar::Symlink => tabs.event_symlink(),
EventChar::Preview => current_status.event_preview(),
EventChar::Shortcut => current_status.event_shortcut(),
+ EventChar::Bulkrename => tabs.event_bulkrename(),
}
}
}
diff --git a/src/fileinfo.rs b/src/fileinfo.rs
index 02f77cf..55fe508 100644
--- a/src/fileinfo.rs
+++ b/src/fileinfo.rs
@@ -320,6 +320,10 @@ impl PathContent {
Some(&self.files[self.selected])
}
}
+
+ pub fn contains(&self, path: &path::PathBuf) -> bool {
+ path.starts_with(&self.path)
+ }
}
/// Associates a filetype to `tuikit::prelude::Attr` : fg color, bg color and
diff --git a/src/help.rs b/src/help.rs
index 6ac506f..4dca4ef 100644
--- a/src/help.rs
+++ b/src/help.rs
@@ -37,6 +37,7 @@ Ctrl+f: fuzzy finder
p: move to current dir
x: delete flagged files
S: symlink flagged files
+ B: Bulkrename
- MODES -
m: CHMOD
diff --git a/src/tabs.rs b/src/tabs.rs
index f8e9d40..d2b35e3 100644
--- a/src/tabs.rs
+++ b/src/tabs.rs
@@ -7,6 +7,7 @@ use std::path::{self, PathBuf};
use std::sync::Arc;
use crate::args::Args;
+use crate::bulkrename::Bulkrename;
use crate::config::Config;
use crate::fileinfo::PathContent;
use crate::last_edition::LastEdition;
@@ -220,6 +221,24 @@ impl Tabs {
self.reset_statuses()
}
+ pub fn event_bulkrename(&mut self) {
+ match Bulkrename::new(self.filtered_flagged_files()) {
+ Ok(mut renamer) => {
+ let _ = renamer.rename(&self.selected().opener);
+ }
+ Err(e) => eprintln!("{}", e),
+ }
+ }
+
+ fn filtered_flagged_files(&mut self) -> Vec<PathBuf> {
+ let path_content = self.selected().path_content.clone();
+ self.flagged
+ .iter()
+ .filter(|p| path_content.contains(p))
+ .map(|p| p.to_owned())
+ .collect()
+ }
+
fn exec_copy_paste(&mut self) {
self.flagged.iter().for_each(|oldpath| {
let newpath = self.statuses[self.index]