This commit is contained in:
sxyazi 2023-08-14 18:03:52 +08:00
parent 3faac9be6b
commit 4708e76275
No known key found for this signature in database
3 changed files with 46 additions and 26 deletions

View file

@ -48,8 +48,8 @@ impl Boot {
}
#[inline]
pub fn tmpfile(&self) -> PathBuf {
pub fn tmpfile(&self, prefix: &str) -> PathBuf {
let nanos = SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_nanos();
self.cache_dir.join(format!("{:x}", Md5::new_with_prefix(nanos.to_le_bytes()).finalize()))
self.cache_dir.join(format!("{prefix}-{}", nanos / 1000))
}
}

View file

@ -2,7 +2,7 @@ use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr,
use anyhow::{bail, Error, Result};
use config::{open::Opener, BOOT, OPEN};
use shared::{in_same_root, Defer, Term, MIME_DIR};
use shared::{max_common_root, Defer, Term, MIME_DIR};
use tokio::{fs::{self, OpenOptions}, io::{AsyncReadExt, AsyncWriteExt}};
use super::{PreviewData, Tab, Tabs, Watcher};
@ -224,18 +224,13 @@ impl Manager {
pub fn bulk_rename(&self) -> bool {
let mut old: Vec<_> = self.selected().iter().map(|&f| f.path()).collect();
if old.is_empty() {
return false;
}
let root = in_same_root(&old);
if let Some(ref root) = root {
old = old.into_iter().map(|p| p.strip_prefix(root).unwrap().to_owned()).collect();
}
let root = max_common_root(&old);
old = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect();
let tmp = BOOT.tmpfile();
let tmp = BOOT.tmpfile("bulk");
tokio::spawn(async move {
let Some(opener) = OPEN.block_opener("bulk-rename.txt", "text/plain") else {
let Some(opener) = OPEN.block_opener("bulk.txt", "text/plain") else {
bail!("No opener for bulk rename");
};
@ -246,7 +241,10 @@ impl Manager {
}
let _guard = BLOCKER.acquire().await.unwrap();
let _defer = Defer::new(|| Event::Stop(false, None).emit());
let _defer = Defer::new(|| {
Event::Stop(false, None).emit();
tokio::spawn(fs::remove_file(tmp.clone()))
});
emit!(Stop(true)).await;
let mut child = external::shell(ShellOpt {
@ -256,18 +254,14 @@ impl Manager {
})?;
child.wait().await?;
let new: Vec<_> = fs::read_to_string(tmp).await?.lines().map(|l| l.into()).collect();
let new: Vec<_> = fs::read_to_string(&tmp).await?.lines().map(|l| l.into()).collect();
Self::bulk_rename_do(root, old, new).await
});
false
}
async fn bulk_rename_do(
root: Option<PathBuf>,
old: Vec<PathBuf>,
new: Vec<PathBuf>,
) -> Result<()> {
async fn bulk_rename_do(root: PathBuf, old: Vec<PathBuf>, new: Vec<PathBuf>) -> Result<()> {
Term::clear()?;
if old.len() != new.len() {
println!("Number of old and new differ, press ENTER to exit");
@ -282,7 +276,7 @@ impl Manager {
stdout().write_all(b" -> ")?;
stdout().write_all(n.as_os_str().as_bytes())?;
stdout().write_all(b"\n")?;
todo.push(if let Some(ref root) = root { (root.join(o), root.join(n)) } else { (o, n) });
todo.push((root.join(o), root.join(n)));
}
}
if todo.is_empty() {

View file

@ -150,13 +150,39 @@ pub fn file_mode(mode: u32) -> String {
s
}
// Note: files must contain at least one file path
pub fn in_same_root(files: &[PathBuf]) -> Option<PathBuf> {
// Find the max common root of a list of files
// e.g. /a/b/c, /a/b/d -> /a/b
// /aa/bb/cc, /aa/dd/ee -> /aa
pub fn max_common_root(files: &[PathBuf]) -> PathBuf {
if files.is_empty() {
return None;
return PathBuf::new();
}
let mut files = files.iter();
let parent = files.next().map(|f| f.parent().unwrap_or(f).to_path_buf()).unwrap();
if files.all(|f| f.parent().unwrap_or(f) == parent) { Some(parent) } else { None }
let mut it = files.iter().map(|p| p.components());
let mut root = it.next().unwrap().collect::<PathBuf>();
for components in it {
let mut new_root = PathBuf::new();
for (a, b) in root.components().zip(components) {
if a != b {
break;
}
new_root.push(a);
}
root = new_root;
}
root
}
#[test]
fn test_max_common_root() {
assert_eq!(max_common_root(&[]).as_os_str(), "");
assert_eq!(max_common_root(&["".into()]).as_os_str(), "");
assert_eq!(max_common_root(&["/a/b".into()]).as_os_str(), "/a/b");
assert_eq!(max_common_root(&["/a/b/c".into(), "/a/b/d".into()]).as_os_str(), "/a/b");
assert_eq!(max_common_root(&["/aa/bb/cc".into(), "/aa/dd/ee".into()]).as_os_str(), "/aa");
assert_eq!(
max_common_root(&["/aa/bb/cc".into(), "/aa/bb/cc/dd/ee".into(), "/aa/bb/cc/ff".into()])
.as_os_str(),
"/aa/bb/cc"
);
}