mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
3faac9be6b
commit
4708e76275
3 changed files with 46 additions and 26 deletions
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue