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]
|
#[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();
|
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 anyhow::{bail, Error, Result};
|
||||||
use config::{open::Opener, BOOT, OPEN};
|
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 tokio::{fs::{self, OpenOptions}, io::{AsyncReadExt, AsyncWriteExt}};
|
||||||
|
|
||||||
use super::{PreviewData, Tab, Tabs, Watcher};
|
use super::{PreviewData, Tab, Tabs, Watcher};
|
||||||
|
|
@ -224,18 +224,13 @@ impl Manager {
|
||||||
|
|
||||||
pub fn bulk_rename(&self) -> bool {
|
pub fn bulk_rename(&self) -> bool {
|
||||||
let mut old: Vec<_> = self.selected().iter().map(|&f| f.path()).collect();
|
let mut old: Vec<_> = self.selected().iter().map(|&f| f.path()).collect();
|
||||||
if old.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let root = in_same_root(&old);
|
let root = max_common_root(&old);
|
||||||
if let Some(ref root) = root {
|
old = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect();
|
||||||
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 {
|
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");
|
bail!("No opener for bulk rename");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -246,7 +241,10 @@ impl Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
let _guard = BLOCKER.acquire().await.unwrap();
|
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;
|
emit!(Stop(true)).await;
|
||||||
|
|
||||||
let mut child = external::shell(ShellOpt {
|
let mut child = external::shell(ShellOpt {
|
||||||
|
|
@ -256,18 +254,14 @@ impl Manager {
|
||||||
})?;
|
})?;
|
||||||
child.wait().await?;
|
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
|
Self::bulk_rename_do(root, old, new).await
|
||||||
});
|
});
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn bulk_rename_do(
|
async fn bulk_rename_do(root: PathBuf, old: Vec<PathBuf>, new: Vec<PathBuf>) -> Result<()> {
|
||||||
root: Option<PathBuf>,
|
|
||||||
old: Vec<PathBuf>,
|
|
||||||
new: Vec<PathBuf>,
|
|
||||||
) -> Result<()> {
|
|
||||||
Term::clear()?;
|
Term::clear()?;
|
||||||
if old.len() != new.len() {
|
if old.len() != new.len() {
|
||||||
println!("Number of old and new differ, press ENTER to exit");
|
println!("Number of old and new differ, press ENTER to exit");
|
||||||
|
|
@ -282,7 +276,7 @@ impl Manager {
|
||||||
stdout().write_all(b" -> ")?;
|
stdout().write_all(b" -> ")?;
|
||||||
stdout().write_all(n.as_os_str().as_bytes())?;
|
stdout().write_all(n.as_os_str().as_bytes())?;
|
||||||
stdout().write_all(b"\n")?;
|
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() {
|
if todo.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -150,13 +150,39 @@ pub fn file_mode(mode: u32) -> String {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: files must contain at least one file path
|
// Find the max common root of a list of files
|
||||||
pub fn in_same_root(files: &[PathBuf]) -> Option<PathBuf> {
|
// 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() {
|
if files.is_empty() {
|
||||||
return None;
|
return PathBuf::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut files = files.iter();
|
let mut it = files.iter().map(|p| p.components());
|
||||||
let parent = files.next().map(|f| f.parent().unwrap_or(f).to_path_buf()).unwrap();
|
let mut root = it.next().unwrap().collect::<PathBuf>();
|
||||||
if files.all(|f| f.parent().unwrap_or(f) == parent) { Some(parent) } else { None }
|
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