diff --git a/core/src/manager/manager.rs b/core/src/manager/manager.rs index f6ee59e3..c24e0690 100644 --- a/core/src/manager/manager.rs +++ b/core/src/manager/manager.rs @@ -1,9 +1,9 @@ -use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr, io::{stdout, Write}, mem, os::unix::prelude::OsStrExt, path::{Path, PathBuf}}; +use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr, io::{stdout, BufWriter, Write}, mem, os::unix::prelude::OsStrExt, path::{Path, PathBuf}}; -use anyhow::{bail, Error, Result}; +use anyhow::{anyhow, bail, Error, Result}; use config::{open::Opener, BOOT, OPEN}; use shared::{max_common_root, Defer, Term, MIME_DIR}; -use tokio::{fs::{self, OpenOptions}, io::{AsyncReadExt, AsyncWriteExt}}; +use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}}; use super::{PreviewData, Tab, Tabs, Watcher}; use crate::{emit, external::{self, ShellOpt}, files::{File, FilesOp}, input::InputOpt, manager::Folder, select::SelectOpt, tasks::Tasks, Event, BLOCKER}; @@ -226,7 +226,7 @@ impl Manager { let mut old: Vec<_> = self.selected().iter().map(|&f| f.path()).collect(); let root = max_common_root(&old); - old = old.into_iter().map(|p| p.strip_prefix(&root).unwrap().to_owned()).collect(); + old.iter_mut().for_each(|p| *p = p.strip_prefix(&root).unwrap().to_owned()); let tmp = BOOT.tmpfile("bulk"); tokio::spawn(async move { @@ -265,52 +265,56 @@ impl Manager { Term::clear()?; if old.len() != new.len() { println!("Number of old and new differ, press ENTER to exit"); - tokio::io::stdin().read_exact(&mut [0]).await?; + stdin().read_exact(&mut [0]).await?; return Ok(()); } - let mut todo = Vec::with_capacity(old.len()); - for (o, n) in old.into_iter().zip(new) { - if n != o { - stdout().write_all(o.as_os_str().as_bytes())?; - stdout().write_all(b" -> ")?; - stdout().write_all(n.as_os_str().as_bytes())?; - stdout().write_all(b"\n")?; - todo.push((root.join(o), root.join(n))); - } - } + let todo: Vec<_> = old.into_iter().zip(new).filter(|(o, n)| o != n).collect(); if todo.is_empty() { return Ok(()); - } else { - print!("Continue to rename? (y/N): "); - stdout().flush()?; } - let mut buf = [0]; - tokio::io::stdin().read_exact(&mut buf).await?; + { + let mut stdout = BufWriter::new(stdout().lock()); + for (o, n) in &todo { + writeln!(stdout, "{} -> {}", o.display(), n.display())?; + } + write!(stdout, "Continue to rename? (y/N): ")?; + stdout.flush()?; + } + + let mut buf = [0; 10]; + stdin().read(&mut buf).await.ok(); if buf[0] != b'y' && buf[0] != b'Y' { return Ok(()); } let mut failed = Vec::new(); for (o, n) in todo { - if let Err(e) = fs::rename(&o, &n).await { - failed.push((o, n, e)); + if fs::metadata(&n).await.is_ok() { + failed.push((o, n, anyhow!("Destination already exists"))); + continue; } + if let Err(e) = fs::rename(root.join(&o), root.join(&n)).await { + failed.push((o, n, e.into())); + } + } + if failed.is_empty() { + return Ok(()); } - if !failed.is_empty() { - Term::clear()?; - println!("Failed to rename:"); + Term::clear()?; + { + let mut stdout = BufWriter::new(stdout().lock()); + writeln!(stdout, "Failed to rename:")?; for (o, n, e) in failed { - stdout().write_all(o.as_os_str().as_bytes())?; - stdout().write_all(b" -> ")?; - stdout().write_all(n.as_os_str().as_bytes())?; - stdout().write_fmt(format_args!(": {e}\n"))?; + writeln!(stdout, "{} -> {}: {e}", o.display(), n.display())?; } - println!("\nPress ENTER to exit"); - tokio::io::stdin().read_exact(&mut [0]).await?; + writeln!(stdout, "\nPress ENTER to exit")?; + stdout.flush()?; } + + stdin().read_exact(&mut [0]).await?; Ok(()) } diff --git a/shared/src/fs.rs b/shared/src/fs.rs index bc62d97a..8201f44e 100644 --- a/shared/src/fs.rs +++ b/shared/src/fs.rs @@ -158,7 +158,7 @@ pub fn max_common_root(files: &[PathBuf]) -> PathBuf { return PathBuf::new(); } - let mut it = files.iter().map(|p| p.components()); + let mut it = files.iter().map(|p| p.parent().unwrap_or(Path::new("")).components()); let mut root = it.next().unwrap().collect::(); for components in it { let mut new_root = PathBuf::new(); @@ -177,12 +177,14 @@ pub fn max_common_root(files: &[PathBuf]) -> PathBuf { 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".into()]).as_os_str(), ""); + assert_eq!(max_common_root(&["/a".into()]).as_os_str(), "/"); + assert_eq!(max_common_root(&["/a/b".into()]).as_os_str(), "/a"); 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" + "/aa/bb" ); }