summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Zhao <jeff.no.zhao@gmail.com>2022-07-18 12:06:49 -0400
committerJeff Zhao <jeff.no.zhao@gmail.com>2022-07-18 12:06:49 -0400
commit743354da056c65c6ce0910394230270ef793d8cc (patch)
tree22795339118dfdf2e819a03fa3b8081d87226339
parenteb8b155329b2c2689cc5b854f0b87f4448485c66 (diff)
asynchronize delete operation
-rw-r--r--src/commands/delete_files.rs70
-rw-r--r--src/commands/file_ops.rs10
-rw-r--r--src/context/local_state.rs8
-rw-r--r--src/context/worker_context.rs6
-rw-r--r--src/event/app_event.rs6
-rw-r--r--src/event/process_event.rs26
-rw-r--r--src/io/file_operation.rs81
-rw-r--r--src/io/io_observer.rs11
-rw-r--r--src/io/io_worker.rs266
-rw-r--r--src/io/mod.rs6
-rw-r--r--src/key_command/command.rs4
-rw-r--r--src/key_command/impl_comment.rs5
-rw-r--r--src/key_command/impl_from_str.rs4
-rw-r--r--src/ui/widgets/tui_worker.rs12
14 files changed, 279 insertions, 236 deletions
diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs
index b702771..c56118d 100644
--- a/src/commands/delete_files.rs
+++ b/src/commands/delete_files.rs
@@ -1,63 +1,14 @@
-use std::fs;
use std::path;
use termion::event::Key;
use crate::context::AppContext;
use crate::history::DirectoryHistory;
+use crate::io::{FileOperation, FileOperationOptions, IoWorkerThread};
use crate::ui::widgets::TuiPrompt;
use crate::ui::AppBackend;
-use super::reload;
-
-fn trash_error_to_io_error(err: trash::Error) -> std::io::Error {
- match err {
- trash::Error::Unknown { description } => {
- std::io::Error::new(std::io::ErrorKind::Other, description)
- }
- trash::Error::TargetedRoot => {
- std::io::Error::new(std::io::ErrorKind::Other, "Targeted Root")
- }
- _ => std::io::Error::new(std::io::ErrorKind::Other, "Unknown Error"),
- }
-}
-
-pub fn remove_files<P>(paths: &[P]) -> std::io::Result<()>
-where
- P: AsRef<path::Path>,
-{
- for path in paths {
- if let Ok(metadata) = fs::symlink_metadata(path) {
- if metadata.is_dir() {
- fs::remove_dir_all(&path)?;
- } else {
- fs::remove_file(&path)?;
- }
- }
- }
- Ok(())
-}
-
-pub fn trash_files<P>(paths: &[P]) -> std::io::Result<()>
-where
- P: AsRef<path::Path>,
-{
- for path in paths {
- if let Err(e) = trash::delete(path) {
- return Err(trash_error_to_io_error(e));
- }
- }
- Ok(())
-}
-
fn delete_files(context: &mut AppContext, backend: &mut AppBackend) -> std::io::Result<()> {
- let delete_func = if context.config_ref().use_trash {
- trash_files
- } else {
- remove_files
- };
-
- let tab_index = context.tab_context_ref().index;
let paths = context
.tab_context_ref()
.curr_tab_ref()
@@ -92,17 +43,16 @@ fn delete_files(context: &mut AppContext, backend: &mut AppBackend) -> std::io::
true
};
if confirm_delete {
- delete_func(&paths)?;
+ let file_op = FileOperation::Delete;
+ let options = FileOperationOptions {
+ overwrite: false,
+ skip_exist: false,
+ permanently: !context.config_ref().use_trash,
+ };
- // remove directory previews
- for tab in context.tab_context_mut().iter_mut() {
- for p in &paths {
- tab.history_mut().remove(p.as_path());
- }
- }
- reload::reload(context, tab_index)?;
- let msg = format!("Deleted {} files", paths_len);
- context.message_queue_mut().push_success(msg);
+ let dest = path::PathBuf::new();
+ let worker_thread = IoWorkerThread::new(file_op, paths, dest, options);
+ context.worker_context_mut().push_worker(worker_thread);
}
Ok(())
}
diff --git a/src/commands/file_ops.rs b/src/commands/file_ops.rs
index 9e9498d..ce9b787 100644
--- a/src/commands/file_ops.rs
+++ b/src/commands/file_ops.rs
@@ -3,9 +3,7 @@ use std::process::Command;
use crate::context::{AppContext, LocalStateContext};
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
-use crate::io::FileOp;
-
-use crate::io::{IoWorkerOptions, IoWorkerThread};
+use crate::io::{FileOperation, FileOperationOptions, IoWorkerThread};
pub fn cut(context: &mut AppContext) -> JoshutoResult {
if let Some(list) = context.tab_context_ref().curr_tab_ref().curr_list_ref() {
@@ -13,7 +11,7 @@ pub fn cut(context: &mut AppContext) -> JoshutoResult {
let mut local_state = LocalStateContext::new();
local_state.set_paths(selected.into_iter());
- local_state.set_file_op(FileOp::Cut);
+ local_state.set_file_op(FileOperation::Cut);
context.set_local_state(local_state);
}
@@ -26,14 +24,14 @@ pub fn copy(context: &mut AppContext) -> JoshutoResult {
let mut local_state = LocalStateContext::new();
local_state.set_paths(selected.into_iter());
- local_state.set_file_op(FileOp::Copy);
+ local_state.set_file_op(FileOperation::Copy);
context.set_local_state(local_state);
}
Ok(())
}
-pub fn paste(context: &mut AppContext, options: IoWorkerOptions) -> JoshutoResult {
+pub fn paste(context: &mut AppContext, options: FileOperationOptions) -> JoshutoResult {
match context.take_local_state() {
Some(state) if !state.paths.is_empty() => {
let dest = context.tab_context_ref().curr_tab_ref().cwd().to_path_buf();
diff --git a/src/context/local_state.rs b/src/context/local_state.rs
index 71ca8f4..049d90d 100644
--- a/src/context/local_state.rs
+++ b/src/context/local_state.rs
@@ -1,22 +1,22 @@
-use crate::io::FileOp;
+use crate::io::FileOperation;
use std::iter::Iterator;
use std::path;
pub struct LocalStateContext {
pub paths: Vec<path::PathBuf>,
- pub file_op: FileOp,
+ pub file_op: FileOperation,
}
impl LocalStateContext {
pub fn new() -> Self {
Self {
paths: Vec::new(),
- file_op: FileOp::Copy,
+ file_op: FileOperation::Copy,
}
}
- pub fn set_file_op(&mut self, operation: FileOp) {
+ pub fn set_file_op(&mut self, operation: FileOperation) {
self.file_op = operation;
}
diff --git a/src/context/worker_context.rs b/src/context/worker_context.rs
index fdd76fa..5bdf055 100644
--- a/src/context/worker_context.rs
+++ b/src/context/worker_context.rs
@@ -4,7 +4,7 @@ use std::sync::mpsc;
use std::thread;
use crate::event::AppEvent;
-use crate::io::{IoWorkerObserver, IoWorkerProgress, IoWorkerThread};
+use crate::io::{FileOperationProgress, IoWorkerObserver, IoWorkerThread};
pub struct WorkerContext {
// forks of applications
@@ -49,7 +49,7 @@ impl WorkerContext {
self.worker.as_ref()
}
- pub fn set_progress(&mut self, res: IoWorkerProgress) {
+ pub fn set_progress(&mut self, res: FileOperationProgress) {
if let Some(s) = self.worker.as_mut() {
s.set_progress(res);
}
@@ -77,7 +77,7 @@ impl WorkerContext {
let worker_handle = thread::spawn(move || worker.start(wtx));
// relay worker info to event loop
while let Ok(progress) = wrx.recv() {
- let _ = tx.send(AppEvent::IoWorkerProgress(progress));
+ let _ = tx.send(AppEvent::FileOperationProgress(progress));
}
let result = worker_handle.join();
diff --git a/src/event/app_event.rs b/src/event/app_event.rs
index fd232f6..a22b0f7 100644
--- a/src/event/app_event.rs
+++ b/src/event/app_event.rs
@@ -11,7 +11,7 @@ use termion::event::Event;
use termion::input::TermRead;
use crate::fs::JoshutoDirList;
-use crate::io::IoWorkerProgress;
+use crate::io::FileOperationProgress;
use crate::preview::preview_file::FilePreview;
#[derive(Debug)]
@@ -21,8 +21,8 @@ pub enum AppEvent {
// background IO worker events
IoWorkerCreate,
- IoWorkerProgress(IoWorkerProgress),
- IoWorkerResult(io::Result<IoWorkerProgress>),
+ FileOperationProgress(FileOperationProgress),
+ IoWorkerResult(io::Result<FileOperationProgress>),
// forked process events
ChildProcessComplete(u32),
diff --git a/src/event/process_event.rs b/src/event/process_event.rs
index bf587a3..f8fe41a 100644
--- a/src/event/process_event.rs
+++ b/src/event/process_event.rs
@@ -11,7 +11,7 @@ use crate::context::AppContext;
use crate::event::AppEvent;
use crate::fs::JoshutoDirList;
use crate::history::DirectoryHistory;
-use crate::io::{FileOp, IoWorkerProgress};
+use crate::io::{FileOperation, FileOperationProgress};
use crate::key_command::{AppExecute, Command, CommandKeybind};
use crate::preview::preview_file::FilePreview;
use crate::ui;
@@ -56,7 +56,7 @@ pub fn get_input_while_composite<'a>(
pub fn process_noninteractive(event: AppEvent, context: &mut AppContext) {
match event {
AppEvent::IoWorkerCreate => process_new_worker(context),
- AppEvent::IoWorkerProgress(res) => process_worker_progress(context, res),
+ AppEvent::FileOperationProgress(res) => process_worker_progress(context, res),
AppEvent::IoWorkerResult(res) => process_finished_worker(context, res),
AppEvent::PreviewDir(Ok(dirlist)) => process_dir_preview(context, dirlist),
AppEvent::PreviewFile(path, file_preview) => {
@@ -81,13 +81,16 @@ pub fn process_new_worker(context: &mut AppContext) {
}
}
-pub fn process_worker_progress(context: &mut AppContext, res: IoWorkerProgress) {
+pub fn process_worker_progress(context: &mut AppContext, res: FileOperationProgress) {
let worker_context = context.worker_context_mut();
worker_context.set_progress(res);
worker_context.update_msg();
}
-pub fn process_finished_worker(context: &mut AppContext, res: std::io::Result<IoWorkerProgress>) {
+pub fn process_finished_worker(
+ context: &mut AppContext,
+ res: std::io::Result<FileOperationProgress>,
+) {
let worker_context = context.worker_context_mut();
let observer = worker_context.remove_worker().unwrap();
let options = context.config_ref().display_options_ref().clone();
@@ -95,12 +98,23 @@ pub fn process_finished_worker(context: &mut AppContext, res: std::io::Result<Io
let _ = tab.history_mut().reload(observer.dest_path(), &options);
let _ = tab.history_mut().reload(observer.src_path(), &options);
}
+
+ /* delete
+ // remove directory previews
+ for tab in context.tab_context_mut().iter_mut() {
+ for p in &paths {
+ tab.history_mut().remove(p.as_path());
+ }
+ }
+ */
+
observer.join();
match res {
Ok(progress) => {
let op = match progress.kind() {
- FileOp::Copy => "copied",
- FileOp::Cut => "moved",
+ FileOperation::Cut => "moved",
+ FileOperation::Copy => "copied",
+ FileOperation::Delete => "deleted",
};
let processed_size = format::file_size_to_string(progress.bytes_processed());
let total_size = format::file_size_to_string(progress.total_bytes());
diff --git a/src/io/file_operation.rs b/src/io/file_operation.rs
new file mode 100644
index 0000000..a0000f7
--- /dev/null
+++ b/src/io/file_operation.rs
@@ -0,0 +1,81 @@
+#[derive(Clone, Copy, Debug)]
+pub enum FileOperation {
+ Cut,
+ Copy,
+ Delete,
+}
+
+#[derive(Clone, Copy, Debug, Default)]
+pub struct FileOperationOptions {
+ // cut, copy
+ pub overwrite: bool,
+ pub skip_exist: bool,
+
+ // delete
+ pub permanently: bool,
+}
+
+impl std::fmt::Display for FileOperationOptions {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(
+ f,
+ "overwrite={} skip_exist={}",
+ self.overwrite, self.skip_exist
+ )
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct FileOperationProgress {
+ _kind: FileOperation,
+ _files_processed: usize,
+ _total_files: usize,
+ _bytes_processed: u64,
+ _total_bytes: u64,
+}
+
+impl FileOperationProgress {
+ pub fn new(
+ _kind: FileOperation,
+ _files_processed: usize,
+ _total_files: usize,
+ _bytes_processed: u64,
+ _total_bytes: u64,
+ ) -> Self {
+ Self {
+ _kind,
+ _files_processed,
+ _total_files,
+ _bytes_processed,
+ _total_bytes,
+ }
+ }
+
+ pub fn kind(&self) -> FileOperation {
+ self._kind
+ }
+
+ pub fn files_processed(&self) -> usize {
+ self._files_processed
+ }
+
+ pub fn set_files_processed(&mut self, files_processed: usize) {
+ self._files_processed = files_processed;
+ }
+
+ pub fn total_files(&self) -> usize {
+ self._total_files
+ }
+
+ pub fn bytes_processed(&self) -> u64 {
+ self._bytes_processed
+ }
+
+ pub fn set_bytes_processed(&mut self, _bytes_processed: u64) {
+ self._bytes_processed = _bytes_processed;
+ }
+
+ pub fn total_bytes(&self) -> u64 {
+ self._total_bytes
+ }
+}
diff --git a/src/io/io_observer.rs b/src/io/io_observer.rs
index 4e9d3af..2df4842 100644
--- a/src/io/io_observer.rs
+++ b/src/io/io_observer.rs
@@ -1,13 +1,13 @@
use std::path;
use std::thread;
-use crate::io::{FileOp, IoWorkerProgress};
+use crate::io::{FileOperation, FileOperationProgress};
use crate::util::format;
#[derive(Debug)]
pub struct IoWorkerObserver {
pub handle: thread::JoinHandle<()>,
- pub progress: Option<IoWorkerProgress>,
+ pub progress: Option<FileOperationProgress>,
msg: String,
src: path::PathBuf,
dest: path::PathBuf,
@@ -27,7 +27,7 @@ impl IoWorkerObserver {
pub fn join(self) -> bool {
matches!(self.handle.join(), Ok(_))
}
- pub fn set_progress(&mut self, progress: IoWorkerProgress) {
+ pub fn set_progress(&mut self, progress: FileOperationProgress) {
self.progress = Some(progress);
}
pub fn update_msg(&mut self) {
@@ -35,8 +35,9 @@ impl IoWorkerObserver {
None => {}
Some(progress) => {
let op_str = match progress.kind() {
- FileOp::Cut => "Moving",
- FileOp::Copy => "Copying",
+ FileOperation::Cut => "Moving",
+ FileOperation::Copy => "Copying",
+ FileOperation::Delete => "Deleting",
};
let processed_size = format::file_size_to_string(progress.bytes_processed());
let total_size = format::file_size_to_string(progress.total_bytes());
diff --git a/src/io/io_worker.rs b/src/io/io_worker.rs
index 505e524..50d8035 100644
--- a/src/io/io_worker.rs
+++ b/src/io/io_worker.rs
@@ -4,99 +4,23 @@ use std::io;
use std::path;
use std::sync::mpsc;
+use crate::io::{FileOperation, FileOperationOptions, FileOperationProgress};
use crate::util::name_resolution::rename_filename_conflict;
-#[derive(Clone, Copy, Debug)]
-pub enum FileOp {
- Cut,
- Copy,
-}
-
-#[derive(Clone, Copy, Debug, Default)]
-pub struct IoWorkerOptions {
- pub overwrite: bool,
- pub skip_exist: bool,
-}
-
-impl std::fmt::Display for IoWorkerOptions {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(
- f,
- "overwrite={} skip_exist={}",
- self.overwrite, self.skip_exist
- )
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct IoWorkerProgress {
- _kind: FileOp,
- _files_processed: usize,
- _total_files: usize,
- _bytes_processed: u64,
- _total_bytes: u64,
-}
-
-impl IoWorkerProgress {
- pub fn new(
- _kind: FileOp,
- _files_processed: usize,
- _total_files: usize,
- _bytes_processed: u64,
- _total_bytes: u64,
- ) -> Self {
- Self {
- _kind,
- _files_processed,
- _total_files,
- _bytes_processed,
- _total_bytes,
- }
- }
-
- pub fn kind(&self) -> FileOp {
- self._kind
- }
-
- pub fn files_processed(&self) -> usize {
- self._files_processed
- }
-
- pub fn set_files_processed(&mut self, files_processed: usize) {
- self._files_processed = files_processed;
- }
-
- pub fn total_files(&self) -> usize {
- self._total_files
- }
-
- pub fn bytes_processed(&self) -> u64 {
- self._bytes_processed
- }
-
- pub fn set_bytes_processed(&mut self, _bytes_processed: u64) {
- self._bytes_processed = _bytes_processed;
- }
-
- pub fn total_bytes(&self) -> u64 {
- self._total_bytes
- }
-}
-
#[derive(Clone, Debug)]
pub struct IoWorkerThread {
- _kind: FileOp,
- pub options: IoWorkerOptions,
+ _kind: FileOperation,
+ pub options: FileOperationOptions,
pub paths: Vec<path::PathBuf>,
pub dest: path::PathBuf,
}
impl IoWorkerThread {
pub fn new(
- _kind: FileOp,
+ _kind: FileOperation,
paths: Vec<path::PathBuf>,
dest: path::PathBuf,
- options: IoWorkerOptions,
+ options: FileOperationOptions,
) -> Self {
Self {
_kind,
@@ -106,88 +30,118 @@ impl IoWorkerThread {
}
}
- pub fn kind(&self) -> FileOp {
+ pub fn kind(&self) -> FileOperation {
self._kind
}
- pub fn start(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
+ pub fn start(
+ &self,
+ tx: mpsc::Sender<FileOperationProgress>,
+ ) -> io::Result<FileOperationProgress> {
match self.kind() {
- FileOp::Cut => self.paste_cut(tx),
- FileOp::Copy => self.paste_copy(tx),
+ FileOperation::Cut => self.paste_cut(tx),
+ FileOperation::Copy => self.paste_copy(tx),
+ FileOperation::Delete => self.delete(tx),
}
}
- fn query_number_of_items(&self) -> io::Result<(usize, u64)> {
- let mut total_bytes = 0;
- let mut total_files = 0;
-
- let mut dirs: VecDeque<path::PathBuf> = VecDeque::new();
- for path in self.paths.iter() {
- let metadata = path.symlink_metadata()?;
- if metadata.is_dir() {
- dirs.push_back(path.clone());
- } else {
- let metadata = path.symlink_metadata()?;
- total_bytes += metadata.len();
- total_files += 1;
- }
- }
-
- while let Some(dir) = dirs.pop_front() {
- for entry in fs::read_dir(dir)? {
- let path = entry?.path();
- if path.is_dir() {
- dirs.push_back(path);
- } else {
- let metadata = path.symlink_metadata()?;
- total_bytes += metadata.len();
- total_files += 1;
- }
- }
- }
- Ok((total_files, total_bytes))
- }
-
- fn paste_copy(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
- let (total_files, total_bytes) = self.query_number_of_items()?;
- let mut progress = IoWorkerProgress::new(self.kind(), 0, total_files, 0, total_bytes);
+ fn paste_copy(
+ &self,
+ tx: mpsc::Sender<FileOperationProgress>,
+ ) -> io::Result<FileOperationProgress> {
+ let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
+ let mut progress = FileOperationProgress::new(self.kind(), 0, total_files, 0, total_bytes);
for path in self.paths.iter() {
let _ = tx.send(progress.clone());
recursive_copy(
- self.options,
+ &tx,
path.as_path(),
self.dest.as_path(),
- tx.clone(),
+ self.options,
&mut progress,
)?;
}
Ok(progress)
}
- fn paste_cut(&self, tx: mpsc::Sender<IoWorkerProgress>) -> io::Result<IoWorkerProgress> {
- let (total_files, total_bytes) = self.query_number_of_items()?;
- let mut progress = IoWorkerProgress::new(self.kind(), 0, total_files, 0, total_bytes);
+ fn paste_cut(
+ &self,
+ tx: mpsc::Sender<FileOperationProgress>,
+ ) -> io::Result<FileOperationProgress> {
+ let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
+ let mut progress = FileOperationProgress::new(
+ self.kind(),
+ total_files,
+ total_files,
+ total_bytes,
+ total_bytes,
+ );
for path in self.paths.iter() {
let _ = tx.send(progress.clone());
recursive_cut(
- self.options,
+ &tx,
path.as_path(),
self.dest.as_path(),
- tx.clone(),
+ self.options,
&mut progress,
)?;
}
Ok(progress)
}
+
+ fn delete(
+ &self,
+ _tx: mpsc::Sender<FileOperationProgress>,
+ ) -> io::Result<FileOperationProgress> {
+ let (total_files, total_bytes) = query_number_of_items(&self.paths)?;
+ let progress = FileOperationProgress::new(self.kind(), 0, total_files, 0, total_bytes);
+ if self.options.permanently {
+ remove_files(&self.paths)?;
+ } else {
+ trash_files(&self.paths)?;
+ }
+ Ok(progress)
+ }
+}
+
+fn query_number_of_items(paths: &[path::PathBuf]) -> io::Result<(usize, u64)> {
+ let mut total_bytes = 0;
+ let mut total_files = 0;
+
+ let mut dirs: VecDeque<path::PathBuf> = VecDeque::new();
+ for path in paths.iter() {
+ let metadata = path.symlink_metadata()?;
+ if metadata.is_dir() {
+ dirs.push_back(path.clone());
+ } else {
+ let metadata = path.symlink_metadata()?;
+ total_bytes += metadata.len();
+ total_files += 1;
+ }
+ }
+
+ while let Some(dir) = dirs.pop_front() {
+ for entry in fs::read_dir(dir)? {
+ let path = entry?.path();
+ if path.is_dir() {
+ dirs.push_back(path);
+ } else {
+ let metadata = path.symlink_metadata()?;
+ total_bytes += metadata.len();
+ total_files += 1;
+ }
+ }
+ }
+ Ok((total_files, total_bytes))
}
pub fn recursive_copy(
- options: IoWorkerOptions,
+ tx: &mpsc::Sender<FileOperationProgress>,
src: &path::Path,
dest: &path::Path,
- tx: mpsc::Sender<IoWorkerProgress>,
- progress: &mut IoWorkerProgress,
+ options: FileOperationOptions,
+ progress: &mut FileOperationProgress,
) -> io::Result<()> {
let mut dest_buf = dest.to_path_buf();
if let Some(s) = src.file_name() {
@@ -210,10 +164,10 @@ pub fn recursive_copy(
let entry = entry?;
let entry_path = entry.path();
recursive_copy(
- options,
+ tx,
entry_path.as_path(),
dest_buf.as_path(),
- tx.clone(),
+ options,
progress,
)?;
let _ = tx.send(progress.clone());
@@ -235,11 +189,11 @@ pub fn recursive_copy(
}
pub fn recursive_cut(
- options: IoWorkerOptions,
+ tx: &mpsc::Sender<FileOperationProgress>,
src: &path::Path,
dest: &path::Path,
- tx: mpsc::Sender<IoWorkerProgress>,
- progress: &mut IoWorkerProgress,
+ options: FileOperationOptions,
+ progress: &mut FileOperationProgress,
) -> io::Result<()> {
let mut dest_buf = dest.to_path_buf();
if let Some(s) = src.file_name() {
@@ -264,10 +218,10 @@ pub fn recursive_cut(
for entry in fs::read_dir(src)? {
let entry_path = entry?.path();
recursive_cut(
- options,
+ tx,
entry_path.as_path(),
dest_buf.as_path(),
- tx.clone(),
+ options,
progress,
)?;
let _ = tx.send(progress.clone());
@@ -290,3 +244,43 @@ pub fn recursive_cut(
}
}
}
+
+fn trash_error_to_io_error(err: trash::Error) -> std::io::Error {
+ match err {
+ trash::Error::Unknown { description } => {
+ std::io::Error::new(std::io::ErrorKind::Other, description)
+ }
+ trash::Error::TargetedRoot => {
+ std::io::Error::new(std::io::ErrorKind::Other, "Targeted Root")
+ }
+ _ => std::io::Error::new(std::io::ErrorKind::Other, "Unknown Error"),
+ }
+}
+
+fn remove_files<P>(paths: &[P]) -> std::io::Result<()>
+where
+ P: AsRef<path::Path>,
+{
+ for path in paths {
+ if let Ok(metadata) = fs::symlink_metadata(path) {
+ if metadata.is_dir() {
+ fs::remove_dir_all(&path)?;
+ } else {
+ fs::remove_file(&path)?;
+ }
+ }
+ }
+ Ok(())
+}
+
+fn trash_files<P>(paths: &[P]) -> std::io::Result<()>
+where
+ P: AsRef<path::Path>,
+{
+ for path in paths {
+ if let Err(e) = trash::delete(path) {
+ return Err(trash_error_to_io_error(e));
+ }
+ }
+ Ok(())
+}
diff --git a/src/io/mod.rs b/src/io/mod.rs
index f577cc6..05f4cf8 100644
--- a/src/io/mod.rs
+++ b/src/io/mod.rs
@@ -1,5 +1,7 @@
+mod file_operation;
mod io_observer;
mod io_worker;
-pub use io_observer::IoWorkerObserver;
-pub use io_worker::{FileOp, IoWorkerOptions, IoWorkerProgress, IoWorkerThread};
+pub use file_operation::*;
+pub use io_observer::*;
+pub use io_worker::*;
diff --git a/src/key_command/command.rs b/src/key_command/command.rs
index 495cff5..4d4e0ba 100644
--- a/src/key_command/command.rs
+++ b/src/key_command/command.rs
@@ -2,7 +2,7 @@ use std::path;
use crate::commands::quit::QuitAction;
use crate::config::option::{LineNumberStyle, SelectOption, SortType};
-use crate::io::IoWorkerOptions;
+use crate::io::FileOperationOptions;
#[derive(Clone, Debug)]
#[allow(clippy::enum_variant_names)]
@@ -17,7 +17,7 @@ pub enum Command {
CutFiles,
CopyFiles,
- PasteFiles(IoWorkerOptions),
+ PasteFiles(FileOperationOptions),
CopyFileName,
CopyFileNameWithoutExtension,
CopyFilePath,
diff --git a/src/key_command/impl_comment.rs b/src/key_command/impl_comment.rs
index bd5e4e6..c441a6b 100644
--- a/src/key_command/impl_comment.rs
+++ b/src/key_command/impl_comment.rs
@@ -1,5 +1,5 @@
use crate::config::option::SortType;
-use crate::io::IoWorkerOptions;
+use crate::io::FileOperationOptions;
use super::{Command, CommandComment};
@@ -27,9 +27,10 @@ impl CommandComment for Command {
Self::CutFiles => "Cut selected files",
Self::CopyFiles => "Copy selected files",
- Self::PasteFiles(IoWorkerOptions {
+ Self::PasteFiles(FileOperationOptions {
overwrite,
skip_exist,
+ ..
}) => match (overwrite, skip_exist) {
(true, false) => "Paste, overwrite",
(false, true) => "Paste, skip existing files",
diff --git a/src/key_command/impl_from_str.rs b/src/key_command/impl_from_str.rs
index c09fe66..74c92e4 100644
--- a/src/key_command/impl_from_str.rs
+++ b/src/key_command/impl_from_str.rs
@@ -6,7 +6,7 @@ use shellexpand::tilde_with_context;
use crate::commands::quit::QuitAction;
use crate::config::option::{LineNumberStyle, SelectOption, SortType};
use crate::error::{JoshutoError, JoshutoErrorKind};
-use crate::io::IoWorkerOptions;
+use crate::io::FileOperationOptions;
use crate::HOME_DIR;
@@ -200,7 +200,7 @@ impl std::str::FromStr for Command {
},
}
} else if command == CMD_PASTE_FILES {
- let mut options = IoWorkerOptions::default();
+ let mut options = FileOperationOptions::default();
for arg in arg.split_whitespace() {
match arg {
"--overwrite=true" => options.overwrite = true,
diff --git a/src/ui/widgets/tui_worker.rs b/src/ui/widgets/tui_worker.rs
index f9e544d..06fcd7a 100644
--- a/src/ui/widgets/tui_worker.rs
+++ b/src/ui/widgets/tui_worker.rs
@@ -4,7 +4,7 @@ use tui::style::{Color, Modifier, Style};
use tui::widgets::Widget;
use crate::context::WorkerContext;
-use crate::io::FileOp;
+use crate::io::FileOperation;
use crate::util::format;
pub struct TuiWorker<'a> {
@@ -23,8 +23,9 @@ impl<'a> Widget for TuiWorker<'a> {
Some(io_obs) => {
if let Some(progress) = io_obs.progress.as_ref() {
let op_str = match progress.kind() {
- FileOp::Copy => "Copying",
- FileOp::Cut => "Moving",
+ FileOperation::Cut => "Moving",
+ FileOperation::Copy => "Copying",
+ FileOperation::Delete => "Deleting",
};
let processed_size = format::file_size_to_string(progress.bytes_processed());
@@ -61,8 +62,9 @@ impl<'a> Widget for TuiWorker<'a> {
let style = Style::default();
for (i, worker) in self.context.iter().enumerate() {
let op_str = match worker.kind() {
- FileOp::Copy => "Copy",
- FileOp::Cut => "Move",
+ FileOperation::Cut => "Move",
+ FileOperation::Copy => "Copy",
+ FileOperation::Delete => "Delete",
};
let msg = format!(
"{:02} {} {} items {:?}",